diff --git a/acinclude.m4 b/acinclude.m4 index 44ced2773..254f35c08 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -447,7 +447,7 @@ AC_ARG_WITH(boxtype, AC_ARG_WITH(boxmodel, AS_HELP_STRING([--with-boxmodel], [valid for generic: generic, raspi]) AS_HELP_STRING([], [valid for coolstream: hd1, hd2]) -AS_HELP_STRING([], [valid for armbox: hd51, hd60, bre2ze4k, vusolo4k, vuduo4k, vuzero4k]) +AS_HELP_STRING([], [valid for armbox: hd51, hd60, bre2ze4k, vusolo4k, vuduo4k, vuultimo4k, vuzero4k]) AS_HELP_STRING([], [valid for mipsbox: vuduo]), [case "${withval}" in generic|raspi) @@ -476,7 +476,7 @@ AS_HELP_STRING([], [valid for mipsbox: vuduo]), AC_MSG_ERROR([unknown model $withval for boxtype $BOXTYPE]) fi ;; - hd51|hd60|bre2ze4k|vusolo4k|vuduo4k|vuzero4k) + hd51|hd60|bre2ze4k|vusolo4k|vuduo4k|vuultimo4k|vuzero4k) if test "$BOXTYPE" = "armbox"; then BOXMODEL="$withval" else @@ -521,6 +521,7 @@ AM_CONDITIONAL(BOXMODEL_HD60, test "$BOXMODEL" = "hd60") AM_CONDITIONAL(BOXMODEL_BRE2ZE4K, test "$BOXMODEL" = "bre2ze4k") AM_CONDITIONAL(BOXMODEL_VUSOLO4K, test "$BOXMODEL" = "vusolo4k") AM_CONDITIONAL(BOXMODEL_VUDUO4K, test "$BOXMODEL" = "vuduo4k") +AM_CONDITIONAL(BOXMODEL_VUULTIMO4K, test "$BOXMODEL" = "vuultimo4k") AM_CONDITIONAL(BOXMODEL_VUZERO4K, test "$BOXMODEL" = "vuzero4k") # mipsbox @@ -567,6 +568,9 @@ elif test "$BOXMODEL" = "vusolo4k"; then elif test "$BOXMODEL" = "vuduo4k"; then AC_DEFINE(BOXMODEL_VUDUO4K, 1, [vuduo4k]) AC_DEFINE(ENABLE_CHANGE_OSD_RESOLUTION, 1, [enable change the osd resolution]) +elif test "$BOXMODEL" = "vuultimo4k"; then + AC_DEFINE(BOXMODEL_VUULTIMO4K, 1, [vuultimo4k]) + AC_DEFINE(ENABLE_CHANGE_OSD_RESOLUTION, 1, [enable change the osd resolution]) elif test "$BOXMODEL" = "vuzero4k"; then AC_DEFINE(BOXMODEL_VUZERO4K, 1, [vuzero4k]) AC_DEFINE(ENABLE_CHANGE_OSD_RESOLUTION, 1, [enable change the osd resolution]) diff --git a/data/y-web/Y_Blocks.txt b/data/y-web/Y_Blocks.txt index c12a7680e..f8abee1c2 100644 --- a/data/y-web/Y_Blocks.txt +++ b/data/y-web/Y_Blocks.txt @@ -540,9 +540,10 @@ start-block~remote {=if-equal:{=var-get:boxtype=}~VU+ DUO4K~ {=include-block:Y_Blocks.txt;rc_vu_solo4k=}~ {=if-equal:{=var-get:boxtype=}~VU+ DUO~ {=include-block:Y_Blocks.txt;rc_vu_solo4k=}~ {=if-equal:{=var-get:boxtype=}~VU+ ZERO4K~ {=include-block:Y_Blocks.txt;rc_vu_solo4k=}~ + {=if-equal:{=var-get:boxtype=}~VU+ ULTIMO4K~ {=include-block:Y_Blocks.txt;rc_vu_solo4k=}~ {=comment:fallback~=} {=include-block:Y_Blocks.txt;rc_cst_v1=} - =}=}=}=}=}=}=}=}=}=}=}=}=}=}=} + =}=}=}=}=}=}=}=}=}=}=}=}=}=}=}=} =}=} ~ {=if-equal:{=var-get:yfbtype=}~-2~ {=include-block:Y_Blocks.txt;rc_dbox_philips=}~ @@ -562,9 +563,10 @@ start-block~remote {=if-equal:{=var-get:yfbtype=}~13~ {=include-block:Y_Blocks.txt;rc_vu_solo4k=}~ {=if-equal:{=var-get:yfbtype=}~14~ {=include-block:Y_Blocks.txt;rc_vu_solo4k=}~ {=if-equal:{=var-get:yfbtype=}~15~ {=include-block:Y_Blocks.txt;rc_vu_solo4k=}~ + {=if-equal:{=var-get:yfbtype=}~16~ {=include-block:Y_Blocks.txt;rc_vu_solo4k=}~ {=comment:fallback~=} {=include-block:Y_Blocks.txt;rc_cst_v1=} - =}=}=}=}=}=}=}=}=}=}=}=}=}=}=}=}=} + =}=}=}=}=}=}=}=}=}=}=}=}=}=}=}=}=}=} =} end-block~remote @@ -1135,7 +1137,7 @@ start-block~rc_wwio_bre2ze4k end-block~rc_wwio_bre2ze4k -# ------ Remote VU+ Solo/Duo/Zero 4K +# ------ Remote VU+ Solo 4K/Duo 4K/Ultimo 4K/Zero 4K start-block~rc_vu_solo4k diff --git a/data/y-web/images/Makefile.am b/data/y-web/images/Makefile.am index 542909b56..acdf2e1ec 100644 --- a/data/y-web/images/Makefile.am +++ b/data/y-web/images/Makefile.am @@ -108,6 +108,10 @@ if BOXMODEL_VUDUO4K install_DATA += rc_vu_solo4k.png endif +if BOXMODEL_VUULTIMO4K +install_DATA += rc_vu_solo4k.png +endif + if BOXMODEL_VUZERO4K install_DATA += rc_vu_solo4k.png endif diff --git a/src/driver/nglcd.cpp b/src/driver/nglcd.cpp new file mode 100644 index 000000000..a5d498c8b --- /dev/null +++ b/src/driver/nglcd.cpp @@ -0,0 +1,952 @@ +/* + Neutrino graphlcd daemon thread + + (C) 2012-2014 by martii + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char * kDefaultConfigFile = "/etc/graphlcd.conf"; +static nGLCD *nglcd = NULL; + +extern CPictureViewer * g_PicViewer; + +nGLCD::nGLCD() { + lcd = NULL; + Channel = "Neutrino"; + Epg = std::string(g_info.hw_caps->boxvendor) + " " + std::string(g_info.hw_caps->boxname); + + sem_init(&sem, 0, 1); + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); + pthread_mutex_init(&mutex, &attr); + + channelLocked = false; + doRescan = false; + doStandby = false; + doStandbyTime = false; + doShowVolume = false; + doSuspend = false; + doExit = false; + doMirrorOSD = false; + fontsize_channel = 0; + fontsize_epg = 0; + fontsize_time = 0; + fontsize_time_standby = 0; + fonts_initialized = false; + doScrollChannel = false; + doScrollEpg = false; + percent_channel = 0; + percent_time = 0; + percent_time_standby = 0; + percent_epg = 0; + percent_bar = 0; + percent_space = 0; + percent_logo = 0; + Scale = 0; + bitmap = NULL; + blitFlag = true; + + nglcd = this; + + if (!g_settings.glcd_enable) + doSuspend = true; + + if (pthread_create (&thrGLCD, 0, nGLCD::Run, this) != 0 ) + fprintf(stderr, "ERROR: pthread_create(nGLCD::Init)\n"); + + Update(); +} + +void nGLCD::Lock(void) +{ + if (nglcd) + pthread_mutex_lock(&nglcd->mutex); +} + +void nGLCD::Unlock(void) +{ + if (nglcd) + pthread_mutex_unlock(&nglcd->mutex); +} + +nGLCD::~nGLCD() { + Suspend(); + nglcd = NULL; + if (lcd) { + lcd->DeInit(); + delete lcd; + } + sem_destroy(&sem); + pthread_mutex_destroy(&mutex); +} + +nGLCD *nGLCD::getInstance() +{ + if (!nglcd) + nglcd = new nGLCD; + return nglcd; +} + +void nGLCD::LcdAnalogClock(int posx,int posy,int dia) +{ + int tm_,th_,mx_,my_,hx_,hy_; + double pi_ = 3.1415926535897932384626433832795, mAngleInRad, mAngleSave, hAngleInRad; + + tm_ = tm->tm_min; + th_ = tm->tm_hour; + + mAngleInRad = ((6 * tm_) * (2*pi_ / 360)); + mAngleSave = mAngleInRad; + mAngleInRad -= pi_/2; + + mx_ = int((dia * 0.7 * cos(mAngleInRad))); + my_ = int((dia * 0.7 * sin(mAngleInRad))); + + hAngleInRad = ((30 * th_)* (2*pi_ / 360)); + hAngleInRad += mAngleSave / 12; + hAngleInRad -= pi_/2; + hx_ = int((dia * 0.4 * cos(hAngleInRad))); + hy_ = int((dia * 0.4 * sin(hAngleInRad))); + + std::string a_clock = ""; + + a_clock = ICONSDIR "/a_clock.png"; + if (access(a_clock.c_str(), F_OK) != 0) + a_clock = ICONSDIR "/a_clock.png"; + + int lcd_a_clock_width = 0, lcd_a_clock_height = 0; + g_PicViewer->getSize(a_clock.c_str(), &lcd_a_clock_width, &lcd_a_clock_height); + if (lcd_a_clock_width && lcd_a_clock_height) + { + showImage(a_clock, (uint32_t) lcd_a_clock_width, (uint32_t) lcd_a_clock_height, + 0, 0, (uint32_t) nglcd->bitmap->Width(), (uint32_t) nglcd->bitmap->Height(), false, false); + + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(true); + } + + // hour + bitmap->DrawLine(posx,posy-8,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-7,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-6,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-5,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-4,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-3,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-2,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-1,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx+1,posy,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+1,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+2,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+3,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+4,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+5,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+6,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+7,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+8,posx+hx_,posy+hy_, g_settings.glcd_color_fg); + + // minute + bitmap->DrawLine(posx,posy-6,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-5,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-4,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-3,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-2,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy-1,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx+1,posy,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+1,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+2,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+3,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+4,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+5,posx+mx_,posy+my_, g_settings.glcd_color_fg); + bitmap->DrawLine(posx,posy+6,posx+mx_,posy+my_, g_settings.glcd_color_fg); +} + +void nGLCD::Exec() { + if (!lcd) + return; + + bitmap->Clear(g_settings.glcd_color_bg); + + if (Channel == "Neutrino") { + if (g_settings.glcd_show_logo) { + int start_width = 0, start_height = 0; + g_PicViewer->getSize(DATADIR "/neutrino/icons/start.jpg", &start_width, &start_height); + if (start_width && start_height) { + showImage(DATADIR "/neutrino/icons/start.jpg", (uint32_t) start_width, (uint32_t) start_height, + 0, 0, (uint32_t) nglcd->bitmap->Width(), (uint32_t) nglcd->bitmap->Height(), false, true); + + GLCD::cFont font_tmp; + + int fw = font_epg.Width(Epg); + font_tmp.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_epg * (bitmap->Width() - 4) / fw); + fw = font_tmp.Width(Epg); + + bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - fw)/2), + 10 * bitmap->Height()/100, bitmap->Width() - 4, Epg, + &font_tmp, g_settings.glcd_color_fg, GLCD::cColor::Transparent); + + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(true); + } + } else { + nglcd->bitmap->Clear(g_settings.glcd_color_bg); + nglcd->lcd->Refresh(true); + } + return; + } + + if (doStandbyTime) { + if (percent_time_standby) { + + std::string Time; + if (g_settings.glcd_time_in_standby == 3) + LcdAnalogClock(bitmap->Width()/2, bitmap->Height()/2, 200); + else if (g_settings.glcd_time_in_standby == 2) + Time = strftime("%H:%M:%S", tm); + else + Time = strftime("%H:%M", tm); + + bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - font_time_standby.Width(Time))/2), + (bitmap->Height() - font_time_standby.Height(Time))/2, bitmap->Width() - 1, Time, + &font_time_standby, g_settings.glcd_color_fg, GLCD::cColor::Transparent); + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(false); + } + return; + } + + if (CNeutrinoApp::getInstance()->recordingstatus) { +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K + for (int bx = 0; bx < 6; bx++) { +#else + for (int bx = 0; bx < 3; bx++) { +#endif + bitmap->DrawRectangle(bx, bx, bitmap->Width() - bx + 1, bitmap->Height() - bx + 1, GLCD::cColor::Red, false); + } + } else + if (CNeutrinoApp::getInstance()->isMuted()) { +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K + for (int bx = 0; bx < 6; bx++) { +#else + for (int bx = 0; bx < 3; bx++) { +#endif + bitmap->DrawRectangle(bx, bx, bitmap->Width() - bx + 1, bitmap->Height() - bx + 1, GLCD::cColor::Blue, false); + } + } + + int off = percent_space; + + if (g_settings.glcd_show_logo && percent_logo && + showImage(channel_id, Channel, 0, off * bitmap->Height()/100, bitmap->Width() - 4, percent_logo * bitmap->Height()/100, true)) { + off += percent_logo; + off += percent_space; + doScrollChannel = false; + scrollChannelSkip = 0; + } else if (percent_channel) { + int logo_offset = 0; + if (g_settings.glcd_show_logo && percent_channel < percent_logo) { + int o = logo_offset = percent_logo - percent_channel; + o >>= 1; + off += o; + logo_offset -= o; + } + if (ChannelWidth) { + if (scrollChannelForward) { + if (ChannelWidth - scrollChannelSkip < bitmap->Width() - 4) + scrollChannelForward = false; + } else if (scrollChannelSkip <= 0) { + scrollChannelSkip = 0; + doScrollChannel = false; + } + + bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - ChannelWidth)/2) + scrollChannelOffset, + off * bitmap->Height()/100, bitmap->Width() - 4, Channel, + &font_channel, g_settings.glcd_color_fg, GLCD::cColor::Transparent, true, scrollChannelSkip); + + if (scrollChannelOffset > 0) + scrollChannelOffset -= g_settings.glcd_scroll_speed; + + if (scrollChannelOffset < 0) + scrollChannelOffset = 0; + + if (scrollChannelOffset == 0) { + if (scrollChannelForward) + scrollChannelSkip += g_settings.glcd_scroll_speed; + else + scrollChannelSkip -= g_settings.glcd_scroll_speed; + } + } + off += percent_channel; + off += logo_offset; + off += percent_space; + } else + off = 0; + + if (percent_epg) { + off += percent_space; + if (EpgWidth) { + if (scrollEpgForward) { + if (EpgWidth - scrollEpgSkip < bitmap->Width() - 4) + scrollEpgForward = false; + } else if (scrollEpgSkip <= 0) { + scrollEpgSkip = 0; + doScrollEpg = false; + } + + bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - EpgWidth)/2) + scrollEpgOffset, + off * bitmap->Height()/100, bitmap->Width() - 4, Epg, + &font_epg, g_settings.glcd_color_fg, GLCD::cColor::Transparent, true, scrollEpgSkip); + + if (scrollEpgOffset > 0) + scrollEpgOffset -= g_settings.glcd_scroll_speed; + + if (scrollEpgOffset < 0) + scrollEpgOffset = 0; + + if (scrollEpgOffset == 0) { + if (scrollEpgForward) + scrollEpgSkip += g_settings.glcd_scroll_speed; + else + scrollEpgSkip -= g_settings.glcd_scroll_speed; + } + } + off += percent_epg; + off += percent_space; + } + + if (percent_bar) { + off += percent_space; + int bar_top = off * bitmap->Height()/100; + off += percent_bar; + int bar_bottom = off * bitmap->Height()/100; + bitmap->DrawHLine(0, bar_top, bitmap->Width(), g_settings.glcd_color_fg); + bitmap->DrawHLine(0, bar_bottom, bitmap->Width(), g_settings.glcd_color_fg); + if (Scale) + bitmap->DrawRectangle(0, bar_top + 1, Scale * (bitmap->Width() - 1)/100, + bar_bottom - 1, g_settings.glcd_color_bar, true); + off += percent_space; + } + + if (percent_time) { + off += percent_space; + std::string Time = strftime("%H:%M", tm); + bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - font_time.Width(Time))/2), + off * bitmap->Height()/100, bitmap->Width() - 1, Time, + &font_time, g_settings.glcd_color_fg, GLCD::cColor::Transparent); + } + + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(false); +} + +void nGLCD::updateFonts() { + int percent; + percent = std::max(g_settings.glcd_percent_channel, g_settings.glcd_show_logo ? g_settings.glcd_percent_logo : 0) + + g_settings.glcd_percent_epg + g_settings.glcd_percent_bar + g_settings.glcd_percent_time; + + int div = 0; + + if (percent_channel || percent_logo) + div += 2; + if (percent_epg) + div += 2; + if (percent_bar) + div += 2; + if (percent_time) + div += 2; + + percent += div; + + if (percent < 100) + percent = 100; + + percent_logo = g_settings.glcd_show_logo ? g_settings.glcd_percent_logo * 100 / percent : 0; + percent_channel = g_settings.glcd_percent_channel * 100 / percent; + percent_epg = g_settings.glcd_percent_epg * 100 / percent; + percent_bar = g_settings.glcd_percent_bar * 100 / percent; + percent_time = g_settings.glcd_percent_time * 100 / percent; + percent_time_standby = std::min(g_settings.glcd_percent_time_standby, 100); + + percent_space = (100 - std::max(percent_logo, percent_channel) - percent_time - percent_epg - percent_bar) / div; + + // calculate height + int fontsize_channel_new = percent_channel * nglcd->lcd->Height() / 100; + int fontsize_epg_new = percent_epg * nglcd->lcd->Height() / 100; + int fontsize_time_new = percent_time * nglcd->lcd->Height() / 100; + int fontsize_time_standby_new = percent_time_standby * nglcd->lcd->Height() / 100; + + if (!fonts_initialized || (fontsize_channel_new != fontsize_channel)) { + fontsize_channel = fontsize_channel_new; + if (!font_channel.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_channel)) { + g_settings.glcd_font = FONTDIR "/neutrino.ttf"; + font_channel.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_channel); + } + } + if (!fonts_initialized || (fontsize_epg_new != fontsize_epg)) { + fontsize_epg = fontsize_epg_new; + if (!font_epg.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_epg)) { + g_settings.glcd_font = FONTDIR "/neutrino.ttf"; + font_epg.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_epg); + } + } + if (!fonts_initialized || (fontsize_time_new != fontsize_time)) { + fontsize_time = fontsize_time_new; + if (!font_time.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_time)) { + g_settings.glcd_font = FONTDIR "/neutrino.ttf"; + font_time.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_time); + } + } + if (!fonts_initialized || (fontsize_time_standby_new != fontsize_time_standby)) { + fontsize_time_standby = fontsize_time_standby_new; + if (!font_time_standby.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_time_standby)) { + g_settings.glcd_font = FONTDIR "/neutrino.ttf"; + font_time_standby.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_time_standby); + } + } + + fonts_initialized = true; +} + +bool nGLCD::getBoundingBox(uint32_t *buffer, int width, int height, int &bb_x, int &bb_y, int &bb_w, int &bb_h) +{ + if (!width || !height) { + bb_x = bb_y = bb_w = bb_h = 0; + return false; + } + + int y_min = height; + uint32_t *b = buffer; + for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++, b++) + if (*b) { + y_min = y; + goto out1; + } + out1: + + int y_max = y_min; + b = buffer + height * width - 1; + for (int y = height - 1; y_min < y; y--) + for (int x = 0; x < width; x++, b--) + if (*b) { + y_max = y; + goto out2; + } + out2: + + int x_min = width; + for (int x = 0; x < width; x++) { + b = buffer + x + y_min * width; + for (int y = y_min; y < y_max; y++, b += width) + if (*b) { + x_min = x; + goto out3; + } + } + out3: + + int x_max = x_min; + for (int x = width - 1; x_min < x; x--) { + b = buffer + x + y_min * width; + for (int y = y_min; y < y_max; y++, b += width) + if (*b) { + x_max = x; + goto out4; + } + } + out4: + + bb_x = x_min; + bb_y = y_min; + bb_w = 1 + x_max - x_min; + bb_h = 1 + y_max - y_min; + + if (bb_x < 0) + bb_x = 0; + if (bb_y < 0) + bb_y = 0; + + return true; +} + +void* nGLCD::Run(void *arg) +{ + nGLCD *me = (nGLCD *) arg; + me->Run(); + pthread_exit(NULL); +} + +void nGLCD::Run(void) +{ + set_threadname("nGLCD::Run"); + + if (GLCD::Config.Load(kDefaultConfigFile) == false) { + fprintf(stderr, "Error loading config file!\n"); + return; + } + if ((GLCD::Config.driverConfigs.size() < 1)) { + fprintf(stderr, "No driver config found!\n"); + return; + } + + struct timespec ts; + + CSectionsdClient::CurrentNextInfo info_CurrentNext; + channel_id = -1; + info_CurrentNext.current_zeit.startzeit = 0; + info_CurrentNext.current_zeit.dauer = 0; + info_CurrentNext.flags = 0; + + fonts_initialized = false; + bool broken = false; + + do { + if (broken) { +#ifdef GLCD_DEBUG + fprintf(stderr, "No graphlcd display found ... sleeping for 30 seconds\n"); +#endif + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 30; + sem_timedwait(&sem, &ts); + broken = false; + if (doExit) + break; + if (!g_settings.glcd_enable) + continue; + } else + while ((doSuspend || doStandby || !g_settings.glcd_enable) && !doExit) + sem_wait(&sem); + + if (doExit) + break; + + int warmUp = 10; + lcd = GLCD::CreateDriver(GLCD::Config.driverConfigs[0].id, &GLCD::Config.driverConfigs[0]); + if (!lcd) { +#ifdef GLCD_DEBUG + fprintf(stderr, "CreateDriver failed.\n"); +#endif + broken = true; + continue; + } +#ifdef GLCD_DEBUG + fprintf(stderr, "CreateDriver succeeded.\n"); +#endif + if (lcd->Init()) { + delete lcd; + lcd = NULL; +#ifdef GLCD_DEBUG + fprintf(stderr, "LCD init failed.\n"); +#endif + broken = true; + continue; + } +#ifdef GLCD_DEBUG + fprintf(stderr, "LCD init succeeded.\n"); +#endif + lcd->SetBrightness(0); + + if (!bitmap) + bitmap = new GLCD::cBitmap(lcd->Width(), lcd->Height(), g_settings.glcd_color_bg); + + UpdateBrightness(); + Update(); + + doMirrorOSD = false; + + while ((!doSuspend && !doStandby) && !doExit && g_settings.glcd_enable) { + if (doMirrorOSD && !doStandbyTime) { + if (blitFlag) { + blitFlag = false; + bitmap->Clear(GLCD::cColor::Black); + ts.tv_sec = 0; // don't wait + static CFrameBuffer* fb = CFrameBuffer::getInstance(); +#if !defined BOXMODEL_VUSOLO4K && !defined BOXMODEL_VUDUO4K && !defined BOXMODEL_VUULTIMO4K + static int fb_width = fb->getScreenWidth(true); +#endif + static int fb_height = fb->getScreenHeight(true); + static uint32_t *fbp = fb->getFrameBufferPointer(); + int lcd_width = bitmap->Width(); + int lcd_height = bitmap->Height(); +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K + unsigned int fb_stride = fb->getStride()/4; + if (!showImage(fbp, fb_stride, fb_height, 0, 0, lcd_width, lcd_height, false)) { +#else + if (!showImage(fbp, fb_width, fb_height, 0, 0, lcd_width, lcd_height, false)) { +#endif + usleep(500000); + } else { + lcd->SetScreen(bitmap->Data(), lcd_width, lcd_height); + lcd->Refresh(false); + } + } else + usleep(100000); + continue; + } + if (g_settings.glcd_mirror_video && !doStandbyTime) { + char ws[10]; + snprintf(ws, sizeof(ws), "%d", bitmap->Width()); + const char *bmpShot = "/tmp/nglcd-video.bmp"; + my_system(4, "/bin/grab", "-vr", ws, bmpShot); + int bw = 0, bh = 0; + g_PicViewer->getSize(bmpShot, &bw, &bh); + if (bw > 0 && bh > 0) { + int lcd_width = bitmap->Width(); + int lcd_height = bitmap->Height(); + if (!showImage(bmpShot, (uint32_t) bw, (uint32_t) bh, 0, 0, (uint32_t) lcd_width, lcd_height, false, true)) + usleep(1000000); + else { + lcd->SetScreen(bitmap->Data(), lcd_width, lcd_height); + lcd->Refresh(false); + } + } + else + usleep(1000000); + continue; + } + + clock_gettime(CLOCK_REALTIME, &ts); + tm = localtime(&ts.tv_sec); + updateFonts(); + Exec(); + clock_gettime(CLOCK_REALTIME, &ts); + tm = localtime(&ts.tv_sec); + if (warmUp > 0) { + ts.tv_sec += 1; + warmUp--; + } else { + ts.tv_sec += 60 - tm->tm_sec; + ts.tv_nsec = 0; + } + + if (!doScrollChannel && !doScrollEpg) + sem_timedwait(&sem, &ts); + + while(!sem_trywait(&sem)); + + if(doRescan || doSuspend || doStandby || doExit) + break; + + if (doShowVolume) { + Epg = ""; + if (Channel.compare(g_Locale->getText(LOCALE_GLCD_VOLUME))) { + Channel = g_Locale->getText(LOCALE_GLCD_VOLUME); + ChannelWidth = font_channel.Width(Channel); + doScrollChannel = ChannelWidth > bitmap->Width() - 4; + scrollChannelSkip = 0; + scrollChannelForward = true; + if (doScrollChannel) { + scrollChannelOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + ChannelWidth += scrollChannelOffset; + } else + scrollChannelOffset = 0; + } + EpgWidth = 0; + scrollEpgSkip = 0; + scrollEpgForward = true; + Scale = g_settings.current_volume; + channel_id = -1; + } else if (channelLocked) { + Lock(); + if (Epg.compare(stagingEpg)) { + Epg = stagingEpg; + EpgWidth = font_epg.Width(Epg); + doScrollEpg = EpgWidth > bitmap->Width() - 4; + scrollEpgSkip = 0; + scrollEpgForward = true; + if (doScrollEpg) { + scrollEpgOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + EpgWidth += scrollEpgOffset; + } else + scrollChannelOffset = 0; + } + if (Channel.compare(stagingChannel)) { + Channel = stagingChannel; + ChannelWidth = font_channel.Width(Channel); + doScrollChannel = ChannelWidth > bitmap->Width() - 4; + scrollChannelSkip = 0; + scrollChannelForward = true; + if (doScrollChannel) { + scrollChannelOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + ChannelWidth += scrollChannelOffset; + } else + scrollChannelOffset = 0; + } + channel_id = -1; + Unlock(); + } else { + CChannelList *channelList = CNeutrinoApp::getInstance ()->channelList; + if (!channelList) + continue; + t_channel_id new_channel_id = channelList->getActiveChannel_ChannelID(); + if (!new_channel_id) + continue; + + if ((new_channel_id != channel_id)) { + Channel = channelList->getActiveChannelName (); + ChannelWidth = font_channel.Width(Channel); + Epg = ""; + EpgWidth = 0; + Scale = 0; + doScrollEpg = false; + doScrollChannel = ChannelWidth > bitmap->Width() - 4; + scrollChannelForward = true; + scrollChannelSkip = 0; + if (doScrollChannel) { + scrollChannelOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + ChannelWidth += scrollChannelOffset; + } else + scrollChannelOffset = 0; + warmUp = 10; + info_CurrentNext.current_name = ""; + info_CurrentNext.current_zeit.dauer = 0; + } + + CEitManager::getInstance()->getCurrentNextServiceKey(channel_id & 0xFFFFFFFFFFFFULL, info_CurrentNext); + channel_id = new_channel_id; + + if (info_CurrentNext.current_name.compare(Epg)) { + Epg = info_CurrentNext.current_name; + EpgWidth = font_epg.Width(Epg); + doScrollEpg = EpgWidth > bitmap->Width() - 4; + scrollEpgForward = true; + scrollEpgSkip = 0; + if (doScrollEpg) { + scrollEpgOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + EpgWidth += scrollEpgOffset; + } else + scrollEpgOffset = 0; + } + if (info_CurrentNext.current_zeit.dauer > 0) + Scale = (ts.tv_sec - info_CurrentNext.current_zeit.startzeit) * 100 / info_CurrentNext.current_zeit.dauer; + if (Scale > 100) + Scale = 100; + else if (Scale < 0) + Scale = 0; + } + } + + if(!g_settings.glcd_enable || doSuspend || doStandby || doExit) { + // for restart, don't blacken screen + bitmap->Clear(GLCD::cColor::Black); + lcd->SetBrightness(0); + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(false); + } + if (doRescan) { + doRescan = false; + Update(); + } + lcd->DeInit(); + delete lcd; + lcd = NULL; + } while(!doExit); +} + +void nGLCD::Update() { + if (nglcd) + sem_post(&nglcd->sem); +} + +void nGLCD::StandbyMode(bool b) { + if (nglcd) { + if (g_settings.glcd_time_in_standby) { + nglcd->doStandbyTime = b; + nglcd->doStandby = false; + } else { + nglcd->doStandbyTime = false; + nglcd->doStandby = b; + } + if (b) { + nglcd->doScrollChannel = false; + nglcd->doScrollEpg = false; + } else { + nglcd->doScrollChannel = true; + nglcd->doScrollEpg = true; + } + nglcd->doMirrorOSD = false; + nglcd->UpdateBrightness(); + nglcd->Update(); + } +} + +void nGLCD::ShowVolume(bool b) { + if (nglcd) { + nglcd->doShowVolume = b; + nglcd->Update(); + } +} + +void nGLCD::MirrorOSD(bool b) { + if (nglcd) { + nglcd->doMirrorOSD = b; + nglcd->Update(); + } +} + +void nGLCD::Exit() { + if (nglcd) { + nglcd->doMirrorOSD = false; + nglcd->doSuspend = false; + nglcd->doExit = true; + nglcd->Update(); + void *res; + pthread_join(nglcd->thrGLCD, &res); + delete nglcd; + nglcd = NULL; + } +} + +void nGLCD::Rescan() { + doRescan = true; + Update(); +} + +void nGLCD::Suspend() { + if (nglcd) { + nglcd->doSuspend = true; + nglcd->Update(); + } +} + +void nGLCD::Resume() { + if (nglcd) { + nglcd->doSuspend = false; + nglcd->channelLocked = false; + nglcd->Update(); + } +} + +void nGLCD::lockChannel(std::string c, std::string e, int s) +{ + if(nglcd) { + nglcd->Lock(); + nglcd->channelLocked = true; + nglcd->stagingChannel = c; + nglcd->stagingEpg = e; + nglcd->Scale = s; + nglcd->Unlock(); + nglcd->Update(); + } +} + +void nGLCD::unlockChannel(void) +{ + if(nglcd) { + nglcd->channelLocked = false; + nglcd->Update(); + } +} + +bool nGLCD::showImage(fb_pixel_t *s, uint32_t sw, uint32_t sh, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize) +{ + int bb_x, bb_y, bb_w, bb_h; + + if (nglcd->getBoundingBox(s, sw, sh, bb_x, bb_y, bb_w, bb_h) && bb_w && bb_h) { + if (!maximize) { + if (bb_h * dw > bb_w * dh) { + uint32_t dw_new = dh * bb_w / bb_h; + dx += (dw - dw_new) >> 1; + dw = dw_new; + } else { + uint32_t dh_new = dw * bb_h / bb_w; + dy += (dh - dh_new) >> 1; + dh = dh_new; + } + } + for (u_int y = 0; y < dh; y++) { + for (u_int x = 0; x < dw; x++) { + uint32_t pix = *(s + (y * bb_h / dh + bb_y) * sw + x * bb_w / dw + bb_x); + if (!transp || pix) + nglcd->bitmap->DrawPixel(x + dx, y + dy, pix); + } + } + return true; + } + return false; +} + +bool nGLCD::showImage(const std::string & filename, uint32_t sw, uint32_t sh, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize) +{ + bool res = false; + if (!dw || !dh) + return res; + fb_pixel_t *s = g_PicViewer->getImage(filename, sw, sh); + if (s && sw && sh) + res = showImage(s, sw, sh, dx, dy, dw, dh, transp, maximize); + if (s) + free(s); + return res; +} + +bool nGLCD::showImage(uint64_t cid, std::string cname, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize) +{ + std::string logo; + int sw, sh; + + if (g_PicViewer->GetLogoName(cid, cname, logo, &sw, &sh)) { + return showImage(logo, (uint32_t) sw, (uint32_t) sh, dx, dy, dw, dh, transp, maximize); + } + return false; +} + +void nGLCD::UpdateBrightness() +{ + if (nglcd && nglcd->lcd) + nglcd->lcd->SetBrightness((unsigned int) (nglcd->doStandbyTime ? g_settings.glcd_brightness_standby : g_settings.glcd_brightness)); +} + +void nGLCD::SetBrightness(unsigned int b) +{ + if (nglcd) + nglcd->SetBrightness(b); +} + +void nGLCD::Blit() +{ + if (nglcd) + nglcd->blitFlag = true; +} + +int nGLCD::handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t /* data */) +{ + if (msg == NeutrinoMessages::EVT_CURRENTNEXT_EPG) { + Update(); + return messages_return::handled; + } + + return messages_return::unhandled; +} + diff --git a/src/driver/rcinput.h b/src/driver/rcinput.h index 1dde795bd..8105ba513 100644 --- a/src/driver/rcinput.h +++ b/src/driver/rcinput.h @@ -223,7 +223,7 @@ class CRCInput RC_tv = KEY_TV, RC_radio = KEY_RADIO, RC_text = KEY_TEXT, -#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUZERO4K || BOXMODEL_VUDUO +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUZERO4K || BOXMODEL_VUDUO RC_info = 0xFFFE, RC_epg = KEY_INFO, #else diff --git a/src/gui/scan_setup.h b/src/gui/scan_setup.h index 86403884a..d07a68980 100644 --- a/src/gui/scan_setup.h +++ b/src/gui/scan_setup.h @@ -66,10 +66,14 @@ class CScanSetup : public CMenuTarget, public CChangeObserver CGenericMenuActivate msettings; CMenuOptionChooser * linkfe; +#if BOXMODEL_VUULTIMO4K + std::string modestr[24]; +#else #if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K std::string modestr[16]; #else std::string modestr[4]; +#endif #endif /* variables for selected frontend */ diff --git a/src/neutrino.cpp b/src/neutrino.cpp index d1505eed5..574ebdc1a 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -5289,7 +5289,7 @@ void CNeutrinoApp::loadKeys(const char * fname) #if BOXMODEL_HD51 || BOXMODEL_HD60 || BOXMODEL_BRE2ZE4K g_settings.mpkey_play = tconfig->getInt32( "mpkey.play", CRCInput::RC_playpause ); g_settings.mpkey_pause = tconfig->getInt32( "mpkey.pause", CRCInput::RC_playpause ); -#elif BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUZERO4K || BOXMODEL_VUDUO +#elif BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUZERO4K || BOXMODEL_VUDUO g_settings.mpkey_play = tconfig->getInt32( "mpkey.play", CRCInput::RC_play ); g_settings.mpkey_pause = tconfig->getInt32( "mpkey.pause", CRCInput::RC_playpause ); #else diff --git a/src/zapit/include/zapit/femanager.h b/src/zapit/include/zapit/femanager.h index b037f006e..e79c7e252 100644 --- a/src/zapit/include/zapit/femanager.h +++ b/src/zapit/include/zapit/femanager.h @@ -31,6 +31,10 @@ #include +#if BOXMODEL_VUULTIMO4K +#define MAX_FE 24 +#define MAX_ADAPTERS 4 +#else #if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K #define MAX_FE 16 #define MAX_ADAPTERS 4 @@ -38,6 +42,7 @@ #define MAX_FE 4 #define MAX_ADAPTERS 4 #endif +#endif //#define DYNAMIC_DEMUX //#define MAKE_FE_KEY(adapter, number) ((adapter << 8) | (number & 0xFF)) diff --git a/src/zapit/src/frontend.cpp b/src/zapit/src/frontend.cpp index bfb41b20e..6ac17166f 100644 --- a/src/zapit/src/frontend.cpp +++ b/src/zapit/src/frontend.cpp @@ -1233,7 +1233,7 @@ bool CFrontend::buildProperties(const FrontendParameters *feparams, struct dtv_p case FEC_2_3: fec = FEC_2_3; if (feparams->delsys == DVB_S2 && feparams->modulation == PSK_8) -#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUZERO4K pilot = PILOT_AUTO; #else pilot = PILOT_ON; @@ -1242,7 +1242,11 @@ bool CFrontend::buildProperties(const FrontendParameters *feparams, struct dtv_p case FEC_3_4: fec = FEC_3_4; if (feparams->delsys == DVB_S2 && feparams->modulation == PSK_8) +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUZERO4K + pilot = PILOT_AUTO; +#else pilot = PILOT_ON; +#endif break; case FEC_4_5: fec = FEC_4_5; @@ -1250,7 +1254,11 @@ bool CFrontend::buildProperties(const FrontendParameters *feparams, struct dtv_p case FEC_5_6: fec = FEC_5_6; if (feparams->delsys == DVB_S2 && feparams->modulation == PSK_8) +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUZERO4K + pilot = PILOT_AUTO; +#else pilot = PILOT_ON; +#endif break; case FEC_6_7: fec = FEC_6_7; @@ -1264,7 +1272,11 @@ bool CFrontend::buildProperties(const FrontendParameters *feparams, struct dtv_p case FEC_3_5: fec = FEC_3_5; if (feparams->delsys == DVB_S2 && feparams->modulation == PSK_8) +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUZERO4K + pilot = PILOT_AUTO; +#else pilot = PILOT_ON; +#endif break; case FEC_9_10: fec = FEC_9_10;