diff --git a/configure.ac b/configure.ac index eb39ec37c..0fb21937f 100644 --- a/configure.ac +++ b/configure.ac @@ -90,6 +90,7 @@ lib/libtriple/Makefile lib/libtuxtxt/Makefile lib/libdvbsub/Makefile lib/libupnpclient/Makefile +src/lcddisplay/Makefile src/nhttpd/Makefile src/nhttpd/web/Makefile src/nhttpd/web/images/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 81ce83fe6..58befd0ec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,6 +20,7 @@ if BOXTYPE_COOL INCLUDES += -I$(top_srcdir)/lib/libcoolstream endif if BOXTYPE_TRIPLE +SUBDIRS += lcddisplay INCLUDES += -I$(top_srcdir)/lib/libtriple endif @@ -82,6 +83,7 @@ endif if BOXTYPE_TRIPLE neutrino_LDADD += \ $(top_builddir)/lib/libtriple/libtriple.a \ - @DIRECTFB_LIBS@ + @DIRECTFB_LIBS@ \ + $(top_builddir)/src/lcddisplay/liblcddisplay.a endif diff --git a/src/driver/Makefile.am b/src/driver/Makefile.am index f133cf648..8cb1f244a 100644 --- a/src/driver/Makefile.am +++ b/src/driver/Makefile.am @@ -37,10 +37,16 @@ libneutrino_driver_a_SOURCES = \ if BOXTYPE_COOL libneutrino_driver_a_SOURCES += \ vfd.cpp + INCLUDES += \ -I$(top_srcdir)/lib/libcoolstream endif if BOXTYPE_TRIPLE +libneutrino_driver_a_SOURCES += \ + newclock.cpp \ + lcdfontrenderer.cpp \ + lcdd.cpp + INCLUDES += \ -I$(top_srcdir)/lib/libtriple endif diff --git a/src/driver/audiodec/vis.cpp b/src/driver/audiodec/vis.cpp index 3f4f9b39c..f2311a848 100644 --- a/src/driver/audiodec/vis.cpp +++ b/src/driver/audiodec/vis.cpp @@ -19,8 +19,12 @@ #include #include +#if HAVE_COOL_HARDWARE #include - +#endif +#if HAVE_TRIPLEDRAGON +#include +#endif #include "int_fft.c" typedef signed short gint16; typedef int gint; diff --git a/src/driver/lcdd.cpp b/src/driver/lcdd.cpp new file mode 100644 index 000000000..52628ac1a --- /dev/null +++ b/src/driver/lcdd.cpp @@ -0,0 +1,1391 @@ +/* + $Id$ + + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Copyright (C) 2008 Novell, Inc. Author: Stefan Seyfried + (C) 2009 Stefan Seyfried + + 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 + +#if defined HAVE_DBOX_HARDWARE || defined HAVE_DREAMBOX_HARDWARE || defined HAVE_IPBOX_HARDWARE +#include +#endif +#include +#include +#include + +#include +extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ + +CLCD::CLCD() + : configfile('\t') +{ +#ifdef LCD_UPDATE + m_fileList = NULL; + m_fileListPos = 0; + m_fileListHeader = ""; + m_infoBoxText = ""; + m_infoBoxAutoNewline = 0; + m_progressShowEscape = 0; + m_progressHeaderGlobal = ""; + m_progressHeaderLocal = ""; + m_progressGlobal = 0; + m_progressLocal = 0; +#endif // LCD_UPDATE + muted = false; + percentOver = 0; + volume = 0; + timeout_cnt = 0; + has_lcd = true; +} + +CLCD* CLCD::getInstance() +{ + static CLCD* lcdd = NULL; + if(lcdd == NULL) + { + lcdd = new CLCD(); + } + return lcdd; +} + +void CLCD::count_down() { + if (timeout_cnt > 0) { + timeout_cnt--; + if (timeout_cnt == 0) { + setlcdparameter(); + } + } +} + +void CLCD::wake_up() { + if (atoi(g_settings.lcd_setting_dim_time) > 0) { + timeout_cnt = atoi(g_settings.lcd_setting_dim_time); + setlcdparameter(); + } +} + +#ifndef BOXMODEL_DM500 +void* CLCD::TimeThread(void *) +{ + while(1) + { + sleep(1); + struct stat buf; + if (stat("/tmp/lcd.locked", &buf) == -1) { + CLCD::getInstance()->showTime(); + CLCD::getInstance()->count_down(); + } else + CLCD::getInstance()->wake_up(); + } + return NULL; +} +#else +// there is no LCD on DM500, so let's use the timethread for blinking the LED during record +void* CLCD::TimeThread(void *) +{ + int led = 0; + int old_led = 0; + int led_fd = open("/dev/dbox/fp0", O_RDWR); + + if (led_fd < 0) + { + perror("CLCD::TimeThread: /dev/dbox/fp0"); + return NULL; + } + // printf("CLCD:TimeThread dm500 led_fd: %d\n",led_fd); + while(1) + { + sleep(1); + if (CNeutrinoApp::getInstance()->recordingstatus) + led = !led; + else + led = (CLCD::getInstance()->mode == MODE_STANDBY); + + if (led != old_led) { + //printf("CLCD:TimeThread ioctl(led_fd,11, &%d)\n",led); + ioctl(led_fd, 11, &led); + old_led = led; + } + } + return NULL; +} +#endif + +void CLCD::init(const char * fontfile, const char * fontname, + const char * fontfile2, const char * fontname2, + const char * fontfile3, const char * fontname3) +{ + InitNewClock(); + + if (!lcdInit(fontfile, fontname, fontfile2, fontname2, fontfile3, fontname3 )) + { + printf("[lcdd] LCD-Init failed!\n"); + has_lcd = false; +#ifndef BOXMODEL_DM500 + // on the dm500, we need the timethread for the front LEDs + return; +#endif + } + + if (pthread_create (&thrTime, NULL, TimeThread, NULL) != 0 ) + { + perror("[lcdd]: pthread_create(TimeThread)"); + return ; + } +} + +enum backgrounds { + BACKGROUND_SETUP = 0, + BACKGROUND_POWER = 1, + BACKGROUND_LCD2 = 2, + BACKGROUND_LCD3 = 3, + BACKGROUND_LCD = 4 +// BACKGROUND_LCD4 = 5 +}; +const char * const background_name[LCD_NUMBER_OF_BACKGROUNDS] = { + "setup", + "power", + "lcd2", + "lcd3", + "lcd" +}; +#define NUMBER_OF_PATHS 2 +const char * const background_path[NUMBER_OF_PATHS] = { + LCDDIR_VAR , + DATADIR "/lcdd/icons/" +}; + +bool CLCD::lcdInit(const char * fontfile, const char * fontname, + const char * fontfile2, const char * fontname2, + const char * fontfile3, const char * fontname3) +{ + fontRenderer = new LcdFontRenderClass(&display); + const char * style_name = fontRenderer->AddFont(fontfile); + const char * style_name2; + const char * style_name3; + + if (fontfile2 != NULL) + style_name2 = fontRenderer->AddFont(fontfile2); + else + { + style_name2 = style_name; + fontname2 = fontname; + } + + if (fontfile3 != NULL) + style_name3 = fontRenderer->AddFont(fontfile3); + else + { + style_name3 = style_name; + fontname3 = fontname; + } + fontRenderer->InitFontCache(); + + fonts.menu = fontRenderer->getFont(fontname, style_name , 12); + fonts.time = fontRenderer->getFont(fontname2, style_name2, 14); + fonts.channelname = fontRenderer->getFont(fontname3, style_name3, 15); + fonts.menutitle = fonts.channelname; + + setAutoDimm(g_settings.lcd_setting[SNeutrinoSettings::LCD_AUTODIMM]); + + if (!display.isAvailable()) + { + printf("[lcdd] exit...(no lcd-support)\n"); + return false; + } + + for (int i = 0; i < LCD_NUMBER_OF_BACKGROUNDS; i++) + { + for (int j = 0; j < NUMBER_OF_PATHS; j++) + { + std::string file = background_path[j]; + file += background_name[i]; + file += ".png"; + if (display.load_png(file.c_str())) + goto found; + } + printf("[neutrino/lcd] no valid %s background.\n", background_name[i]); + return false; + found: + display.dump_screen(&(background[i])); + } + + setMode(MODE_TVRADIO); + + return true; +} + +void CLCD::displayUpdate() +{ + struct stat buf; + if (stat("/tmp/lcd.locked", &buf) == -1) + display.update(); +} + +#ifndef HAVE_TRIPLEDRAGON +void CLCD::setlcdparameter(int dimm, const int contrast, const int power, const int inverse, const int bias) +{ +#if defined HAVE_DBOX_HARDWARE || defined HAVE_DREAMBOX_HARDWARE || defined HAVE_IPBOX_HARDWARE + if (!display.isAvailable()) + return; + int fd; + if (power == 0) + dimm = 0; + + if ((fd = open("/dev/dbox/fp0", O_RDWR)) == -1) + { + perror("[lcdd] open '/dev/dbox/fp0' failed"); + } + else + { + if (ioctl(fd, FP_IOCTL_LCD_DIMM, &dimm) < 0) + { + perror("[lcdd] set dimm failed!"); + } + + close(fd); + } + + if ((fd = open("/dev/dbox/lcd0", O_RDWR)) == -1) + { + perror("[lcdd] open '/dev/dbox/lcd0' failed"); + } + else + { + if (ioctl(fd, LCD_IOCTL_SRV, &contrast) < 0) + { + perror("[lcdd] set contrast failed!"); + } + + if (ioctl(fd, LCD_IOCTL_ON, &power) < 0) + { + perror("[lcdd] set power failed!"); + } + + if (ioctl(fd, LCD_IOCTL_REVERSE, &inverse) < 0) + { + perror("[lcdd] set invert failed!"); + } + + if (g_info.box_Type == CControld::TUXBOX_MAKER_PHILIPS) + { + if (ioctl(fd, LCD_IOCTL_BIAS, &bias) < 0) + { + perror("[lcdd] set bias failed!"); + } + } + close(fd); + } +#endif +} +#else +void CLCD::setlcdparameter(int dimm, const int contrast, const int power, const int inverse, const int bias) +{ + int fd = open("/dev/" DEVICE_NAME_LCD, O_RDWR); + if (fd < 0) + { + perror("CLCD::setlcdparameter open " DEVICE_NAME_LCD); + return; + } + if (ioctl(fd, IOC_LCD_INVERS, inverse & 1) < 0) + perror("CLCD::setlcdparameter ioctl IOC_LCD_INVERS"); + if (ioctl(fd, IOC_LCD_POTI, contrast) < 0) + perror("CLCD::setlcdparameter ioctl IOC_LCD_POTI"); + + close(fd); +} +#endif + +void CLCD::setlcdparameter(void) +{ + last_toggle_state_power = g_settings.lcd_setting[SNeutrinoSettings::LCD_POWER]; + int dim_time = atoi(g_settings.lcd_setting_dim_time); + int dim_brightness = atoi(g_settings.lcd_setting_dim_brightness); + bool timeouted = (dim_time > 0) && (timeout_cnt == 0); + int brightness, power = 0; + + if (timeouted) + brightness = dim_brightness; + else + brightness = g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS]; + + if (last_toggle_state_power && (!timeouted || dim_brightness > 0)) + power = 1; + + if (mode == MODE_STANDBY) + brightness = g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS]; + + setlcdparameter(brightness, + g_settings.lcd_setting[SNeutrinoSettings::LCD_CONTRAST], + power, + g_settings.lcd_setting[SNeutrinoSettings::LCD_INVERSE], + 0 /*g_settings.lcd_setting[SNeutrinoSettings::LCD_BIAS]*/); +} + +static std::string removeLeadingSpaces(const std::string & text) +{ + int pos = text.find_first_not_of(" "); + + if (pos != -1) + return text.substr(pos); + + return text; +} + +static std::string splitString(const std::string & text, const int maxwidth, LcdFont *font, bool dumb, bool utf8) +{ + int pos; + std::string tmp = removeLeadingSpaces(text); + + if (font->getRenderWidth(tmp.c_str(), utf8) > maxwidth) + { + do + { + if (dumb) + tmp = tmp.substr(0, tmp.length()-1); + else + { + pos = tmp.find_last_of("[ .-]+"); // TODO characters might be UTF-encoded! + if (pos != -1) + tmp = tmp.substr(0, pos); + else // does not fit -> fall back to dumb split + tmp = tmp.substr(0, tmp.length()-1); + } + } while (font->getRenderWidth(tmp.c_str(), utf8) > maxwidth); + } + + return tmp; +} + +/* display "big" and "small" text. + TODO: right now, "big" is hardcoded as utf-8, small is not (for EPG) + */ +void CLCD::showTextScreen(const std::string & big, const std::string & small, const int showmode, const bool perform_wakeup, const bool centered) +{ + /* the "showmode" variable is a bit map: + 0x01 show "big" string + 0x02 show "small" string + 0x04 show separator line if big and small are present / shown + 0x08 show only one line of "big" string + */ + + /* draw_fill_rect is braindead: it actually fills _inside_ the described rectangle, + so that you have to give it one pixel additionally in every direction ;-( + this is where the "-1 to 120" intead of "0 to 119" comes from */ + display.draw_fill_rect(-1, 10, LCD_COLS, 51, CLCDDisplay::PIXEL_OFF); + + bool big_utf8 = false; + bool small_utf8 = false; + std::string cname[2]; + std::string event[4]; + int namelines = 0, eventlines = 0, maxnamelines = 2; + if (showmode & 8) + maxnamelines = 1; + + if ((showmode & 1) && !big.empty()) + { + bool dumb = false; + big_utf8 = isUTF8(big); + while (true) + { + namelines = 0; + std::string title = big; + do { // first try "intelligent" splitting + cname[namelines] = splitString(title, LCD_COLS, fonts.channelname, dumb, big_utf8); + title = removeLeadingSpaces(title.substr(cname[namelines].length())); + namelines++; + } while (title.length() > 0 && namelines < maxnamelines); + if (title.length() == 0) + break; + dumb = !dumb; // retry with dumb splitting; + if (!dumb) // second retry -> get out; + break; + } + } + + // one nameline => 2 eventlines, 2 namelines => 1 eventline + int maxeventlines = 4 - (namelines * 3 + 1) / 2; + + if ((showmode & 2) && !small.empty()) + { + bool dumb = false; + small_utf8 = isUTF8(small); + while (true) + { + eventlines = 0; + std::string title = small; + do { // first try "intelligent" splitting + event[eventlines] = splitString(title, LCD_COLS, fonts.menu, dumb, small_utf8); + title = removeLeadingSpaces(title.substr(event[eventlines].length())); + /* DrDish TV appends a 0x0a to the EPG title. We could strip it in sectionsd... + ...instead, strip all control characters at the end of the text for now */ + if (event[eventlines].length() > 0 && event[eventlines].at(event[eventlines].length() - 1) < ' ') + event[eventlines].erase(event[eventlines].length() - 1); + eventlines++; + } while (title.length() >0 && eventlines < maxeventlines); + if (title.length() == 0) + break; + dumb = !dumb; // retry with dumb splitting; + if (!dumb) // second retry -> get out; + break; + } + } + + /* this values were determined empirically */ + int y = 8 + (41 - namelines*14 - eventlines*10)/2; + int x = 1; + for (int i = 0; i < namelines; i++) { + y += 14; + if (centered) + { + int w = fonts.channelname->getRenderWidth(cname[i].c_str(), big_utf8); + x = (LCD_COLS - w) / 2; + } + fonts.channelname->RenderString(x, y, LCD_COLS + 10, cname[i].c_str(), CLCDDisplay::PIXEL_ON, 0, big_utf8); + } + y++; + if (eventlines > 0 && namelines > 0 && showmode & 4) + { + y++; + display.draw_line(0, y, LCD_COLS - 1, y, CLCDDisplay::PIXEL_ON); + } + if (eventlines > 0) + { + for (int i = 0; i < eventlines; i++) { + y += 10; + if (centered) + { + int w = fonts.menu->getRenderWidth(event[i].c_str(), small_utf8); + x = (LCD_COLS - w) / 2; + } + fonts.menu->RenderString(x, y, LCD_COLS + 10, event[i].c_str(), CLCDDisplay::PIXEL_ON, 0, small_utf8); + } + } + + if (perform_wakeup) + wake_up(); + + displayUpdate(); +} + +void CLCD::showServicename(const std::string name, const bool perform_wakeup) +{ + /* + 1 = show servicename + 2 = show epg title + 4 = draw separator line between name and EPG + */ + int showmode = g_settings.lcd_setting[SNeutrinoSettings::LCD_EPGMODE]; + + //printf("CLCD::showServicename '%s' epg: '%s'\n", name.c_str(), epg_title.c_str()); + + if (!name.empty()) + servicename = name; + + if (mode != MODE_TVRADIO) + return; + + showTextScreen(servicename, epg_title, showmode, perform_wakeup, true); + return; +} + +void CLCD::setEPGTitle(const std::string title) +{ + if (title == epg_title) + { + //fprintf(stderr,"CLCD::setEPGTitle: not changed\n"); + return; + } + epg_title = title; + showServicename("", false); +} + +void CLCD::setMovieInfo(const AUDIOMODES playmode, const std::string big, const std::string small, const bool centered) +{ + int showmode = g_settings.lcd_setting[SNeutrinoSettings::LCD_EPGMODE]; + showmode |= 3; // take only the separator line from the config + + movie_playmode = playmode; + movie_big = big; + movie_small = small; + movie_centered = centered; + + if (mode != MODE_MOVIE) + return; + + showAudioPlayMode(movie_playmode); + showTextScreen(movie_big, movie_small, showmode, true, movie_centered); +} + +void CLCD::setMovieAudio(const bool is_ac3) +{ + movie_is_ac3 = is_ac3; + + if (mode != MODE_MOVIE) + return; + + showPercentOver(percentOver, true, MODE_MOVIE); +} + +void CLCD::showTime() +{ + if (showclock) + { + char timestr[21]; + struct timeval tm; + struct tm * t; + + gettimeofday(&tm, NULL); + t = localtime(&tm.tv_sec); + + if (mode == MODE_STANDBY) + { + display.draw_fill_rect(-1, -1, LCD_COLS, 64, CLCDDisplay::PIXEL_OFF); // clear lcd + + ShowNewClock(&display, t->tm_hour, t->tm_min, t->tm_sec, t->tm_wday, t->tm_mday, t->tm_mon); + } + else + { + if (CNeutrinoApp::getInstance ()->recordingstatus && clearClock == 1) + { + strcpy(timestr," : "); + clearClock = 0; + } + else + { + strftime((char*) ×tr, 20, "%H:%M", t); + clearClock = 1; + } + + display.draw_fill_rect (77, 50, LCD_COLS, 64, CLCDDisplay::PIXEL_OFF); + + fonts.time->RenderString(122 - fonts.time->getRenderWidth(timestr), 62, 50, timestr, CLCDDisplay::PIXEL_ON); + } + displayUpdate(); + } +} + +void CLCD::showRCLock(int duration) +{ + std::string icon = DATADIR "/lcdd/icons/rclock.raw"; + raw_display_t curr_screen; + + // Saving the whole screen is not really nice since the clock is updated + // every second. Restoring the screen can cause a short travel to the past ;) + display.dump_screen(&curr_screen); + display.draw_fill_rect (-1, 10, LCD_COLS, 50, CLCDDisplay::PIXEL_OFF); + display.paintIcon(icon,44,25,false); + wake_up(); + displayUpdate(); + sleep(duration); + display.load_screen(&curr_screen); + wake_up(); + displayUpdate(); +} + +void CLCD::showVolume(const char vol, const bool perform_update) +{ + volume = vol; + if ( + ((mode == MODE_TVRADIO) && (g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME])) || + ((mode == MODE_MOVIE) && (g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME])) || + (mode == MODE_SCART) || + (mode == MODE_AUDIO) + ) + { + display.draw_fill_rect (11,53,73,61, CLCDDisplay::PIXEL_OFF); + //strichlin + if ((muted) || (volume==0)) + { + display.draw_line (12,55,72,59, CLCDDisplay::PIXEL_ON); + } + else + { + int dp = vol*61/100+12; + display.draw_fill_rect (11,54,dp,60, CLCDDisplay::PIXEL_ON); + } + if(mode == MODE_AUDIO) + { + display.draw_fill_rect (-1, 51, 10, 62, CLCDDisplay::PIXEL_OFF); + display.draw_rectangle ( 1, 55, 3, 58, CLCDDisplay::PIXEL_ON, CLCDDisplay::PIXEL_OFF); + display.draw_line ( 3, 55, 6, 52, CLCDDisplay::PIXEL_ON); + display.draw_line ( 3, 58, 6, 61, CLCDDisplay::PIXEL_ON); + display.draw_line ( 6, 54, 6, 59, CLCDDisplay::PIXEL_ON); + } + + if (perform_update) + displayUpdate(); + } + wake_up(); +} + +void CLCD::showPercentOver(const unsigned char perc, const bool perform_update, const MODES m) +{ + if (mode != m) + return; + + int left, top, width, height = 5; + bool draw = true; + percentOver = perc; + if (mode == MODE_TVRADIO || mode == MODE_MOVIE) + { + if (g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME] == 0) + { + left = 12; top = 55; width = 60; + } + else if (g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME] == 2) + { + left = 12; top = 3; width = 104; + } + else if (g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME] == 3) + { + left = 12; top = 3; width = 84; + + if ((g_RemoteControl != NULL && mode == MODE_TVRADIO) || mode == MODE_MOVIE) + { + bool is_ac3; + if (mode == MODE_MOVIE) + is_ac3 = movie_is_ac3; + else + { + uint count = g_RemoteControl->current_PIDs.APIDs.size(); + if ((g_RemoteControl->current_PIDs.PIDs.selected_apid < count) && + (g_RemoteControl->current_PIDs.APIDs[g_RemoteControl->current_PIDs.PIDs.selected_apid].is_ac3)) + is_ac3 = true; + else + is_ac3 = false; + } + + const char * icon; + if (is_ac3) + icon = DATADIR "/lcdd/icons/dd.raw"; + else + icon = DATADIR "/lcdd/icons/stereo.raw"; + + display.paintIcon(icon, 101, 1, false); + } + } + else + draw = false; + + if (draw) + { + display.draw_fill_rect (left-1, top-1, left+width+1, top+height, CLCDDisplay::PIXEL_OFF); + if (perc == (unsigned char) -1) + { + display.draw_line (left, top, left+width, top+height-1, CLCDDisplay::PIXEL_ON); + } + else + { + int dp; + if (perc == (unsigned char) -2) + dp = width+1; + else + dp = perc * (width + 1) / 100; + display.draw_fill_rect (left-1, top-1, left+dp, top+height, CLCDDisplay::PIXEL_ON); + + if (perc == (unsigned char) -2) + { + // draw a "+" to show that the event is overdue + display.draw_line(left+width-2, top+1, left+width-2, top+height-2, CLCDDisplay::PIXEL_OFF); + display.draw_line(left+width-1, top+(height/2), left+width-3, top+(height/2), CLCDDisplay::PIXEL_OFF); + } + } + } + + if (perform_update) + displayUpdate(); + } +} + +void CLCD::showMenuText(const int position, const char * text, const int highlight, const bool utf_encoded) +{ + if (mode != MODE_MENU_UTF8) + return; + + // reload specified line + display.draw_fill_rect(-1, 35+14*position, LCD_COLS, 35+14+14*position, CLCDDisplay::PIXEL_OFF); + fonts.menu->RenderString(0,35+11+14*position, LCD_COLS + 20, text, CLCDDisplay::PIXEL_INV, highlight, utf_encoded); + wake_up(); + displayUpdate(); + +} + +void CLCD::showAudioTrack(const std::string & artist, const std::string & title, const std::string & album) +{ + if (mode != MODE_AUDIO) + { + return; + } + + // reload specified line + display.draw_fill_rect (-1, 10, LCD_COLS, 24, CLCDDisplay::PIXEL_OFF); + display.draw_fill_rect (-1, 20, LCD_COLS, 37, CLCDDisplay::PIXEL_OFF); + display.draw_fill_rect (-1, 33, LCD_COLS, 50, CLCDDisplay::PIXEL_OFF); + fonts.menu->RenderString(0, 22, LCD_COLS + 5, artist.c_str(), CLCDDisplay::PIXEL_ON, 0, isUTF8(artist)); + fonts.menu->RenderString(0, 35, LCD_COLS + 5, album.c_str(), CLCDDisplay::PIXEL_ON, 0, isUTF8(album)); + fonts.menu->RenderString(0, 48, LCD_COLS + 5, title.c_str(), CLCDDisplay::PIXEL_ON, 0, isUTF8(title)); + wake_up(); + displayUpdate(); + +} + +void CLCD::showAudioPlayMode(AUDIOMODES m) +{ + display.draw_fill_rect (-1,51,10,62, CLCDDisplay::PIXEL_OFF); + switch(m) + { + case AUDIO_MODE_PLAY: + { + int x=3,y=53; + display.draw_line(x ,y ,x ,y+8, CLCDDisplay::PIXEL_ON); + display.draw_line(x+1,y+1,x+1,y+7, CLCDDisplay::PIXEL_ON); + display.draw_line(x+2,y+2,x+2,y+6, CLCDDisplay::PIXEL_ON); + display.draw_line(x+3,y+3,x+3,y+5, CLCDDisplay::PIXEL_ON); + display.draw_line(x+4,y+4,x+4,y+4, CLCDDisplay::PIXEL_ON); + break; + } + case AUDIO_MODE_STOP: + display.draw_fill_rect (1, 53, 8 ,61, CLCDDisplay::PIXEL_ON); + break; + case AUDIO_MODE_PAUSE: + display.draw_line(1,54,1,60, CLCDDisplay::PIXEL_ON); + display.draw_line(2,54,2,60, CLCDDisplay::PIXEL_ON); + display.draw_line(6,54,6,60, CLCDDisplay::PIXEL_ON); + display.draw_line(7,54,7,60, CLCDDisplay::PIXEL_ON); + break; + case AUDIO_MODE_FF: + { + int x=2,y=55; + display.draw_line(x ,y , x , y+4, CLCDDisplay::PIXEL_ON); + display.draw_line(x+1 ,y+1 , x+1, y+3, CLCDDisplay::PIXEL_ON); + display.draw_line(x+2 ,y+2 , x+2, y+2, CLCDDisplay::PIXEL_ON); + display.draw_line(x+3 ,y , x+3, y+4, CLCDDisplay::PIXEL_ON); + display.draw_line(x+4 ,y+1 , x+4, y+3, CLCDDisplay::PIXEL_ON); + display.draw_line(x+5 ,y+2 , x+5, y+2, CLCDDisplay::PIXEL_ON); + } + break; + case AUDIO_MODE_REV: + { + int x=2,y=55; + display.draw_line(x ,y+2 , x , y+2, CLCDDisplay::PIXEL_ON); + display.draw_line(x+1 ,y+1 , x+1, y+3, CLCDDisplay::PIXEL_ON); + display.draw_line(x+2 ,y , x+2, y+4, CLCDDisplay::PIXEL_ON); + display.draw_line(x+3 ,y+2 , x+3, y+2, CLCDDisplay::PIXEL_ON); + display.draw_line(x+4 ,y+1 , x+4, y+3, CLCDDisplay::PIXEL_ON); + display.draw_line(x+5 ,y , x+5, y+4, CLCDDisplay::PIXEL_ON); + } + break; + } + wake_up(); + displayUpdate(); +} + +void CLCD::showAudioProgress(const char perc, bool isMuted) +{ + if (mode == MODE_AUDIO) + { + display.draw_fill_rect (11,53,73,61, CLCDDisplay::PIXEL_OFF); + int dp = int( perc/100.0*61.0+12.0); + display.draw_fill_rect (11,54,dp,60, CLCDDisplay::PIXEL_ON); + if(isMuted) + { + if(dp > 12) + { + display.draw_line(12, 56, dp-1, 56, CLCDDisplay::PIXEL_OFF); + display.draw_line(12, 58, dp-1, 58, CLCDDisplay::PIXEL_OFF); + } + else + display.draw_line (12,55,72,59, CLCDDisplay::PIXEL_ON); + } + displayUpdate(); + } +} + +void CLCD::setMode(const MODES m, const char * const title) +{ + mode = m; + menutitle = title; + setlcdparameter(); + + switch (m) + { + case MODE_TVRADIO: + case MODE_MOVIE: + switch (g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME]) + { + case 0: + display.load_screen(&(background[BACKGROUND_LCD2])); + showPercentOver(percentOver, false, mode); + break; + case 1: + display.load_screen(&(background[BACKGROUND_LCD])); + showVolume(volume, false); + break; + case 2: + display.load_screen(&(background[BACKGROUND_LCD3])); + showVolume(volume, false); + showPercentOver(percentOver, false, mode); + break; + case 3: + display.load_screen(&(background[BACKGROUND_LCD3])); + showVolume(volume, false); + showPercentOver(percentOver, false, mode); + break; + default: + break; + } + if (mode == MODE_TVRADIO) + showServicename(servicename); + else + { + setMovieInfo(movie_playmode, movie_big, movie_small, movie_centered); + setMovieAudio(movie_is_ac3); + } + showclock = true; + showTime(); /* "showclock = true;" implies that "showTime();" does a "displayUpdate();" */ + break; + case MODE_AUDIO: + { + display.load_screen(&(background[BACKGROUND_LCD])); + display.draw_fill_rect(0, 14, LCD_COLS, 48, CLCDDisplay::PIXEL_OFF); + + showAudioPlayMode(AUDIO_MODE_STOP); + showVolume(volume, false); + showclock = true; + showTime(); /* "showclock = true;" implies that "showTime();" does a "displayUpdate();" */ + break; + } + case MODE_SCART: + display.load_screen(&(background[BACKGROUND_LCD])); + showVolume(volume, false); + showclock = true; + showTime(); /* "showclock = true;" implies that "showTime();" does a "displayUpdate();" */ + break; + case MODE_MENU_UTF8: + showclock = false; + display.load_screen(&(background[BACKGROUND_SETUP])); + fonts.menutitle->RenderString(0, 28, LCD_COLS + 20, title, CLCDDisplay::PIXEL_ON, 0, true); // UTF-8 + displayUpdate(); + break; + case MODE_SHUTDOWN: + showclock = false; + display.load_screen(&(background[BACKGROUND_POWER])); + displayUpdate(); + break; + case MODE_STANDBY: + showclock = true; + showTime(); /* "showclock = true;" implies that "showTime();" does a "displayUpdate();" */ + /* "showTime()" clears the whole lcd in MODE_STANDBY */ + break; +#ifdef LCD_UPDATE + case MODE_FILEBROWSER: + showclock = true; + display.draw_fill_rect(-1, -1, LCD_COLS, 64, CLCDDisplay::PIXEL_OFF); // clear lcd + showFilelist(); + break; + case MODE_PROGRESSBAR: + showclock = false; + display.load_screen(&(background[BACKGROUND_SETUP])); + showProgressBar(); + break; + case MODE_PROGRESSBAR2: + showclock = false; + display.load_screen(&(background[BACKGROUND_SETUP])); + showProgressBar2(); + break; + case MODE_INFOBOX: + showclock = false; + showInfoBox(); + break; +#endif // LCD_UPDATE + } + wake_up(); +} + + +void CLCD::setBrightness(int bright) +{ + g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS] = bright; + setlcdparameter(); +} + +int CLCD::getBrightness() +{ + return g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS]; +} + +void CLCD::setBrightnessStandby(int bright) +{ + g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS] = bright; + setlcdparameter(); +} + +int CLCD::getBrightnessStandby() +{ + return g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS]; +} + +void CLCD::setContrast(int contrast) +{ + g_settings.lcd_setting[SNeutrinoSettings::LCD_CONTRAST] = contrast; + setlcdparameter(); +} + +int CLCD::getContrast() +{ + return g_settings.lcd_setting[SNeutrinoSettings::LCD_CONTRAST]; +} + +void CLCD::setPower(int power) +{ + g_settings.lcd_setting[SNeutrinoSettings::LCD_POWER] = power; + setlcdparameter(); +} + +int CLCD::getPower() +{ + return g_settings.lcd_setting[SNeutrinoSettings::LCD_POWER]; +} + +void CLCD::togglePower(void) +{ + last_toggle_state_power = 1 - last_toggle_state_power; + setlcdparameter((mode == MODE_STANDBY) ? g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS] : g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS], + g_settings.lcd_setting[SNeutrinoSettings::LCD_CONTRAST], + last_toggle_state_power, + g_settings.lcd_setting[SNeutrinoSettings::LCD_INVERSE], + 0 /*g_settings.lcd_setting[SNeutrinoSettings::LCD_BIAS]*/); +} + +void CLCD::setInverse(int inverse) +{ + g_settings.lcd_setting[SNeutrinoSettings::LCD_INVERSE] = inverse; + setlcdparameter(); +} + +int CLCD::getInverse() +{ + return g_settings.lcd_setting[SNeutrinoSettings::LCD_INVERSE]; +} + +void CLCD::setAutoDimm(int autodimm) +{ +#ifdef HAVE_DBOX_HARDWARE + int fd; + g_settings.lcd_setting[SNeutrinoSettings::LCD_AUTODIMM] = autodimm; + + if ((fd = open("/dev/dbox/fp0", O_RDWR)) == -1) + { + perror("[lcdd] open '/dev/dbox/fp0' failed"); + } + else + { + if( ioctl(fd, FP_IOCTL_LCD_AUTODIMM, &autodimm) < 0 ) + { + perror("[lcdd] set autodimm failed!"); + } + + close(fd); + } +#endif +} + +int CLCD::getAutoDimm() +{ + return g_settings.lcd_setting[SNeutrinoSettings::LCD_AUTODIMM]; +} + +void CLCD::setMuted(bool mu) +{ + muted = mu; + showVolume(volume); +} + +void CLCD::resume() +{ + display.resume(); +} + +void CLCD::pause() +{ + display.pause(); +} + +void CLCD::ShowIcon(vfd_icon icon, bool show) +{ + fprintf(stderr, "CLCD::ShowIcon(%d, %d)\n", icon, show); +} + +void CLCD::Lock() +{ +/* + if(!has_lcd) return; + creat("/tmp/vfd.locked", 0); +*/ +} + +void CVFD::Unlock() +{ +/* + if(!has_lcd) return; + unlink("/tmp/vfd.locked"); +*/ +} + +void CLCD::Clear() +{ + return; +} + +#ifdef LCD_UPDATE +/*****************************************************************************************/ +// showInfoBox +/*****************************************************************************************/ +#define LCD_WIDTH LCD_COLS +#define LCD_HEIGTH 64 + +#define EPG_INFO_FONT_HEIGHT 9 +#define EPG_INFO_SHADOW_WIDTH 1 +#define EPG_INFO_LINE_WIDTH 1 +#define EPG_INFO_BORDER_WIDTH 2 + +#define EPG_INFO_WINDOW_POS 4 +#define EPG_INFO_LINE_POS EPG_INFO_WINDOW_POS + EPG_INFO_SHADOW_WIDTH +#define EPG_INFO_BORDER_POS EPG_INFO_WINDOW_POS + EPG_INFO_SHADOW_WIDTH + EPG_INFO_LINE_WIDTH +#define EPG_INFO_TEXT_POS EPG_INFO_WINDOW_POS + EPG_INFO_SHADOW_WIDTH + EPG_INFO_LINE_WIDTH + EPG_INFO_BORDER_WIDTH + +#define EPG_INFO_TEXT_WIDTH LCD_WIDTH - (2*EPG_INFO_WINDOW_POS) + +// timer 0: OFF, timer>0 time to show in seconds, timer>=999 endless +void CLCD::showInfoBox(const char * const title, const char * const text ,int autoNewline,int timer) +{ + //printf("[lcdd] Info: \n"); + if(text != NULL) + m_infoBoxText = text; + if(title != NULL) + m_infoBoxTitle = title; + if(timer != -1) + m_infoBoxTimer = timer; + if(autoNewline != -1) + m_infoBoxAutoNewline = autoNewline; + + //printf("[lcdd] Info: %s,%s,%d,%d\n",m_infoBoxTitle.c_str(),m_infoBoxText.c_str(),m_infoBoxAutoNewline,m_infoBoxTimer); + if( mode == MODE_INFOBOX && + !m_infoBoxText.empty()) + { + // paint empty box + display.draw_fill_rect (EPG_INFO_WINDOW_POS, EPG_INFO_WINDOW_POS, LCD_WIDTH-EPG_INFO_WINDOW_POS+1, LCD_HEIGTH-EPG_INFO_WINDOW_POS+1, CLCDDisplay::PIXEL_OFF); + display.draw_fill_rect (EPG_INFO_LINE_POS, EPG_INFO_LINE_POS, LCD_WIDTH-EPG_INFO_LINE_POS-1, LCD_HEIGTH-EPG_INFO_LINE_POS-1, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (EPG_INFO_BORDER_POS, EPG_INFO_BORDER_POS, LCD_WIDTH-EPG_INFO_BORDER_POS-3, LCD_HEIGTH-EPG_INFO_BORDER_POS-3, CLCDDisplay::PIXEL_OFF); + + // paint title + if(!m_infoBoxTitle.empty()) + { + int width = fonts.menu->getRenderWidth(m_infoBoxTitle.c_str(),true); + if(width > LCD_COLS - 20) + width = LCD_COLS - 20; + int start_pos = (LCD_COLS - width) /2; + display.draw_fill_rect (start_pos, EPG_INFO_WINDOW_POS-4, start_pos+width+5, EPG_INFO_WINDOW_POS+10, CLCDDisplay::PIXEL_OFF); + fonts.menu->RenderString(start_pos+4,EPG_INFO_WINDOW_POS+5, width+5, m_infoBoxTitle.c_str(), CLCDDisplay::PIXEL_ON, 0, true); // UTF-8 + } + + // paint info + std::string text_line; + int line; + int pos = 0; + int length = m_infoBoxText.size(); + for(line = 0; line < 5; line++) + { + text_line.clear(); + while ( m_infoBoxText[pos] != '\n' && + ((fonts.menu->getRenderWidth(text_line.c_str(), true) < EPG_INFO_TEXT_WIDTH-10) || !m_infoBoxAutoNewline )&& + (pos < length)) // UTF-8 + { + if ( m_infoBoxText[pos] >= ' ' && m_infoBoxText[pos] <= '~' ) // any char between ASCII(32) and ASCII (126) + text_line += m_infoBoxText[pos]; + pos++; + } + //printf("[lcdd] line %d:'%s'\r\n",line,text_line.c_str()); + fonts.menu->RenderString(EPG_INFO_TEXT_POS+1,EPG_INFO_TEXT_POS+(line*EPG_INFO_FONT_HEIGHT)+EPG_INFO_FONT_HEIGHT+3, EPG_INFO_TEXT_WIDTH, text_line.c_str(), CLCDDisplay::PIXEL_ON, 0, true); // UTF-8 + if ( m_infoBoxText[pos] == '\n' ) + pos++; // remove new line + } + displayUpdate(); + } +} + +/*****************************************************************************************/ +//showFilelist +/*****************************************************************************************/ +#define BAR_POS_X 114 +#define BAR_POS_Y 10 +#define BAR_POS_WIDTH 6 +#define BAR_POS_HEIGTH 40 + +void CLCD::showFilelist(int flist_pos,CFileList* flist,const char * const mainDir) +{ + //printf("[lcdd] FileList\n"); + if(flist != NULL) + m_fileList = flist; + if(flist_pos != -1) + m_fileListPos = flist_pos; + if(mainDir != NULL) + m_fileListHeader = mainDir; + + if (mode == MODE_FILEBROWSER && + m_fileList != NULL && + m_fileList->size() > 0) + { + + printf("[lcdd] FileList:OK\n"); + int size = m_fileList->size(); + + display.draw_fill_rect(-1, -1, LCD_COLS, 52, CLCDDisplay::PIXEL_OFF); // clear lcd + + if(m_fileListPos > size) + m_fileListPos = size-1; + + int width = fonts.menu->getRenderWidth(m_fileListHeader.c_str(), true); + if(width > LCD_COLS - 10) + width = LCD_COLS - 10; + fonts.menu->RenderString((LCD_COLS - width) / 2, 11, width+5, m_fileListHeader.c_str(), CLCDDisplay::PIXEL_ON); + + //printf("list%d,%d\r\n",m_fileListPos,(*m_fileList)[m_fileListPos].Marked); + std::string text; + int marked; + if(m_fileListPos > 0) + { + if ( (*m_fileList)[m_fileListPos-1].Marked == false ) + { + text =""; + marked = CLCDDisplay::PIXEL_ON; + } + else + { + text ="*"; + marked = CLCDDisplay::PIXEL_INV; + } + text += (*m_fileList)[m_fileListPos-1].getFileName(); + fonts.menu->RenderString(1, 12+12, BAR_POS_X+5, text.c_str(), marked); + } + if(m_fileListPos < size) + { + if ((*m_fileList)[m_fileListPos-0].Marked == false ) + { + text =""; + marked = CLCDDisplay::PIXEL_ON; + } + else + { + text ="*"; + marked = CLCDDisplay::PIXEL_INV; + } + text += (*m_fileList)[m_fileListPos-0].getFileName(); + fonts.time->RenderString(1, 12+12+14, BAR_POS_X+5, text.c_str(), marked); + } + if(m_fileListPos < size-1) + { + if ((*m_fileList)[m_fileListPos+1].Marked == false ) + { + text =""; + marked = CLCDDisplay::PIXEL_ON; + } + else + { + text ="*"; + marked = CLCDDisplay::PIXEL_INV; + } + text += (*m_fileList)[m_fileListPos+1].getFileName(); + fonts.menu->RenderString(1, 12+12+14+12, BAR_POS_X+5, text.c_str(), marked); + } + // paint marker + int pages = (((size-1)/3 )+1); + int marker_length = (BAR_POS_HEIGTH-2) / pages; + if(marker_length <4) + marker_length=4;// not smaller than 4 pixel + int marker_offset = ((BAR_POS_HEIGTH-2-marker_length) * m_fileListPos) /size ; + //printf("%d,%d,%d\r\n",pages,marker_length,marker_offset); + + display.draw_fill_rect (BAR_POS_X, BAR_POS_Y, BAR_POS_X+BAR_POS_WIDTH, BAR_POS_Y+BAR_POS_HEIGTH, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (BAR_POS_X+1, BAR_POS_Y+1, BAR_POS_X+BAR_POS_WIDTH-1, BAR_POS_Y+BAR_POS_HEIGTH-1, CLCDDisplay::PIXEL_OFF); + display.draw_fill_rect (BAR_POS_X+1, BAR_POS_Y+1+marker_offset, BAR_POS_X+BAR_POS_WIDTH-1, BAR_POS_Y+1+marker_offset+marker_length, CLCDDisplay::PIXEL_ON); + + displayUpdate(); + } +} + +/*****************************************************************************************/ +//showProgressBar +/*****************************************************************************************/ +#define PROG_GLOB_POS_X 10 +#define PROG_GLOB_POS_Y 30 +#define PROG_GLOB_POS_WIDTH 100 +#define PROG_GLOB_POS_HEIGTH 20 +void CLCD::showProgressBar(int global, const char * const text,int show_escape,int timer) +{ + if(text != NULL) + m_progressHeaderGlobal = text; + + if(timer != -1) + m_infoBoxTimer = timer; + + if(global >= 0) + { + if(global > 100) + m_progressGlobal =100; + else + m_progressGlobal = global; + } + + if(show_escape != -1) + m_progressShowEscape = show_escape; + + if (mode == MODE_PROGRESSBAR) + { + //printf("[lcdd] prog:%s,%d,%d\n",m_progressHeaderGlobal.c_str(),m_progressGlobal,m_progressShowEscape); + // Clear Display + display.draw_fill_rect (0, 12, LCD_COLS, 64, CLCDDisplay::PIXEL_OFF); + + // paint progress header + int width = fonts.menu->getRenderWidth(m_progressHeaderGlobal.c_str(),true); + if(width > 100) + width = 100; + int start_pos = (LCD_COLS - width) /2; + fonts.menu->RenderString(start_pos, 12+12, width+10, m_progressHeaderGlobal.c_str(), CLCDDisplay::PIXEL_ON,0,true); + + // paint global bar + int marker_length = (PROG_GLOB_POS_WIDTH * m_progressGlobal)/100; + + display.draw_fill_rect (PROG_GLOB_POS_X, PROG_GLOB_POS_Y, PROG_GLOB_POS_X+PROG_GLOB_POS_WIDTH, PROG_GLOB_POS_Y+PROG_GLOB_POS_HEIGTH, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (PROG_GLOB_POS_X+1+marker_length, PROG_GLOB_POS_Y+1, PROG_GLOB_POS_X+PROG_GLOB_POS_WIDTH-1, PROG_GLOB_POS_Y+PROG_GLOB_POS_HEIGTH-1, CLCDDisplay::PIXEL_OFF); + + // paint foot + if(m_progressShowEscape == true) + { + fonts.menu->RenderString(90, 64, 40, "Home", CLCDDisplay::PIXEL_ON); + } + displayUpdate(); + } +} + +/*****************************************************************************************/ +// showProgressBar2 +/*****************************************************************************************/ +#define PROG2_GLOB_POS_X 10 +#define PROG2_GLOB_POS_Y 37 +#define PROG2_GLOB_POS_WIDTH 100 +#define PROG2_GLOB_POS_HEIGTH 10 + +#define PROG2_LOCAL_POS_X 10 +#define PROG2_LOCAL_POS_Y 24 +#define PROG2_LOCAL_POS_WIDTH PROG2_GLOB_POS_WIDTH +#define PROG2_LOCAL_POS_HEIGTH PROG2_GLOB_POS_HEIGTH + +void CLCD::showProgressBar2(int local,const char * const text_local ,int global ,const char * const text_global ,int show_escape ) +{ + //printf("[lcdd] prog2\n"); + if(text_local != NULL) + m_progressHeaderLocal = text_local; + + if(text_global != NULL) + m_progressHeaderGlobal = text_global; + + if(global >= 0) + { + if(global > 100) + m_progressGlobal =100; + else + m_progressGlobal = global; + } + + if(local >= 0) + { + if(local > 100) + m_progressLocal =100; + else + m_progressLocal = local; + } + + if(show_escape != -1) + m_progressShowEscape = show_escape; + + if (mode == MODE_PROGRESSBAR2) + { + //printf("[lcdd] prog2:%s,%d,%d\n",m_progressHeaderGlobal.c_str(),m_progressGlobal,m_progressShowEscape); + // Clear Display + display.draw_fill_rect (0, 12, LCD_COLS, 64, CLCDDisplay::PIXEL_OFF); + + + // paint global caption + int width = fonts.menu->getRenderWidth(m_progressHeaderGlobal.c_str(),true); + if(width > 100) + width = 100; + int start_pos = (LCD_COLS - width) /2; + fonts.menu->RenderString(start_pos, PROG2_GLOB_POS_Y+20, width+10, m_progressHeaderGlobal.c_str(), CLCDDisplay::PIXEL_ON,0,true); + + // paint global bar + int marker_length = (PROG2_GLOB_POS_WIDTH * m_progressGlobal)/100; + + display.draw_fill_rect (PROG2_GLOB_POS_X, PROG2_GLOB_POS_Y, PROG2_GLOB_POS_X+PROG2_GLOB_POS_WIDTH, PROG2_GLOB_POS_Y+PROG2_GLOB_POS_HEIGTH, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (PROG2_GLOB_POS_X+1+marker_length, PROG2_GLOB_POS_Y+1, PROG2_GLOB_POS_X+PROG2_GLOB_POS_WIDTH-1, PROG2_GLOB_POS_Y+PROG2_GLOB_POS_HEIGTH-1, CLCDDisplay::PIXEL_OFF); + + + // paint local caption + width = fonts.menu->getRenderWidth(m_progressHeaderLocal.c_str(),true); + if(width > 100) + width = 100; + start_pos = (LCD_COLS - width) /2; + fonts.menu->RenderString(start_pos, PROG2_LOCAL_POS_Y -3, width+10, m_progressHeaderLocal.c_str(), CLCDDisplay::PIXEL_ON,0,true); + // paint local bar + marker_length = (PROG2_LOCAL_POS_WIDTH * m_progressLocal)/100; + + display.draw_fill_rect (PROG2_LOCAL_POS_X, PROG2_LOCAL_POS_Y, PROG2_LOCAL_POS_X+PROG2_LOCAL_POS_WIDTH, PROG2_LOCAL_POS_Y+PROG2_LOCAL_POS_HEIGTH, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (PROG2_LOCAL_POS_X+1+marker_length, PROG2_LOCAL_POS_Y+1, PROG2_LOCAL_POS_X+PROG2_LOCAL_POS_WIDTH-1, PROG2_LOCAL_POS_Y+PROG2_LOCAL_POS_HEIGTH-1, CLCDDisplay::PIXEL_OFF); + + + // paint foot + if(m_progressShowEscape == true) + { + fonts.menu->RenderString(90, 64, 40, "Home", CLCDDisplay::PIXEL_ON); + } + displayUpdate(); + } +} +/*****************************************************************************************/ +#endif // LCD_UPDATE diff --git a/src/driver/lcdd.h b/src/driver/lcdd.h new file mode 100644 index 000000000..1e7e5be15 --- /dev/null +++ b/src/driver/lcdd.h @@ -0,0 +1,256 @@ +/* + $Id$ + + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + 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. +*/ + +#ifndef __lcdd__ +#define __lcdd__ + +#ifndef LCD_UPDATE +#define LCD_UPDATE 1 +#endif + +#define LCDDIR_VAR "/var/share/tuxbox/neutrino/lcdd" + +typedef enum +{ + VFD_ICON_BAR8 = 0x00000004, + VFD_ICON_BAR7 = 0x00000008, + VFD_ICON_BAR6 = 0x00000010, + VFD_ICON_BAR5 = 0x00000020, + VFD_ICON_BAR4 = 0x00000040, + VFD_ICON_BAR3 = 0x00000080, + VFD_ICON_BAR2 = 0x00000100, + VFD_ICON_BAR1 = 0x00000200, + VFD_ICON_FRAME = 0x00000400, + VFD_ICON_HDD = 0x00000800, + VFD_ICON_MUTE = 0x00001000, + VFD_ICON_DOLBY = 0x00002000, + VFD_ICON_POWER = 0x00004000, + VFD_ICON_TIMESHIFT = 0x00008000, + VFD_ICON_SIGNAL = 0x00010000, + VFD_ICON_TV = 0x00020000, + VFD_ICON_RADIO = 0x00040000, + VFD_ICON_HD = 0x01000001, + VFD_ICON_1080P = 0x02000001, + VFD_ICON_1080I = 0x03000001, + VFD_ICON_720P = 0x04000001, + VFD_ICON_480P = 0x05000001, + VFD_ICON_480I = 0x06000001, + VFD_ICON_USB = 0x07000001, + VFD_ICON_MP3 = 0x08000001, + VFD_ICON_PLAY = 0x09000001, + VFD_ICON_COL1 = 0x09000002, + VFD_ICON_PAUSE = 0x0A000001, + VFD_ICON_CAM1 = 0x0B000001, + VFD_ICON_COL2 = 0x0B000002, + VFD_ICON_CAM2 = 0x0C000001 +} vfd_icon; + +#ifdef LCD_UPDATE +#ifdef HAVE_CONFIG_H +#include +#endif +// TODO Why is USE_FILE_OFFSET64 not defined, if file.h is included here???? +#ifndef __USE_FILE_OFFSET64 +#define __USE_FILE_OFFSET64 1 +#endif +#include "driver/file.h" +#endif // LCD_UPDATE + +#include +#include + +#include + + +class CLCDPainter; +class LcdFontRenderClass; +class CLCD +{ + public: + + enum MODES + { + MODE_TVRADIO, + MODE_SCART, + MODE_SHUTDOWN, + MODE_STANDBY, + MODE_MENU_UTF8, + MODE_AUDIO, + MODE_MOVIE +#ifdef LCD_UPDATE + , MODE_FILEBROWSER, + MODE_PROGRESSBAR, + MODE_PROGRESSBAR2, + MODE_INFOBOX +#endif // LCD_UPDATE + }; + enum AUDIOMODES + { + AUDIO_MODE_PLAY, + AUDIO_MODE_STOP, + AUDIO_MODE_FF, + AUDIO_MODE_PAUSE, + AUDIO_MODE_REV + }; + + + private: + + class FontsDef + { + public: + LcdFont *channelname; + LcdFont *time; + LcdFont *menutitle; + LcdFont *menu; + }; + + CLCDDisplay display; + LcdFontRenderClass *fontRenderer; + FontsDef fonts; + +#define LCD_NUMBER_OF_BACKGROUNDS 5 + raw_display_t background[LCD_NUMBER_OF_BACKGROUNDS]; + + MODES mode; + AUDIOMODES movie_playmode; + + std::string servicename; + std::string epg_title; + std::string movie_big; + std::string movie_small; + std::string menutitle; + char volume; + unsigned char percentOver; + bool muted; + bool showclock; + bool movie_centered; + bool movie_is_ac3; + CConfigFile configfile; + pthread_t thrTime; + int last_toggle_state_power; + int clearClock; + unsigned int timeout_cnt; + + void count_down(); + + CLCD(); + + static void* TimeThread(void*); + bool lcdInit(const char * fontfile1, const char * fontname1, + const char * fontfile2=NULL, const char * fontname2=NULL, + const char * fontfile3=NULL, const char * fontname3=NULL); + void setlcdparameter(int dimm, int contrast, int power, int inverse, int bias); + void displayUpdate(); + void showTextScreen(const std::string & big, const std::string & small, int showmode, bool perform_wakeup, bool centered = false); + + public: + bool has_lcd; + void wake_up(); + void setled(void) { return; }; + void setlcdparameter(void); + + static CLCD* getInstance(); + void init(const char * fontfile, const char * fontname, + const char * fontfile2=NULL, const char * fontname2=NULL, + const char * fontfile3=NULL, const char * fontname3=NULL); + + void setMode(const MODES m, const char * const title = ""); + MODES getMode() { return mode; }; + + void showServicename(const std::string name, const bool perform_wakeup = true); // UTF-8 + void setEPGTitle(const std::string title); + void setMovieInfo(const AUDIOMODES playmode, const std::string big, const std::string small, const bool centered = false); + void setMovieAudio(const bool is_ac3); + std::string getMenutitle() { return menutitle; }; + void showTime(); + /** blocks for duration seconds */ + void showRCLock(int duration = 2); + void showVolume(const char vol, const bool perform_update = true); + void showPercentOver(const unsigned char perc, const bool perform_update = true, const MODES m = MODE_TVRADIO); + void showMenuText(const int position, const char * text, const int highlight = -1, const bool utf_encoded = false); + void showAudioTrack(const std::string & artist, const std::string & title, const std::string & album); + void showAudioPlayMode(AUDIOMODES m=AUDIO_MODE_PLAY); + void showAudioProgress(const char perc, bool isMuted); + void setBrightness(int); + int getBrightness(); + + void setBrightnessStandby(int); + int getBrightnessStandby(); + + void setContrast(int); + int getContrast(); + + void setPower(int); + int getPower(); + + void togglePower(void); + + void setInverse(int); + int getInverse(); + + void setAutoDimm(int); + int getAutoDimm(); + void setBrightnessDeepStandby(int) { return ; }; + int getBrightnessDeepStandby() { return 0; }; + + void setMuted(bool); + + void resume(); + void pause(); + + void Lock(); + void Unlock(); + void Clear(); + void ShowIcon(vfd_icon icon, bool show); + void ShowText(const char *s) { showServicename(std::string(s)); }; +#ifdef LCD_UPDATE + private: + CFileList* m_fileList; + int m_fileListPos; + std::string m_fileListHeader; + + std::string m_infoBoxText; + std::string m_infoBoxTitle; + int m_infoBoxTimer; // for later use + bool m_infoBoxAutoNewline; + + bool m_progressShowEscape; + std::string m_progressHeaderGlobal; + std::string m_progressHeaderLocal; + int m_progressGlobal; + int m_progressLocal; + public: + void showFilelist(int flist_pos = -1,CFileList* flist = NULL,const char * const mainDir=NULL); + void showInfoBox(const char * const title = NULL,const char * const text = NULL,int autoNewline = -1,int timer = -1); + void showProgressBar(int global = -1,const char * const text = NULL,int show_escape = -1,int timer = -1); + void showProgressBar2(int local = -1,const char * const text_local = NULL,int global = -1,const char * const text_global = NULL,int show_escape = -1); +#endif // LCD_UPDATE +}; + + +#endif diff --git a/src/driver/lcdfontrenderer.cpp b/src/driver/lcdfontrenderer.cpp new file mode 100644 index 000000000..471425a24 --- /dev/null +++ b/src/driver/lcdfontrenderer.cpp @@ -0,0 +1,302 @@ +/* + $Header$ + + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Copyright (C) 2003 thegoodguy + baseroutines by tmbinc + + + 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. +*/ + +#include +#include + +#include +#include +#include + +#include +#include FT_FREETYPE_H + +FT_Error LcdFontRenderClass::myFTC_Face_Requester(FTC_FaceID face_id, + FT_Library library, + FT_Pointer request_data, + FT_Face* aface) +{ + return ((LcdFontRenderClass*)request_data)->FTC_Face_Requester(face_id, aface); +} + + +LcdFontRenderClass::LcdFontRenderClass(CLCDDisplay * fb) +{ + framebuffer = fb; + printf("[LCDFONT] initializing core..."); + fflush(stdout); + if (FT_Init_FreeType(&library)) + { + printf("failed.\n"); + return; + } + printf("\n"); + font=0; + pthread_mutex_init(&render_mutex, NULL); +} + +LcdFontRenderClass::~LcdFontRenderClass() +{ + FTC_Manager_Done(cacheManager); + FT_Done_FreeType(library); +} + +void LcdFontRenderClass::InitFontCache() +{ + printf("[LCDFONT] Intializing font cache..."); + fflush(stdout); + if (FTC_Manager_New(library, 3, 0, 0, myFTC_Face_Requester, this, &cacheManager)) + { + printf(" manager failed!\n"); + return; + } + if (!cacheManager) + { + printf(" error.\n"); + return; + } + if (FTC_SBitCache_New(cacheManager, &sbitsCache)) + { + printf(" sbit failed!\n"); + return; + } + if (FTC_ImageCache_New(cacheManager, &imageCache)) + { + printf(" imagecache failed!\n"); + } + printf("\n"); +} + +FT_Error LcdFontRenderClass::FTC_Face_Requester(FTC_FaceID face_id, + FT_Face* aface) +{ + fontListEntry *font=(fontListEntry *)face_id; + if (!font) + return -1; + printf("[LCDFONT] FTC_Face_Requester (%s/%s)\n", font->family, font->style); + + int error; + if ((error=FT_New_Face(library, font->filename, 0, aface))) + { + printf(" failed: %i\n", error); + return error; + } + return 0; +} + +FTC_FaceID LcdFontRenderClass::getFaceID(const char *family, const char *style) +{ + for (fontListEntry *f=font; f; f=f->next) + { + if ((!strcmp(f->family, family)) && (!strcmp(f->style, style))) + return (FTC_FaceID)f; + } + return 0; +} + +FT_Error LcdFontRenderClass::getGlyphBitmap(FTC_ImageType font, FT_ULong glyph_index, FTC_SBit *sbit) +{ + return FTC_SBitCache_Lookup(sbitsCache, font, glyph_index, sbit, NULL); +} + +const char * LcdFontRenderClass::AddFont(const char * const filename) +{ + printf("[LCDFONT] adding font %s...", filename); + fflush(stdout); + int error; + fontListEntry *n=new fontListEntry; + + FT_Face face; + if ((error=FT_New_Face(library, filename, 0, &face))) + { + printf(" failed: %i\n", error); + delete n; + return NULL; + } + n->filename = strdup(filename); + n->family = strdup(face->family_name); + n->style = strdup(face->style_name); + FT_Done_Face(face); + + n->next=font; + printf("OK (%s/%s)\n", n->family, n->style); + font=n; + return n->style; +} + +LcdFontRenderClass::fontListEntry::~fontListEntry() +{ + free(filename); + free(family); + free(style); +} + +LcdFont *LcdFontRenderClass::getFont(const char *family, const char *style, int size) +{ + FTC_FaceID id=getFaceID(family, style); + if (!id) + return 0; + return new LcdFont(framebuffer, this, id, size); +} + +LcdFont::LcdFont(CLCDDisplay * fb, LcdFontRenderClass *render, FTC_FaceID faceid, int isize) +{ + framebuffer=fb; + renderer=render; + font.face_id=faceid; + font.width = isize; + font.height = isize; + font.flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_MONOCHROME; +} + +FT_Error LcdFont::getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit) +{ + return renderer->getGlyphBitmap(&font, glyph_index, sbit); +} + +void LcdFont::RenderString(int x, int y, const int width, const char * text, const int color, const int selected, const bool utf8_encoded) +{ + int err; + + FTC_ScalerRec scaler; + + scaler.face_id = font.face_id; + scaler.width = font.width; + scaler.height = font.height; + scaler.pixel = true; + + pthread_mutex_lock(&renderer->render_mutex); + + if ((err=FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size))!=0) + { + printf("FTC_Manager_Lookup_Size failed! (%d)\n",err); + pthread_mutex_unlock(&renderer->render_mutex); + return; + } + int left=x, step_y=(size->metrics.height >> 6 )*3/4 + 4; + + int pos =0; + for (; *text; text++) + { + pos++; + FTC_SBit glyph; + //if ((x + size->metrics.x_ppem > (left+width)) || (*text=='\n')) + if (x + size->metrics.x_ppem > (left+width)) + { //width clip + break; + } + if (*text=='\n') + { + x = left; + y += step_y; + } + + int unicode_value = UTF8ToUnicode(text, utf8_encoded); + + if (unicode_value == -1) + break; + + int index = FT_Get_Char_Index(size->face, unicode_value); + + if (!index) + continue; + if (getGlyphBitmap(index, &glyph)) + { + printf("failed to get glyph bitmap.\n"); + continue; + } + + int rx=x+glyph->left; + int ry=y-glyph->top; + if(pos==selected) + { + framebuffer->draw_fill_rect(x-2,y-glyph->height-2, x+glyph->width+2, y+2, CLCDDisplay::PIXEL_INV ); + } + + for (int ay=0; ayheight; ay++) + { + int ax=0; + int w=glyph->width; + int xpos = rx; + for (; axbuffer[ay*abs(glyph->pitch)+(ax>>3)]; + if((c>>(7-(ax&7)))&1) + framebuffer->draw_point(xpos,ry, color); + xpos ++; + } + ry++; + } + + x+=glyph->xadvance+1; + } + pthread_mutex_unlock(&renderer->render_mutex); +} + +int LcdFont::getRenderWidth(const char * text, const bool utf8_encoded) +{ + FTC_ScalerRec scaler; + + scaler.face_id = font.face_id; + scaler.width = font.width; + scaler.height = font.height; + scaler.pixel = true; + + pthread_mutex_lock(&renderer->render_mutex); + + if (FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size)<0) + { + printf("FTC_Manager_Lookup_Size failed!\n"); + pthread_mutex_unlock(&renderer->render_mutex); + return -1; + } + int x=0; + for (; *text; text++) + { + FTC_SBit glyph; + + int unicode_value = UTF8ToUnicode(text, utf8_encoded); + + if (unicode_value == -1) + break; + + int index=FT_Get_Char_Index(size->face, unicode_value); + + if (!index) + continue; + if (getGlyphBitmap(index, &glyph)) + { + printf("failed to get glyph bitmap.\n"); + continue; + } + + x+=glyph->xadvance+1; + } + pthread_mutex_unlock(&renderer->render_mutex); + return x; +} + diff --git a/src/driver/newclock.cpp b/src/driver/newclock.cpp new file mode 100644 index 000000000..a2b71d91b --- /dev/null +++ b/src/driver/newclock.cpp @@ -0,0 +1,222 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean', + 2003 thegoodguy + + 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. +*/ + + +#include +#include + +static bool time_digits[24*32 * 10]; +static bool days[24*16 * 7]; +static bool date_digits[16*16 * 10]; +static bool months[32*16 * 12]; + +static bool signs[] = {1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + + 1, 1, 1, 0, + 1, 1, 1, 0, + 0, 1, 1, 0, + 1, 1, 0, 0, + + 1, 1, 1, 0, + 1, 1, 1, 0, + 1, 1, 1, 0, + 0, 0, 0, 0}; + +void loadSkin(char * const filename, char * const backup_filename, const unsigned int modify_char_filename, const unsigned int modify_char_backup_filename, bool * const dest, const unsigned int count, const unsigned int width, const unsigned int height, const char * const name) +{ + FILE * fd; + int row, bit; + char * file; + unsigned int i ,byte, digit_pos; + unsigned char BMPWidth; + unsigned char BMPHeight; + char line_buffer[4]; + + file = filename; + digit_pos = modify_char_filename; + + for (i = 0; i < count; i++) + { + retry: + if ((fd = fopen(file, "rb")) == 0) + { + printf("[lcdd] %s-skin not found -> using default...\n", name); + file = backup_filename; + digit_pos = modify_char_backup_filename; + i = 0; + goto retry; + } + + fseek(fd, 0x12, SEEK_SET); + fread(&BMPWidth, 1, 1, fd); + fseek(fd, 0x16, SEEK_SET); + fread(&BMPHeight, 1, 1, fd); + + if ((BMPWidth > width) || (BMPHeight > height)) + { + printf("[lcdd] %s-skin not supported -> using default...\n", name); + fclose(fd); + file = backup_filename; + digit_pos = modify_char_backup_filename; + i = 0; + goto retry; + } + + fseek(fd, 0x3E, SEEK_SET); + + for (row = height - 1; row >= 0; row--) + { + fread(&line_buffer, 1, sizeof(line_buffer), fd); /* width must not be greater than 32 */ + + for (byte = 0; byte < (width >> 3); byte++) /* width must be multiple of 8 */ + { + for (bit = 7; bit >= 0; bit--) + { + dest[(7 - bit) + (byte << 3) + (row + i * height) * width] = line_buffer[byte] & (1 << bit); + } + } + } + + fclose(fd); + + file[digit_pos]++; + } +} + +void InitNewClock(void) +{ + char filename_usr[] = CONFIGDIR "/lcdd/clock/t_a.bmp"; + char filename_std[] = DATADIR "/lcdd/clock/t_a.bmp"; + + loadSkin(filename_usr, filename_std, sizeof(filename_usr) - 6, sizeof(filename_std) - 6, time_digits, 10, 24, 32, "time"); + + filename_usr[sizeof(filename_usr) - 8] = 'w'; + filename_std[sizeof(filename_std) - 8] = 'w'; + filename_usr[sizeof(filename_usr) - 6] = 'a'; + filename_std[sizeof(filename_std) - 6] = 'a'; + loadSkin(filename_usr, filename_std, sizeof(filename_usr) - 6, sizeof(filename_std) - 6, days, 7, 24, 16, "weekday"); + + filename_usr[sizeof(filename_usr) - 8] = 'd'; + filename_std[sizeof(filename_std) - 8] = 'd'; + filename_usr[sizeof(filename_usr) - 6] = 'a'; + filename_std[sizeof(filename_std) - 6] = 'a'; + loadSkin(filename_usr, filename_std, sizeof(filename_usr) - 6, sizeof(filename_std) - 6, date_digits, 10, 16, 16, "date"); + + filename_usr[sizeof(filename_usr) - 8] = 'm'; + filename_std[sizeof(filename_std) - 8] = 'm'; + filename_usr[sizeof(filename_usr) - 6] = 'a'; + filename_std[sizeof(filename_std) - 6] = 'a'; + loadSkin(filename_usr, filename_std, sizeof(filename_usr) - 6, sizeof(filename_std) - 6, months, 12, 32, 16, "month"); +} + +void RenderSign(CLCDDisplay* const display, int sign, int x_position, int y_position) +{ + int x, y; + + for(y = 0; y < 4; y++) + { + for(x = 0; x < 4; x++) + { + display->draw_point(x_position + x, y_position + y, signs[x + y*4 + sign*sizeof(signs)/3] ? CLCDDisplay::PIXEL_ON : CLCDDisplay::PIXEL_OFF); + } + } +} + +void RenderTimeDigit(CLCDDisplay* const display, int digit, int position) +{ + int x, y; + + for(y = 0; y < 32; y++) + { + for(x = 0; x < 24; x++) + { + display->draw_point(position + x, 5 + y, time_digits[x + y*24 + digit*sizeof(time_digits)/10] ? CLCDDisplay::PIXEL_ON : CLCDDisplay::PIXEL_OFF); + } + } +} + +void RenderDay(CLCDDisplay* const display, int day) +{ + int x, y; + + for(y = 0; y < 16; y++) + { + for(x = 0; x < 24; x++) + { + display->draw_point(5 + x, 43 + y, days[x + y*24 + day*sizeof(days)/7] ? CLCDDisplay::PIXEL_ON : CLCDDisplay::PIXEL_OFF); + } + } +} + +void RenderDateDigit(CLCDDisplay* const display, int digit, int position) +{ + int x, y; + + for(y = 0; y < 16; y++) + { + for(x = 0; x < 16; x++) + { + display->draw_point(position + x, 43 + y, date_digits[x + y*16 + digit*sizeof(date_digits)/10] ? CLCDDisplay::PIXEL_ON : CLCDDisplay::PIXEL_OFF); + } + } +} + +void RenderMonth(CLCDDisplay* const display, int month) +{ + int x, y; + + for(y = 0; y < 16; y++) + { + for(x = 0; x < 32; x++) + { + display->draw_point(83 + x, 43 + y, months[x + y*32 + month*sizeof(months)/12] ? CLCDDisplay::PIXEL_ON : CLCDDisplay::PIXEL_OFF); + } + } +} + +void ShowNewClock(CLCDDisplay* display, int hour, int minute, int second, int day, int date, int month) +{ + RenderTimeDigit(display, hour/10, 5); + RenderTimeDigit(display, hour%10, 32); + RenderTimeDigit(display, minute/10, 64); + RenderTimeDigit(display, minute%10, 91); + + RenderDay(display, day); + + RenderDateDigit(display, date/10, 43); + RenderDateDigit(display, date%10, 60); + + RenderMonth(display, month); + + RenderSign(display, 1, 31, 57); + RenderSign(display, 2, 78, 56); + + if (second % 2 == 0) + { + RenderSign(display, 0, 58, 15); + RenderSign(display, 0, 58, 23); + } +} diff --git a/src/driver/newclock.h b/src/driver/newclock.h new file mode 100644 index 000000000..07031fc44 --- /dev/null +++ b/src/driver/newclock.h @@ -0,0 +1,30 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + 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. +*/ + + +#include + +void InitNewClock(); +void ShowNewClock(CLCDDisplay* display, int hour, int minute, int second, int day, int date, int month); diff --git a/src/driver/stream2file.cpp b/src/driver/stream2file.cpp index d1e882b7f..53454cfc7 100644 --- a/src/driver/stream2file.cpp +++ b/src/driver/stream2file.cpp @@ -54,12 +54,13 @@ #include #include -#include #if HAVE_COOL_HARDWARE #include +#include #endif #if HAVE_TRIPLEDRAGON #include +#include #endif #include #include diff --git a/src/global.h b/src/global.h index 1fae8d900..5179fe1b3 100644 --- a/src/global.h +++ b/src/global.h @@ -40,8 +40,14 @@ #include "driver/fontrenderer.h" #include "driver/rcinput.h" +#if HAVE_COOL_HARDWARE #include "driver/vfd.h" #include "driver/rfmod.h" +#endif +#if HAVE_TRIPLEDRAGON +#include "driver/lcdd.h" +#define CVFD CLCD +#endif #include "system/localize.h" #include "system/settings.h" @@ -85,8 +91,10 @@ NEUTRINO_CPP CEpgData *g_EpgData; NEUTRINO_CPP CInfoViewer *g_InfoViewer; NEUTRINO_CPP EventList *g_EventList; -NEUTRINO_CPP CLocaleManager *g_Locale; +NEUTRINO_CPP CLocaleManager *g_Locale; +#if HAVE_COOL_HARDWARE NEUTRINO_CPP RFmod *g_RFmod; +#endif NEUTRINO_CPP CVideoSettings *g_videoSettings; diff --git a/src/lcddisplay/Makefile.am b/src/lcddisplay/Makefile.am new file mode 100644 index 000000000..b21bf8cbf --- /dev/null +++ b/src/lcddisplay/Makefile.am @@ -0,0 +1,7 @@ +noinst_LIBRARIES = liblcddisplay.a + +liblcddisplay_a_SOURCES = lcddisplay.cpp fontrenderer.cpp + +AM_CXXFLAGS = \ + @FREETYPE_CFLAGS@ \ + @PNG_CFLAGS@ diff --git a/src/lcddisplay/fontrenderer.cpp b/src/lcddisplay/fontrenderer.cpp new file mode 100644 index 000000000..7d3880dd3 --- /dev/null +++ b/src/lcddisplay/fontrenderer.cpp @@ -0,0 +1,387 @@ +/* + $Header$ + + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Copyright (C) 2003 thegoodguy + baseroutines by tmbinc + + + 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. +*/ + +#include + +#include "fontrenderer.h" + +#include +#include + +#include +#include FT_FREETYPE_H + +/* tested with freetype 2.3.9, and 2.1.4 */ +#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 3 +#define FT_NEW_CACHE_API +#endif + +FT_Error LcdFontRenderClass::myFTC_Face_Requester(FTC_FaceID face_id, + FT_Library library, + FT_Pointer request_data, + FT_Face* aface) +{ + return ((LcdFontRenderClass*)request_data)->FTC_Face_Requester(face_id, aface); +} + + +LcdFontRenderClass::LcdFontRenderClass(CLCDDisplay * fb) +{ + framebuffer = fb; + printf("[LCDFONT] initializing core..."); + fflush(stdout); + if (FT_Init_FreeType(&library)) + { + printf("failed.\n"); + return; + } + printf("\n"); + font=0; + pthread_mutex_init(&render_mutex, NULL); +} + +LcdFontRenderClass::~LcdFontRenderClass() +{ + FTC_Manager_Done(cacheManager); + FT_Done_FreeType(library); +} + +void LcdFontRenderClass::InitFontCache() +{ + printf("[LCDFONT] Intializing font cache..."); + fflush(stdout); + if (FTC_Manager_New(library, 3, 0, 0, myFTC_Face_Requester, this, &cacheManager)) + { + printf(" manager failed!\n"); + return; + } + if (!cacheManager) + { + printf(" error.\n"); + return; + } + if (FTC_SBitCache_New(cacheManager, &sbitsCache)) + { + printf(" sbit failed!\n"); + return; + } + if (FTC_ImageCache_New(cacheManager, &imageCache)) + { + printf(" imagecache failed!\n"); + } + printf("\n"); +} + +FT_Error LcdFontRenderClass::FTC_Face_Requester(FTC_FaceID face_id, + FT_Face* aface) +{ + fontListEntry *font=(fontListEntry *)face_id; + if (!font) + return -1; + printf("[LCDFONT] FTC_Face_Requester (%s/%s)\n", font->family, font->style); + + int error; + if ((error=FT_New_Face(library, font->filename, 0, aface))) + { + printf(" failed: %i\n", error); + return error; + } + return 0; +} + +FTC_FaceID LcdFontRenderClass::getFaceID(const char *family, const char *style) +{ + for (fontListEntry *f=font; f; f=f->next) + { + if ((!strcmp(f->family, family)) && (!strcmp(f->style, style))) + return (FTC_FaceID)f; + } + for (fontListEntry *f=font; f; f=f->next) + { + if (!strcmp(f->family, family)) + return (FTC_FaceID)f; + } + return 0; +} + +#ifdef FT_NEW_CACHE_API +FT_Error LcdFontRenderClass::getGlyphBitmap(FTC_ImageType font, FT_ULong glyph_index, FTC_SBit *sbit) +{ + return FTC_SBitCache_Lookup(sbitsCache, font, glyph_index, sbit, NULL); +} +#else +FT_Error LcdFontRenderClass::getGlyphBitmap(FTC_Image_Desc *font, FT_ULong glyph_index, FTC_SBit *sbit) +{ + return FTC_SBit_Cache_Lookup(sbitsCache, font, glyph_index, sbit); +} +#endif + +const char * LcdFontRenderClass::AddFont(const char * const filename) +{ + printf("[LCDFONT] adding font %s...", filename); + fflush(stdout); + int error; + fontListEntry *n=new fontListEntry; + + FT_Face face; + if ((error=FT_New_Face(library, filename, 0, &face))) + { + printf(" failed: %i\n", error); + delete n; + return NULL; + } + n->filename = strdup(filename); + n->family = strdup(face->family_name); + n->style = strdup(face->style_name); + FT_Done_Face(face); + + n->next=font; + printf("OK (%s/%s)\n", n->family, n->style); + font=n; + return n->style; +} + +LcdFontRenderClass::fontListEntry::~fontListEntry() +{ + free(filename); + free(family); + free(style); +} + +LcdFont *LcdFontRenderClass::getFont(const char *family, const char *style, int size) +{ + FTC_FaceID id=getFaceID(family, style); + if (!id) + return 0; + return new LcdFont(framebuffer, this, id, size); +} + +LcdFont::LcdFont(CLCDDisplay * fb, LcdFontRenderClass *render, FTC_FaceID faceid, int isize) +{ + framebuffer=fb; + renderer=render; +#ifdef FT_NEW_CACHE_API + font.face_id=faceid; + font.width = isize; + font.height = isize; + font.flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_MONOCHROME; +#else + font.font.face_id=faceid; + font.font.pix_width = isize; + font.font.pix_height = isize; + font.image_type = ftc_image_mono; + font.image_type |= ftc_image_flag_autohinted; +#endif +} + +FT_Error LcdFont::getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit) +{ + return renderer->getGlyphBitmap(&font, glyph_index, sbit); +} + +int UTF8ToUnicode(const char * &text, const bool utf8_encoded) // returns -1 on error +{ + int unicode_value; + + if (utf8_encoded && ((((unsigned char)(*text)) & 0x80) != 0)) + { + int remaining_unicode_length; + if ((((unsigned char)(*text)) & 0xf8) == 0xf0) + { + unicode_value = ((unsigned char)(*text)) & 0x07; + remaining_unicode_length = 3; + } + else if ((((unsigned char)(*text)) & 0xf0) == 0xe0) + { + unicode_value = ((unsigned char)(*text)) & 0x0f; + remaining_unicode_length = 2; + } + else if ((((unsigned char)(*text)) & 0xe0) == 0xc0) + { + unicode_value = ((unsigned char)(*text)) & 0x1f; + remaining_unicode_length = 1; + } + else // cf.: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return -1; // corrupted character or a character with > 4 bytes utf-8 representation + + for (int i = 0; i < remaining_unicode_length; i++) + { + text++; + if (((*text) & 0xc0) != 0x80) + { + remaining_unicode_length = -1; + return -1; // incomplete or corrupted character + } + unicode_value <<= 6; + unicode_value |= ((unsigned char)(*text)) & 0x3f; + } + if (remaining_unicode_length == -1) + return -1; // incomplete or corrupted character + } + else + unicode_value = (unsigned char)(*text); + + return unicode_value; +} + +void LcdFont::RenderString(int x, int y, const int width, const char * text, const int color, const int selected, const bool utf8_encoded) +{ + int err; + pthread_mutex_lock(&renderer->render_mutex); + +#ifdef FT_NEW_CACHE_API + FTC_ScalerRec scaler; + + scaler.face_id = font.face_id; + scaler.width = font.width; + scaler.height = font.height; + scaler.pixel = true; + + if ((err = FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size)) != 0) +#else + if ((err=FTC_Manager_Lookup_Size(renderer->cacheManager, &font.font, &face, &size))!=0) +#endif + { + printf("FTC_Manager_Lookup_Size failed! (%d)\n",err); + pthread_mutex_unlock(&renderer->render_mutex); + return; + } + int left=x, step_y=(size->metrics.height >> 6 )*3/4 + 4; + + int pos =0; + for (; *text; text++) + { + pos++; + FTC_SBit glyph; + //if ((x + size->metrics.x_ppem > (left+width)) || (*text=='\n')) + if (x + size->metrics.x_ppem > (left+width)) + { //width clip + break; + } + if (*text=='\n') + { + x = left; + y += step_y; + } + + int unicode_value = UTF8ToUnicode(text, utf8_encoded); + + if (unicode_value == -1) + break; + +#ifdef FT_NEW_CACHE_API + int index = FT_Get_Char_Index(size->face, unicode_value); +#else + int index = FT_Get_Char_Index(face, unicode_value); +#endif + + if (!index) + continue; + if (getGlyphBitmap(index, &glyph)) + { + printf("failed to get glyph bitmap.\n"); + continue; + } + + int rx=x+glyph->left; + int ry=y-glyph->top; + if(pos==selected) + { + framebuffer->draw_fill_rect(x-2,y-glyph->height-2, x+glyph->width+2, y+2, CLCDDisplay::PIXEL_INV ); + } + + for (int ay=0; ayheight; ay++) + { + int ax=0; + int w=glyph->width; + int xpos = rx; + for (; axbuffer[ay*abs(glyph->pitch)+(ax>>3)]; + if((c>>(7-(ax&7)))&1) + framebuffer->draw_point(xpos,ry, color); + xpos ++; + } + ry++; + } + + x+=glyph->xadvance+1; + } + pthread_mutex_unlock(&renderer->render_mutex); +} + +int LcdFont::getRenderWidth(const char * text, const bool utf8_encoded) +{ + pthread_mutex_lock(&renderer->render_mutex); + FT_Error err; +#ifdef FT_NEW_CACHE_API + FTC_ScalerRec scaler; + scaler.face_id = font.face_id; + scaler.width = font.width; + scaler.height = font.height; + scaler.pixel = true; + + err = FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size); +#else + err = FTC_Manager_Lookup_Size(renderer->cacheManager, &font.font, &face, &size); +#endif + if (err != 0) + { + printf("FTC_Manager_Lookup_Size failed! (0x%x)\n", err); + pthread_mutex_unlock(&renderer->render_mutex); + return -1; + } + int x=0; + for (; *text; text++) + { + FTC_SBit glyph; + + int unicode_value = UTF8ToUnicode(text, utf8_encoded); + + if (unicode_value == -1) + break; + +#ifdef FT_NEW_CACHE_API + int index = FT_Get_Char_Index(size->face, unicode_value); +#else + int index=FT_Get_Char_Index(face, unicode_value); +#endif + + if (!index) + continue; + if (getGlyphBitmap(index, &glyph)) + { + printf("failed to get glyph bitmap.\n"); + continue; + } + + x+=glyph->xadvance+1; + } + pthread_mutex_unlock(&renderer->render_mutex); + return x; +} + diff --git a/src/lcddisplay/fontrenderer.h b/src/lcddisplay/fontrenderer.h new file mode 100644 index 000000000..805149c1c --- /dev/null +++ b/src/lcddisplay/fontrenderer.h @@ -0,0 +1,115 @@ +/* + $Header$ + + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + baseroutines by tmbinc + Homepage: http://dbox.cyberphoria.org/ + + + + 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. +*/ + +#ifndef __LCDFONTRENDERER__ +#define __LCDFONTRENDERER__ + +#include "lcddisplay.h" + +#include +#include FT_FREETYPE_H +#include FT_CACHE_H +#include FT_CACHE_IMAGE_H +#include FT_CACHE_SMALL_BITMAPS_H + +#include + + + +class LcdFontRenderClass; +class LcdFont +{ + CLCDDisplay *framebuffer; +#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 3 + FTC_ImageTypeRec font; +#else + FTC_Image_Desc font; + FT_Face face; +#endif + LcdFontRenderClass *renderer; + FT_Size size; + + FT_Error getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit); + + public: + void RenderString(int x, int y, int width, const char *text, int color, int selected=0, const bool utf8_encoded = false); + + int getRenderWidth(const char *text, const bool utf8_encoded = false); + + LcdFont(CLCDDisplay *fb, LcdFontRenderClass *render, FTC_FaceID faceid, int isize); + ~LcdFont(){} +}; + + +class LcdFontRenderClass +{ + CLCDDisplay *framebuffer; + + struct fontListEntry + { + char *filename, *style, *family; + fontListEntry *next; + ~fontListEntry(); + } *font; + + FT_Library library; + FTC_Manager cacheManager; /* the cache manager */ + FTC_ImageCache imageCache; /* the glyph image cache */ + FTC_SBitCache sbitsCache; /* the glyph small bitmaps cache */ + + FTC_FaceID getFaceID(const char *family, const char *style); +#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 3 + FT_Error getGlyphBitmap(FTC_ImageType font, FT_ULong glyph_index, FTC_SBit *sbit); +#else + FT_Error getGlyphBitmap(FTC_Image_Desc *font, FT_ULong glyph_index, FTC_SBit *sbit); +#endif + + public: + pthread_mutex_t render_mutex; + const char * AddFont(const char * const filename); + void InitFontCache(); + + FT_Error FTC_Face_Requester(FTC_FaceID face_id, + FT_Face* aface); + + + static FT_Error myFTC_Face_Requester(FTC_FaceID face_id, + FT_Library library, + FT_Pointer request_data, + FT_Face* aface); + + //FT_Face getFace(const char *family, const char *style); + LcdFont *getFont(const char *family, const char *style, int size); + LcdFontRenderClass(CLCDDisplay *fb); + ~LcdFontRenderClass(); + + + friend class LcdFont; +}; + +#endif /* __LCDFONTRENDERER__ */ diff --git a/src/lcddisplay/lcddisplay.cpp b/src/lcddisplay/lcddisplay.cpp new file mode 100644 index 000000000..6d31cf27c --- /dev/null +++ b/src/lcddisplay/lcddisplay.cpp @@ -0,0 +1,501 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + baseroutines by Shadow_ + Homepage: http://dbox.cyberphoria.org/ + + + + 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. +*/ + +#include +#include "lcddisplay.h" + +#include + +#include /* uint8_t */ +#include +#include +#include +#include +#include +#include +#include + + +CLCDDisplay::CLCDDisplay() +{ + paused=0; + available = false; +#ifndef HAVE_GENERIC_HARDWARE + //open device + if ((fd = open(LCD_DEVICE, O_RDWR)) < 0) + { + perror("LCD (" LCD_DEVICE ")"); + return; + } + + //clear the display + if ( ioctl(fd,LCD_IOCTL_CLEAR) < 0) + { + perror("clear failed"); + return; + } + + //graphic (binary) mode +#ifdef HAVE_TRIPLEDRAGON + if (ioctl(fd, IOC_LCD_WRMODE, LCD_MODE_BIN) < 0) +#else + int i=LCD_MODE_BIN; + if ( ioctl(fd,LCD_IOCTL_ASC_MODE,&i) < 0 ) +#endif + { + perror("graphic mode failed"); + return; + } + + available = true; +#endif + iconBasePath = ""; +} + +bool CLCDDisplay::isAvailable() +{ + return available; +} + +CLCDDisplay::~CLCDDisplay() +{ + close(fd); +} + +void CLCDDisplay::pause() +{ + paused = 1; +} + +void CLCDDisplay::resume() +{ +#ifndef HAVE_GENERIC_HARDWARE + //clear the display + if ( ioctl(fd,LCD_IOCTL_CLEAR) < 0) + { + perror("clear failed"); + return; + } + + //graphic (binary) mode +#ifdef HAVE_TRIPLEDRAGON + if (ioctl(fd, IOC_LCD_WRMODE, LCD_MODE_BIN) < 0) +#else + int i=LCD_MODE_BIN; + if ( ioctl(fd,LCD_IOCTL_ASC_MODE,&i) < 0 ) +#endif + { + perror("graphic mode failed"); + return; + } +#endif + paused = 0; +} + +#ifdef HAVE_TRIPLEDRAGON +void CLCDDisplay::convert_data() +{ + int x, y, xx, xp, yp; + unsigned char pix, bit; + + /* 128x64 (8bpp) membuffer -> 16*64 (1bpp) lcdbuffer */ + /* TODO: extend skins to 128x64 */ + + /* the strange offset handling comes from a bug (probably) in the + TD LCD driver: the MSB (0x80) of the first byte (lcd[0]) written to + the device actually appears on the lower right, 8 pixels up, so we + must shift the whole buffer one pixel to the right. This is wrong for + the column 127 (rightmost), which is shifted up 8 lines. + */ + for (y = 0; y < LCD_LINES; y++) { + for (x = 0; x < LCD_STRIDE; x++) { + pix = 0; + bit = 0x80; + + for (xx = x * 8; xx < x * 8 + 8; xx++, bit >>= 1) { + xp = xx - 1; /* shift the whole buffer one pixel to the right */ + yp = y; + if (xp < 0) { /* rightmost column (column 127) */ + xp += LCD_COLS; /* wraparound */ + yp -= 8; /* shift down 8 lines */ + if (yp < 0) /* wraparound */ + yp += LCD_LINES; + } + if (raw[yp][xp] == 1) + pix |= bit; + } +/* I was chasing this one for quite some time, so check it for now */ +#if 1 + if (y * LCD_STRIDE + x > LCD_BUFFER_SIZE) + fprintf(stderr, "%s: y (%d) * LCD_STRIDE (%d) + x (%d) (== %d) > LCD_BUFFER_SIZE (%d)\n", + __FUNCTION__, y, LCD_STRIDE, x, y*LCD_STRIDE+x, LCD_BUFFER_SIZE); + else +#endif + lcd[y * LCD_STRIDE + x] = pix; + } + } + +#if 0 +/* alternative solution, just ignore the rightmost column (which would be the + MSB of the first byte */ + for (y=0; y<64; y++){ + for (x=0; x<(128/8); x++){ + int pix=0, start = 0; + unsigned char bit = 0x80; + int offset=(y*128)+x*8; + if (x == 0) { /* first column, skip MSB */ + start = 1; + bit = 0x40; + } else + offset--; + for (yy=start; yy<8; yy++, bit >>=1) { + pix|=(_buffer[offset++]>=108)?bit:0; + } + raw[y*16+x]=pix; + } + } +#endif +} +#else +void CLCDDisplay::convert_data () +{ +#ifndef HAVE_GENERIC_HARDWARE + unsigned int x, y, z; + char tmp; + + for (x = 0; x < LCD_COLS; x++) + { + for (y = 0; y < LCD_ROWS; y++) + { + tmp = 0; + + for (z = 0; z < 8; z++) + if (raw[y * 8 + z][x] == 1) + tmp |= (1 << z); + + lcd[y][x] = tmp; + } + } +#endif +} +#endif + +void CLCDDisplay::update() +{ +#ifndef HAVE_GENERIC_HARDWARE + convert_data(); + if(paused || !available) + return; + else + if ( write(fd, lcd, LCD_BUFFER_SIZE) < 0) { + perror("lcdd: CLCDDisplay::update(): write()"); + } +#endif +} + +void CLCDDisplay::draw_point(const int x, const int y, const int state) +{ + if ((x < 0) || (x >= LCD_COLS) || (y < 0) || (y >= (LCD_ROWS * 8))) + return; + + if (state == LCD_PIXEL_INV) + raw[y][x] ^= 1; + else + raw[y][x] = state; +} + + +/* + * draw_line + * + * args: + * x1 StartCol + * y1 StartRow + * x2 EndCol + * y1 EndRow + * state LCD_PIXEL_OFF/LCD_PIXEL_ON/LCD_PIXEL_INV + * + */ +void CLCDDisplay::draw_line(const int x1, const int y1, const int x2, const int y2, const int state) +{ + int dx = abs (x1 - x2); + int dy = abs (y1 - y2); + int x; + int y; + int End; + int step; + + if ( dx > dy ) + { + int p = 2 * dy - dx; + int twoDy = 2 * dy; + int twoDyDx = 2 * (dy-dx); + + if ( x1 > x2 ) + { + x = x2; + y = y2; + End = x1; + step = y1 < y2 ? -1 : 1; + } + else + { + x = x1; + y = y1; + End = x2; + step = y2 < y1 ? -1 : 1; + } + + draw_point(x, y, state); + + while( x < End ) + { + x++; + if ( p < 0 ) + p += twoDy; + else + { + y += step; + p += twoDyDx; + } + draw_point(x, y, state); + } + } + else + { + int p = 2 * dx - dy; + int twoDx = 2 * dx; + int twoDxDy = 2 * (dx-dy); + + if ( y1 > y2 ) + { + x = x2; + y = y2; + End = y1; + step = x1 < x2 ? -1 : 1; + } + else + { + x = x1; + y = y1; + End = y2; + step = x2 < x1 ? -1 : 1; + } + + draw_point(x, y, state); + + while( y < End ) + { + y++; + if ( p < 0 ) + p += twoDx; + else + { + x += step; + p += twoDxDy; + } + draw_point(x, y, state); + } + } +} + + +void CLCDDisplay::draw_fill_rect (int left,int top,int right,int bottom,int state) { + int x,y; + for(x = left + 1;x < right;x++) { + for(y = top + 1;y < bottom;y++) { + draw_point(x,y,state); + } + } +} + + +void CLCDDisplay::draw_rectangle (int left,int top, int right, int bottom, int linestate,int fillstate) +{ + // coordinate checking in draw_pixel (-> you can draw lines only + // partly on screen) + + draw_line(left,top,right,top,linestate); + draw_line(left,top,left,bottom,linestate); + draw_line(right,top,right,bottom,linestate); + draw_line(left,bottom,right,bottom,linestate); + draw_fill_rect(left,top,right,bottom,fillstate); +} + + +void CLCDDisplay::draw_polygon(int num_vertices, int *vertices, int state) +{ + + // coordinate checking in draw_pixel (-> you can draw polygons only + // partly on screen) + + int i; + for(i=0;i> 1; + height = (header.height_hi << 8) | header.height_lo; + + unsigned char pixbuf[200]; + while (height-- > 0) + { + read(fd, &pixbuf, stride); + pixpos = (unsigned char*) &pixbuf; + for (int count2 = 0; count2 < stride; count2++) + { + unsigned char compressed = *pixpos; + + draw_point(x + (count2 << 1) , y, ((((compressed & 0xf0) >> 4) != header.transp) ^ invert) ? PIXEL_ON : PIXEL_OFF); + draw_point(x + (count2 << 1) + 1, y, (( (compressed & 0x0f) != header.transp) ^ invert) ? PIXEL_ON : PIXEL_OFF); + + pixpos++; + } + y++; + } + + close(_fd); + return true; +} + +void CLCDDisplay::dump_screen(raw_display_t *screen) { + memcpy(screen, raw, sizeof(raw_display_t)); +} + +void CLCDDisplay::load_screen(const raw_display_t * const screen) { + memcpy(raw, screen, sizeof(raw_display_t)); +} + +bool CLCDDisplay::load_png(const char * const filename) +{ + png_structp png_ptr; + png_infop info_ptr; + unsigned int i; + unsigned int pass; + unsigned int number_passes; + int bit_depth; + int color_type; + int interlace_type; + png_uint_32 width; + png_uint_32 height; + png_byte * fbptr; + FILE * fh; + bool ret_value = false; + + if ((fh = fopen(filename, "rb"))) + { + if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) + { + if (!(info_ptr = png_create_info_struct(png_ptr))) + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + else + { + if (!(setjmp(png_ptr->jmpbuf))) + { + png_init_io(png_ptr,fh); + + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); + + if ( + (color_type == PNG_COLOR_TYPE_PALETTE) && + (bit_depth == 1 ) && + (width <= LCD_COLS ) && + (height == (LCD_ROWS * 8)) + ) + { + png_set_packing(png_ptr); /* expand to 1 byte blocks */ + + number_passes = png_set_interlace_handling(png_ptr); + png_read_update_info(png_ptr,info_ptr); + + if (width == png_get_rowbytes(png_ptr, info_ptr)) + { + ret_value = true; + + for (pass = 0; pass < number_passes; pass++) + { + fbptr = (png_byte *)raw; + for (i = 0; i < height; i++, fbptr += LCD_COLS) + { + png_read_row(png_ptr, fbptr, NULL); + /* if the PNG is smaller, than the display width... */ + if (width < LCD_COLS) /* clear the area right of the PNG */ + memset(fbptr + width, 0, LCD_COLS - width); + } + } + png_read_end(png_ptr, info_ptr); + } + } + } + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + } + } + fclose(fh); + } + return ret_value; +} diff --git a/src/lcddisplay/lcddisplay.h b/src/lcddisplay/lcddisplay.h index 1904076c8..6585c9713 100644 --- a/src/lcddisplay/lcddisplay.h +++ b/src/lcddisplay/lcddisplay.h @@ -26,7 +26,38 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifdef HAVE_GENERIC_HARDWARE +// dummy +#define LCD_ROWS 8 +#define LCD_COLS 120 +#define LCD_PIXEL_OFF 0 +#define LCD_PIXEL_ON 1 +#define LCD_PIXEL_INV 2 + +#else +#ifndef HAVE_TRIPLEDRAGON +/* dreambox is actually compatible to dbox2 wrt. lcd */ #include +#define LCD_DEVICE "/dev/dbox/lcd0" +#else +#include +#include +#define LCD_LINES 64 +#define LCD_ROWS (LCD_LINES / 8) // compatibility with stupid DBOX LCD driver +#define LCD_COLS 128 +#define LCD_STRIDE (LCD_COLS / 8) +#define LCD_BUFFER_SIZE (LCD_LINES * LCD_STRIDE) +#define LCD_PIXEL_OFF 0 +#define LCD_PIXEL_ON 1 +#define LCD_PIXEL_INV 2 +#define LCD_DEVICE "/dev/" DEVICE_NAME_LCD +#define LCD_MODE_ASC 0 +#define LCD_MODE_BIN 2 +// ioctls +#define LCD_IOCTL_ASC_MODE IOC_LCD_WRMODE +#define LCD_IOCTL_CLEAR IOC_LCD_CLEAR +#endif +#endif #include @@ -36,7 +67,11 @@ class CLCDDisplay { private: raw_display_t raw; +#ifdef HAVE_TRIPLEDRAGON + unsigned char lcd[LCD_BUFFER_SIZE]; +#else unsigned char lcd[LCD_ROWS][LCD_COLS]; +#endif int fd, paused; std::string iconBasePath; bool available; diff --git a/src/neutrino.cpp b/src/neutrino.cpp index 6306d4dfe..d05e6cf6a 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -68,7 +68,10 @@ #include #include #include - +#if HAVE_TRIPLEDRAGON +#include +#include "gui/widget/lcdcontroler.h" +#endif #include #include @@ -77,8 +80,10 @@ #include "gui/widget/messagebox.h" #include "gui/widget/hintbox.h" #include "gui/widget/icons.h" +#if HAVE_COOL_HARDWARE #include "gui/widget/vfdcontroler.h" #include "gui/widget/progressbar.h" +#endif #include "gui/widget/keychooser.h" #include "gui/widget/stringinput.h" #include "gui/widget/stringinput_ext.h" @@ -349,7 +354,7 @@ typedef struct lcd_setting_t const unsigned int default_value; } lcd_setting_struct_t; -const lcd_setting_struct_t lcd_setting[LCD_SETTING_COUNT] = +const lcd_setting_struct_t lcd_setting[SNeutrinoSettings::LCD_SETTING_COUNT] = { {"lcd_brightness" , DEFAULT_VFD_BRIGHTNESS }, {"lcd_standbybrightness", DEFAULT_VFD_STANDBYBRIGHTNESS}, @@ -359,6 +364,9 @@ const lcd_setting_struct_t lcd_setting[LCD_SETTING_COUNT] = {"lcd_show_volume" , DEFAULT_LCD_SHOW_VOLUME }, {"lcd_autodimm" , DEFAULT_LCD_AUTODIMM }, {"lcd_deepbrightness" , DEFAULT_VFD_STANDBYBRIGHTNESS } +#if HAVE_TRIPLEDRAGON + ,{ "lcd_epgmode" , 0 /*DEFAULT_LCD_EPGMODE*/ } +#endif }; /************************************************************************************** @@ -771,7 +779,7 @@ printf("***************************** rec dir %s timeshift dir %s\n", g_settings for (int i = 0; i < TIMING_SETTING_COUNT; i++) g_settings.timing[i] = configfile.getInt32(locale_real_names[timing_setting_name[i]], default_timing[i]); - for (int i = 0; i < LCD_SETTING_COUNT; i++) + for (int i = 0; i < SNeutrinoSettings::LCD_SETTING_COUNT; i++) g_settings.lcd_setting[i] = configfile.getInt32(lcd_setting[i].name, lcd_setting[i].default_value); strcpy(g_settings.lcd_setting_dim_time, configfile.getString("lcd_dim_time","0").c_str()); strcpy(g_settings.lcd_setting_dim_brightness, configfile.getString("lcd_dim_brightness","0").c_str()); @@ -1283,7 +1291,7 @@ void CNeutrinoApp::saveSetup(const char * fname) for (int i = 0; i < TIMING_SETTING_COUNT; i++) configfile.setInt32(locale_real_names[timing_setting_name[i]], g_settings.timing[i]); - for (int i = 0; i < LCD_SETTING_COUNT; i++) + for (int i = 0; i < SNeutrinoSettings::LCD_SETTING_COUNT; i++) configfile.setInt32(lcd_setting[i].name, g_settings.lcd_setting[i]); configfile.setString("lcd_dim_time", g_settings.lcd_setting_dim_time); configfile.setString("lcd_dim_brightness", g_settings.lcd_setting_dim_brightness); @@ -4572,7 +4580,7 @@ void CNeutrinoApp::loadColors(const char * fname) g_settings.infobar_Text_red = tconfig.getInt32( "infobar_Text_red", 0x64 ); g_settings.infobar_Text_green = tconfig.getInt32( "infobar_Text_green", 0x64 ); g_settings.infobar_Text_blue = tconfig.getInt32( "infobar_Text_blue", 0x64 ); - for (int i = 0; i < LCD_SETTING_COUNT; i++) + for (int i = 0; i < SNeutrinoSettings::LCD_SETTING_COUNT; i++) g_settings.lcd_setting[i] = tconfig.getInt32(lcd_setting[i].name, lcd_setting[i].default_value); strcpy(g_settings.lcd_setting_dim_time, tconfig.getString("lcd_dim_time","0").c_str()); strcpy(g_settings.lcd_setting_dim_brightness, tconfig.getString("lcd_dim_brightness","0").c_str()); @@ -4638,7 +4646,7 @@ void CNeutrinoApp::saveColors(const char * fname) tconfig.setInt32( "infobar_Text_red", g_settings.infobar_Text_red ); tconfig.setInt32( "infobar_Text_green", g_settings.infobar_Text_green ); tconfig.setInt32( "infobar_Text_blue", g_settings.infobar_Text_blue ); - for (int i = 0; i < LCD_SETTING_COUNT; i++) + for (int i = 0; i < SNeutrinoSettings::LCD_SETTING_COUNT; i++) tconfig.setInt32(lcd_setting[i].name, g_settings.lcd_setting[i]); tconfig.setString("lcd_dim_time", g_settings.lcd_setting_dim_time); tconfig.setString("lcd_dim_brightness", g_settings.lcd_setting_dim_brightness); diff --git a/src/system/settings.h b/src/system/settings.h index efe1e3be6..a2639efc2 100644 --- a/src/system/settings.h +++ b/src/system/settings.h @@ -384,16 +384,19 @@ struct SNeutrinoSettings }; // lcdd -#define LCD_SETTING_COUNT 8 enum LCD_SETTINGS { LCD_BRIGHTNESS = 0, - LCD_STANDBY_BRIGHTNESS = 1, - LCD_CONTRAST = 2, - LCD_POWER = 3, - LCD_INVERSE = 4, - LCD_SHOW_VOLUME = 5, - LCD_AUTODIMM = 6, - LCD_DEEPSTANDBY_BRIGHTNESS = 7 + LCD_STANDBY_BRIGHTNESS , + LCD_CONTRAST , + LCD_POWER , + LCD_INVERSE , + LCD_SHOW_VOLUME , + LCD_AUTODIMM , + LCD_DEEPSTANDBY_BRIGHTNESS, +#if HAVE_TRIPLEDRAGON + LCD_EPGMODE , +#endif + LCD_SETTING_COUNT }; int lcd_setting[LCD_SETTING_COUNT];