diff -Nru graphlcd-base-0.2.0+git20101020/99-graphlcd-base.rules graphlcd-base-0.1.9+git20120310/99-graphlcd-base.rules --- graphlcd-base-0.2.0+git20101020/99-graphlcd-base.rules 1970-01-01 00:00:00.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/99-graphlcd-base.rules 2012-03-10 09:18:56.000000000 +0000 @@ -0,0 +1,8 @@ +# +# all displays / modules supported by graphlcd-base +# +# Futaba DM140-GINK VFD displays, incl. activity 5xx +ATTRS{idVendor}=="040b", ATTRS{idProduct}=="7001", GROUP="uucp", MODE="0660" +ATTRS{idVendor}=="1509", ATTRS{idProduct}=="925d", GROUP="uucp", MODE="0660" +# AX206DPF-based picture frames (modified firmware) +ATTRS{idVendor}=="1908", ATTRS{idProduct}=="0102", GROUP="uucp", MODE="0660" diff -Nru graphlcd-base-0.2.0+git20101020/debian/changelog graphlcd-base-0.1.9+git20120310/debian/changelog --- graphlcd-base-0.2.0+git20101020/debian/changelog 2012-03-29 21:49:36.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/debian/changelog 2012-03-29 21:49:37.000000000 +0000 @@ -1,41 +1,73 @@ -graphlcd-base (0.2.0+git20101020-0yavdr1) lucid; urgency=low +graphlcd-base (0.1.9+git20120310-0yavdr0~lucid) lucid; urgency=high - * New upstream snapshot + * Rebuild for yaVDR 0.3.3 - -- Holger Schvestka Wed, 20 Oct 2010 07:17:02 +0200 + -- Frank Neumann Thu, 29 Mar 2012 23:36:36 +0200 -graphlcd-base (0.2.0+git20100518-2yavdr1) lucid; urgency=low +graphlcd-base (0.1.9+git20120310-0yavdr0~natty) natty; urgency=medium - * New upstream snapshot - * added new libglcdskin1-dev + libglcd1 + * New Upstream Snaphot + * Added libmagick-dev build-dep and usage of LIBMAGICK - -- Holger Schvestka Tue, 18 May 2010 21:59:29 +0200 + -- Reiner Paulus Sat, 10 Mar 2012 11:33:57 +0100 -graphlcd-base (0.2.0-pre1-2gda+hotzenplotz5+2) karmic; urgency=low +graphlcd-base (0.1.9+git20111129-0yavdr0~natty) natty; urgency=medium - * -fPIC for C++ + * New Upstream Snaphot - -- Gerald Dachs Sun, 18 Oct 2009 19:41:31 +0200 + -- Reiner Paulus Tue, 29 Nov 2011 09:12:00 +0100 -graphlcd-base (0.2.0-pre1-2gda+hotzenplotz5+1) karmic; urgency=low +graphlcd-base (0.1.9+git20111024-0yavdr0~natty) natty; urgency=medium - * Added 05_gcc-44.dpatch to fix gcc 4.4.x issue - * Added 06_glcdskin.dpatch - * removed installation of genfont + * New Upstream Snaphot + * added libmagick-dev build-dep - -- Gerald Dachs Sun, 18 Oct 2009 12:19:49 +0200 + -- Holger Schvestka Mon, 24 Oct 2011 20:08:15 +0200 -graphlcd-base (0.2.0-pre1-1ubuntu1) karmic; urgency=low +graphlcd-base (0.1.9+git20110829-1yavdr1~natty) natty; urgency=medium - * New upstream release + * New upstream snapshot (touchcol branch) + * removed ax206 udev file, now provided upstream + + -- Gerald Dachs Mon, 29 Aug 2011 11:02:52 +0200 + +graphlcd-base (0.1.9+git20110825-1yavdr2~natty) natty; urgency=medium + + * changed group in ax206 udev rule + + -- Gerald Dachs Fri, 26 Aug 2011 13:52:09 +0200 + +graphlcd-base (0.1.9+git20110825-1yavdr1~natty) natty; urgency=medium + + * New upstream snapshot (touchcol branch) + + -- Gerald Dachs Thu, 25 Aug 2011 13:16:42 +0200 - -- Holger Schvestka Tue, 13 Oct 2009 14:25:51 +0200 +graphlcd-base (0.1.9+git20110812-1yavdr2~natty) natty; urgency=medium -graphlcd-base (0.1.5-5ubuntu1) karmic; urgency=low + * cleaned up package (thanks to Keine_Ahnung) - * Ubuntu Karmic + -- Gerald Dachs Thu, 25 Aug 2011 11:56:18 +0200 + +graphlcd-base (0.1.9+git20110812-1yavdr1~natty) natty; urgency=low + + * New upstream snapshot (touchcol branch) + * added udev rule for ax206dpf + + -- Gerald Dachs Fri, 12 Aug 2011 09:04:14 +0200 + +graphlcd-base (0.1.9+git20110811-1yavdr1~natty) natty; urgency=low + + * New upstream snapshot (touchcol branch) + * activated ax206dpf + + -- Gerald Dachs Thu, 11 Aug 2011 09:38:39 +0200 + +graphlcd-base (0.1.9+git20110424-1yavdr1~natty) natty; urgency=low + + * New upstream snapshot - -- Holger Schvestka Thu, 08 Oct 2009 20:25:29 +0200 + -- Holger Schvestka Sun, 24 Apr 2011 07:17:02 +0200 graphlcd-base (0.1.5-5) unstable; urgency=low diff -Nru graphlcd-base-0.2.0+git20101020/debian/compat graphlcd-base-0.1.9+git20120310/debian/compat --- graphlcd-base-0.2.0+git20101020/debian/compat 2012-03-29 21:49:36.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/debian/compat 2012-03-29 21:49:37.000000000 +0000 @@ -1 +1 @@ -4 +7 diff -Nru graphlcd-base-0.2.0+git20101020/debian/control graphlcd-base-0.1.9+git20120310/debian/control --- graphlcd-base-0.2.0+git20101020/debian/control 2012-03-29 21:49:36.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/debian/control 2012-03-29 21:49:37.000000000 +0000 @@ -1,13 +1,13 @@ Source: graphlcd-base Priority: optional Maintainer: Tobias Grimm -Build-Depends: debhelper (>= 7), dpatch, libfreetype6-dev -Standards-Version: 3.8.3 +Build-Depends: debhelper (>= 7), libfreetype6-dev, pkg-config, libusb-dev, libmagick9-dev | libmagick-dev |libmagickwand-dev, libmagick++-dev +Standards-Version: 3.9.1 Section: libs Package: libglcddrivers1-dev Provides: libglcddrivers-dev -Conflicts: libglcddrivers-dev, libglcddrivers1 (< 0.2.0) +Conflicts: libglcddrivers-dev, libglcddrivers1 (<< 0.1.9) Section: libdevel Architecture: any Depends: libglcddrivers1 (= ${Source-Version}) @@ -29,7 +29,7 @@ Package: libglcdgraphics2-dev Provides: libglcdgraphics-dev -Conflicts: libglcdgraphics-dev, libglcdgraphics2 (< 0.2.0) +Conflicts: libglcdgraphics-dev, libglcdgraphics2 (<< 0.1.9) Section: libdevel Architecture: any Depends: libglcdgraphics2 (= ${Source-Version}) @@ -62,8 +62,9 @@ Package: libglcdskin1 Section: libs Architecture: any -Depends: libglcdskin1-dev -Description: Development files for the GraphLCD graphics library - The GraphLCD graphics library +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Library for handling skins with GraphLCD + The GraphLCD graphics library provides methods for processing skins + to be displayed with the GraphLCD drivers library. diff -Nru graphlcd-base-0.2.0+git20101020/debian/libglcddrivers1.install graphlcd-base-0.1.9+git20120310/debian/libglcddrivers1.install --- graphlcd-base-0.2.0+git20101020/debian/libglcddrivers1.install 2012-03-29 21:49:36.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/debian/libglcddrivers1.install 2012-03-29 21:49:37.000000000 +0000 @@ -1,3 +1,4 @@ debian/tmp/usr/lib/libglcddrivers.so.* graphlcd.conf etc/ +99-graphlcd-base.rules lib/udev/rules.d diff -Nru graphlcd-base-0.2.0+git20101020/debian/rules graphlcd-base-0.1.9+git20120310/debian/rules --- graphlcd-base-0.2.0+git20101020/debian/rules 2012-03-29 21:49:36.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/debian/rules 2012-03-29 21:49:37.000000000 +0000 @@ -26,7 +26,7 @@ dh_testdir # Add here commands to compile the package. - $(MAKE) + $(MAKE) HAVE_AX206DPF_EXPERIMENTAL=1 touch build-stamp @@ -37,7 +37,7 @@ rm -f build-stamp configure-stamp # Add here commands to clean up after the build process. - -$(MAKE) clean + -$(MAKE) HAVE_AX206DPF_EXPERIMENTAL=1 clean dh_clean diff -Nru graphlcd-base-0.2.0+git20101020/docs/DRIVER.ax206dpf graphlcd-base-0.1.9+git20120310/docs/DRIVER.ax206dpf --- graphlcd-base-0.2.0+git20101020/docs/DRIVER.ax206dpf 1970-01-01 00:00:00.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/docs/DRIVER.ax206dpf 2012-03-10 09:18:56.000000000 +0000 @@ -0,0 +1,160 @@ +--------------------------------------------------------------------- +GraphLCD driver library + +The AX 206 digital photoframe driver +--------------------------------------------------------------------- + +Description +----------- +The ax206dpf driver supports AX 206 based DPFs. +For more information about these DPFs see: +http://tech.section5.ch/news/?p=68 + +The driver was tested with this display: +http://www.pearl.de/a-PX1184-5618.shtml or http://www.pearl.de/a-HPM1184-5618.shtml + +Important Notes +--------------- +This driver is experimental and not enabled by default. +To use this driver uncomment the HAVE_AX206DPF_EXPERIMENTAL line in +Make.config and recompile the library. +The DPF does not work out of the box with this driver. +It has to be modified with a custom firmware (see "Hacking your DPF"). +If your DPF is already hacked, there is no need to install the "dpf-ax" package +described in "Hacking your DPF". All necessary routines to access a hacked +DPF are included in this driver. + +Multi-display setups +-------------------- +This driver supports up to 4 displays. The displays can be aligned horizontal, +vertical or tiled (See "Example multi-display setups"). + +Hot plugging +------------ +Hot plugging of displays is supported. The driver will add/remove displays automatically +as they are plugged in or removed. For multi-display setups the scan for new displays will +continue until all needed displays are detected. + +Non-root users +-------------- +The driver needs write access to the USB port of the display module. +If the enclosed udev-rules file '99-graphlcd-base.rules' is installed, add +the user(s) that should be authorised to use the display to the group 'uucp'. + +If the enclosed udev-rule will not be used a custom rule needs to be provided if +other users than root are to be authorised: + +ATTRS{idVendor}=="1908", ATTRS{idProduct}=="0102", GROUP="", MODE="0660" +Replace through a unix group of your desire. + + +Configuration Parameters +------------------------ +The driver supports the following parameters in config file: + +Device + Selects a specific display. + 'dpf0' = first detected display, 'dpf1' = second detected display, ... + Default value: 'dpf0' + +Width + Sets the horizontal size of the display. If this parameter is not + given, a default value according to the selected DPF is used. + Default value: 320 or 240 (see 'Portrait') + +Height + Sets the vertical size of the display. If this parameter is not + given, a default value according to the selected DPF is used. + Default value: 240 or 320 (see 'Portrait') + +UpsideDown + Rotates the display output by 180 degrees. This might be useful, if + the display is mounted upside-down. + Possible values: 'yes', 'no' + Default value: 'no' + +Brightness + Sets the brightness of the display's backlight. + Possible values: 0 <= x <= 100) + Default value: 100 + +Portrait + Select portrait or landscape mode. + Rotate display output by 90 degrees if necessary. + Possible values: 'yes' -> default size = 240 x 320 + 'no' -> default size = 320 x 240 + Default value: 'no' + +Zoom + Determines if pixels should be magnified. + Possible values: 1, 2, 3, 4 + Default value: 1 + +The following parameters are for multi-display setups only (see "Example multi-display setups"). + +Horizontal +Sets the number of displays in horizontal direction. + Possible values if Vertical=1: 1, 2, 3, 4 + if Vertical=2: 1, 2 + Default value: 1 + +Vertical + Sets the number of displays in vertical direction. + Possible values if Horizontal=1: 1, 2, 3, 4 + if Horizontal=2: 1, 2 + Default value: 1 + +Flip + Rotates a single displays output by 180 degrees. This might be useful, if + some displays are mounted upside-down. + Possible values for every display : 'y', 'n' + Default value: 'nnnn' + + +Example multi-display setups +---------------------------- +'#' = position of USB-connector + +Portrait=y Portrait=n Portrait=n Portrait=n +Horizontal=2 Horizontal=2 Horizontal=1 Horizontal=2 +Vertical=1 Vertical=1 Vertical=3 Vertical=2 +Flip=nn Flip=ny Flip=nyn Flip=nyny + ++-+ +-+ +---+ +---+ +---+ +---+ +---+ +| | | | # +---+ +---+# #+---+ #+---+ +---+# ++-+ +-+ 1 2 1 1 2 + # # +---+ +---+ +---+ + 1 2 +---+# #+---+ +---+# + 2 3 4 + +---+ + #+---+ + 3 + +Hacking your DPF +---------------- +For hacking your DPF you need this dpf-ax package: +http://tech.section5.ch/files/dpfhack-0.12devel.tgz + +First of all, let me quote this from the dpf-ax README ((c) 4/2011, hackfin): +[quote] +Also note: NO SUPPORT! NO WARRANTY! FRIENDS DON'T MAKE FRIENDS HACK THEIR +DPF! LET ALONE NON-FRIENDS! (Bottomline: Don't ask me if I can hack your DPF). + +If you wish to hack your DPF, please check the sites listed below. +. +. +Find updates and documentation here: + +http://tech.section5.ch/news/?p=68 +or here: +http://picframe.spritesserver.nl/wiki/index.php/DPF_with_AppoTech_AX206 +For our german users, a very good explanation is found here: +http://geekparadise.de/2011/04/digitaler-bilderrahmen-von-pearl-als-statusdisplay-fur-dockstar/ +[/quote] + +So if you are not sure if you have the right DPF or something goes wrong: +don't ask me either - I'm like you only a user and not involved in the +development of the hack! + +A guide how to hack the Pearl display can be found here (in german): +http://www.vdr-portal.de/board1-news/board2-vdr-news/p1015287-announce-graphlcd-base-vdr-plugin-touchcol-branch/#post1015287 diff -Nru graphlcd-base-0.2.0+git20101020/docs/DRIVER.futabaMDM166A graphlcd-base-0.1.9+git20120310/docs/DRIVER.futabaMDM166A --- graphlcd-base-0.2.0+git20101020/docs/DRIVER.futabaMDM166A 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/docs/DRIVER.futabaMDM166A 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ ---------------------------------------------------------------------- -GraphLCD driver library - -The futabaMDM166A driver ---------------------------------------------------------------------- - -Description ------------ -The Futaba MDM166A driver supports Futaba MDM166A VFD displays. -The VFD is connected to a PC's USB port. - -Installation Notes ------------------- - -You need installed library libhid to use the futabaMDM166A driver. -This library libhid is used to access and interact with a USB HID device. - - * http://libhid.alioth.debian.org/ - -If Debian used, you can install them with the command : - -#> apt-get install libhid-dev libhid0 - -Wirings -------- -The futabaMDM166A driver supports a connections on a USB port. - - -Configuration Parameters ------------------------- -The futabaMDM166A driver supports the following parameters in config file: - -Width - Sets the horizontal size of the display. If this parameter is not - given, a default value of 96 pixels is used. - -Height - Sets the vertical size of the display. If this parameter is not - given, a default value of 16 pixels is used. - -UpsideDown - Rotates the display output by 180 degrees. This might be useful, if - the LCD is mounted upside-down. - Possible values: 'yes', 'no' - Default value: 'no' - -Invert - Inverts the display. - Possible values: 'yes', 'no' - Default value: 'no' - -Brightness - Sets the brightness of your display's backlight. - Possible values: 0 <= x <= 100) - Default value: 50 - -RefreshDisplay - Normally, most of the drivers do not update the whole display, but - only the areas that have changed since last update. So it might be, - that some faulty pixels would stay a longer time. To avoid this, the - plugin makes a complete refresh from time to time. This parameter - defines how often a complete refresh will be done. - e.g.: A value of 5 means, that the plugin will make a complete - refresh on every 5th update. - A value of 0 completely disables complete refreshs. - Possible values: 0 <= x <= 50 - Default value: 50 - - diff -Nru graphlcd-base-0.2.0+git20101020/docs/DRIVER.noritake800 graphlcd-base-0.1.9+git20120310/docs/DRIVER.noritake800 --- graphlcd-base-0.2.0+git20101020/docs/DRIVER.noritake800 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/docs/DRIVER.noritake800 2012-03-10 09:18:56.000000000 +0000 @@ -93,7 +93,7 @@ Possible values: 0 <= x <= 100) Default value: 100 -AdjustTiming ---> not used in this driver (if there are problems, please report) +AdjustTiming To get a timing that is as accurate as possible, the drivers measure the time for port commands (see: benchmark in syslog). You might decrease or increase the time to wait after port commands with this @@ -101,7 +101,7 @@ Possible values: -50 <= x <= 50 Default value: 0 -RefreshDisplay ---> not used in this driver (if there are problems, please report) +RefreshDisplay Normally, most of the drivers do not update the whole display, but only the areas that have changed since last update. So it might be, that some faulty pixels would stay a longer time. To avoid this, the diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/avrctl.c graphlcd-base-0.1.9+git20120310/glcddrivers/avrctl.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/avrctl.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/avrctl.c 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2005 Andreas Regel + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #include @@ -50,10 +51,8 @@ cDriverAvrCtl::cDriverAvrCtl(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); - port = new cSerialPort(); //width = config->width; @@ -64,7 +63,6 @@ cDriverAvrCtl::~cDriverAvrCtl() { delete port; - delete oldConfig; } int cDriverAvrCtl::Init() @@ -176,6 +174,27 @@ memset(newLCD[x], 0, (kBufferHeight + 7) / 8); } + +void cDriverAvrCtl::SetPixel(int x, int y, uint32_t data) +{ + if (x >= width || y >= height) + return; + + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + } + + int offset = 7 - (y % 8); + if (data == GRAPHLCD_White) + newLCD[x][y / 8] |= (1 << offset); + else + newLCD[x][y / 8] &= ( 0xFF ^ (1 << offset) ); +} + + +#if 0 void cDriverAvrCtl::Set8Pixels(int x, int y, unsigned char data) { if (x >= width || y >= height) @@ -200,6 +219,7 @@ } } } +#endif void cDriverAvrCtl::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/avrctl.h graphlcd-base-0.1.9+git20120310/glcddrivers/avrctl.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/avrctl.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/avrctl.h 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2005 Andreas Regel + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_AVRCTL_H_ @@ -26,8 +27,6 @@ cSerialPort * port; unsigned char ** newLCD; // wanted state unsigned char ** oldLCD; // current state - cDriverConfig * config; - cDriverConfig * oldConfig; int refreshCounter; int WaitForAck(void); @@ -48,7 +47,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); virtual void SetBrightness(unsigned int percent); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/ax206dpf.c graphlcd-base-0.1.9+git20120310/glcddrivers/ax206dpf.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/ax206dpf.c 1970-01-01 00:00:00.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/ax206dpf.c 2012-03-10 09:18:56.000000000 +0000 @@ -0,0 +1,992 @@ +/* + * GraphLCD driver library + * + * ax206dpf.h - AX206dpf driver class + * Output goes to AX 206 based photoframe + * + * based on: + * simlcd device + * (c) 2001-2004 Carsten Siebholz + * (c) 2011 Dirk Heiser + * (c) 2011 Wolfgang Astleitner + * + * includes code from: + * http://sourceforge.net/projects/dpf-ax/ + * + * Original copyright: + * + * Copyright (C) 2008 Jeroen Domburg + * Modified from sample code by: + * Copyright (C) 2005 Michael Reinelt + * Copyright (C) 2005, 2006, 2007 The LCD4Linux Team + * Mods by + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2011 Lutz Neumann + * + * HISTORY + * + * v0.1 - 10 Aug 2011 - Inital release + * v0.2 - 20 Aug 2011 - Optimized display data transfer + * SetBrightness() implemented + * Multi-display support + * v0.3 - 02 Sep 2011 - Fixed multi-thread problem + * + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "config.h" + +#include "ax206dpf.h" + + +namespace GLCD +{ + +static pthread_mutex_t libax_mutex; + + +cDriverAX206DPF::cDriverAX206DPF(cDriverConfig * config) +: cDriver(config) +{ +} + +int cDriverAX206DPF::Init(void) +{ + zoom = 1; + portrait = false; + numxdisplays = numydisplays = 1; + sizex = sizey = bpp = 0; + + for (unsigned int i = 0; i < MAX_DPFS; i++) + { + dh[i] = (DISPLAYHANDLE *) malloc(sizeof(DISPLAYHANDLE)); + dh[i]->attached = false; + dh[i]->address[0] = 0; + dh[i]->dpfh = NULL; + dh[i]->LCD = NULL; + } + + lastbrightness = config->brightness ? config->brightness : 100; + + for (unsigned int i = 0; i < config->options.size(); i++) + { + if (config->options[i].name == "Portrait") { + portrait = config->options[i].value == "yes"; + } + else if (config->options[i].name == "Zoom") { + int z = strtol(config->options[i].value.c_str(), (char **) NULL, 0); + if (z > 0 && z <= 4) + zoom = z; + else + syslog(LOG_ERR, "%s error: zoom %d not supported, using default (%d)!\n",config->name.c_str(), z, zoom); + } + else if (config->options[i].name == "Horizontal") { + int h = strtol(config->options[i].value.c_str(), (char **) NULL, 0); + if (h > 0 && h <= 4) + numxdisplays = h; + else + syslog(LOG_ERR, "%s error: Horizontal=%d not supported, using default (%d)!\n",config->name.c_str(), h, numxdisplays); + } + else if (config->options[i].name == "Vertical") { + int v = strtol(config->options[i].value.c_str(), (char **) NULL, 0); + if (v > 0 && v <= 4) + numydisplays = v; + else + syslog(LOG_ERR, "%s error: Vertical=%d not supported, using default (%d)!\n",config->name.c_str(), v, numydisplays); + } + else if (config->options[i].name == "Flip") { + flips = config->options[i].value; + for (unsigned int j = 0; j < flips.size(); j++) + { + if (flips[j] != 'y' && flips[j] != 'n') + { + syslog(LOG_ERR, "%s error: flips=%s - illegal character, only 'y' and 'n' supported, using default!\n",config->name.c_str(), flips.c_str()); + flips = ""; + break; + } + } + } + } + + // See if we have too many displays + if (numxdisplays * numydisplays > MAX_DPFS) + syslog(LOG_ERR, "%s: too many displays (%dx%d). Max is %d!\n",config->name.c_str(), numxdisplays, numydisplays, MAX_DPFS); + + // Init all displays + numdisplays = 0; + int error = 0; + for (unsigned int i = 0; i < numxdisplays * numydisplays; i++) + { + error = InitSingleDisplay(i); + if (error < 0) + return -1; + numdisplays++; + } + + if (sizex == 0) + { + // no displays detected + sizex = (portrait) ? DEFAULT_HEIGHT : DEFAULT_WIDTH; + sizey = (portrait) ? DEFAULT_WIDTH : DEFAULT_HEIGHT; + bpp = DEFAULT_BPP; + } + + // setup temp transfer LCD array + tempLCD = (unsigned char *) malloc(sizex * sizey * bpp); + + width = sizex * numxdisplays; + height = sizey * numydisplays; + + if (zoom > 1) + { + height /= zoom; + width /= zoom; + } + + ResetMinMax(); + + *oldConfig = *config; + + if (numdisplays == 1) + syslog(LOG_INFO, "%s: AX206DPF initialized (%dx%d).\n", config->name.c_str(), width, height); + else + { + unsigned n = 0; + for (unsigned int i = 0; i < numdisplays; i++) + if (dh[i]->attached) n++; + syslog(LOG_INFO, "%s: using %d display(s) (%d online, %d offline).\n", config->name.c_str(), numdisplays, n, numdisplays - n); + } + + lastscan = time(NULL); + + return 0; +} + +bool cDriverAX206DPF::RescanUSB() +{ + bool ret = false; + usb_find_busses(); + if (usb_find_devices() > 0) + { + unsigned int a = 0, b = 0; + for (unsigned int i = 0; i < numdisplays; i++) + { + if (dh[i]->attached) a |= 0x01 << i; + DeInitSingleDisplay(i); + } + for (unsigned int i = 0; i < numdisplays; i++) + { + InitSingleDisplay(i); + if (dh[i]->attached) b |= 0x01 << i; + } + ret = a != b; + } + return ret; +} + +int cDriverAX206DPF::InitSingleDisplay(unsigned int di) +{ + char index; + + if (config->device.length() != 4 || config->device.compare(0, 3, "dpf")) + index = '0'; + else + index = config->device.at(3); + + char device[5]; + sprintf(device, "usb%c", index + di); + int error = dpf_open(device, &dh[di]->dpfh); + if (error < 0) + { + dh[di]->dpfh = NULL; + dh[di]->attached = false; + return 0; + } + dh[di]->attached = true; + struct usb_device *dev = usb_device(dh[di]->dpfh->dev.udev); + char *s1 = dev->bus->dirname; + char *s2 = dev->filename; + if (strlen(s1) > 3) s1 = (char *) "???"; + if (strlen(s2) > 3) s2 = (char *) "???"; + sprintf(dh[di]->address, "%s:%s", s1, s2); + + // See, if we have to rotate the display + dh[di]->isPortrait = dh[di]->dpfh->width < dh[di]->dpfh->height; + dh[di]->rotate90 = dh[di]->isPortrait != portrait; + dh[di]->flip = (!dh[di]->isPortrait && dh[di]->rotate90); // adjust to make rotate por/land = physical por/land + if (flips.size() >= di + 1 && flips[di] == 'y') + dh[di]->flip = !dh[di]->flip; + + if (sizex == 0) + { + // this is the first display found + // Get width / height from this display (all displays have same geometry) + sizex = ((!dh[di]->rotate90) ? dh[di]->dpfh->width : dh[di]->dpfh->height); + sizey = ((!dh[di]->rotate90) ? dh[di]->dpfh->height : dh[di]->dpfh->width); + bpp = dh[di]->dpfh->bpp; + } + else + { + // make sure alle displays have the same geometry + if ((!(sizex == dh[di]->dpfh->width && sizey == dh[di]->dpfh->height) && + !(sizex == dh[di]->dpfh->height && sizey == dh[di]->dpfh->width)) || + bpp != (unsigned int) dh[di]->dpfh->bpp) + { + syslog(LOG_INFO, "%s: all displays must have same geometry. Display %d has not. Giving up.\n", config->name.c_str(), di); + return -1; + } + } + // setup physical lcd arrays + dh[di]->LCD = (unsigned char *) malloc(dh[di]->dpfh->height * dh[di]->dpfh->width * dh[di]->dpfh->bpp); + ClearSingleDisplay(di); + + // Set Display Brightness + SetSingleDisplayBrightness(di, lastbrightness); + + + // Reorder displays + bool changed = false; + for (unsigned int i = 0; i < MAX_DPFS - 1; i++) + { + for (unsigned int j = i + 1; j < MAX_DPFS; j++) + { + if (strcmp(dh[i]->address, dh[j]->address) < 0) + { + DISPLAYHANDLE *h = dh[i]; + dh[i] = dh[j]; + dh[j] = h; + changed = true; + } + } + } + + //for (unsigned int i = 0; i < MAX_DPFS; i++) + // fprintf(stderr, "Display %d at %s\n", i, (dh[i]->attached) ? dh[i]->address : "-none-"); + //fprintf(stderr, "\n"); + + //fprintf(stderr, "Display %d at %s attached.\n", di, dh[di]->address); + //syslog(LOG_INFO, "%s: display %d at %s attached\n", config->name.c_str(), di, dh[di]->address); + + return 0; +} + +void cDriverAX206DPF::DeInitSingleDisplay(unsigned int di) +{ + if (dh[di]->dpfh != NULL) + dpf_close(dh[di]->dpfh); + dh[di]->dpfh = NULL; + + if (dh[di]->LCD != NULL) + free(dh[di]->LCD); + dh[di]->LCD = NULL; + + dh[di]->attached = false; + dh[di]->address[0] = 0; +} + +int cDriverAX206DPF::DeInit(void) +{ + // close displays & free lcd arrays + for (unsigned int i = 0; i< numdisplays; i++) + DeInitSingleDisplay(i); + + if (tempLCD) + free(tempLCD); + + return 0; +} + + +void cDriverAX206DPF::ResetMinMax(void) +{ + for (unsigned int i = 0; i < numydisplays; i++) + { + if (dh[i]->attached) + { + dh[i]->minx = dh[i]->dpfh->width - 1; + dh[i]->maxx = 0; + dh[i]->miny = dh[i]->dpfh->height - 1; + dh[i]->maxy = 0; + } + } +} + +int cDriverAX206DPF::CheckSetup(void) +{ + if (config->width != oldConfig->width || + config->height != oldConfig->height) + { + DeInit(); + Init(); + return 0; + } + + if (config->brightness != oldConfig->brightness) + { + oldConfig->brightness = config->brightness; + SetBrightness(config->brightness); + } + + if (config->upsideDown != oldConfig->upsideDown || + config->invert != oldConfig->invert) + { + oldConfig->upsideDown = config->upsideDown; + oldConfig->invert = config->invert; + return 1; + } + return 0; +} + +void cDriverAX206DPF::ClearSingleDisplay(unsigned int di) +{ + if (dh[di]->attached) + { + memset(dh[di]->LCD, 0, dh[di]->dpfh->width * dh[di]->dpfh->height * dh[di]->dpfh->bpp); //Black + dh[di]->minx = 0; + dh[di]->maxx = dh[di]->dpfh->width - 1; + dh[di]->miny = 0; + dh[di]->maxy = dh[di]->dpfh->height - 1; + } +} + +void cDriverAX206DPF::Clear(void) +{ + for (unsigned int i = 0; i < numdisplays; i++) + ClearSingleDisplay(i); +} + +#define _RGB565_0(p) \ + (( ((p >> 16) & 0xf8) ) | (((p >> 8) & 0xe0) >> 5)) +#define _RGB565_1(p) \ + (( ((p >> 8) & 0x1c) << 3 ) | (((p) & 0xf8) >> 3)) + +void cDriverAX206DPF::SetPixel(int x, int y, uint32_t data) +{ + bool changed = false; + + if (config->upsideDown) + { + // global upside down orientation + x = width - 1 - x; + y = height - 1 -y; + } + + int sx = sizex / zoom; + int sy = sizey / zoom; + int di = (y / sy) * numxdisplays + (x / sx); + int lx = (x % sx) * zoom; + int ly = (y % sy) * zoom; + + if (!dh[di]->attached) + return; + + if (dh[di]->flip) + { + // local upside down orientation + lx = sizex - 1 - lx; + ly = sizey - 1 - ly; + } + + if (dh[di]->rotate90) + { + // wrong Orientation, rotate + int i = ly; + ly = (dh[di]->dpfh->height) - 1 - lx; + lx = i; + } + + if (lx < 0 || lx >= (int) dh[di]->dpfh->width || ly < 0 || ly >= (int) dh[di]->dpfh->height) + { + syslog(LOG_INFO, "x/y out of bounds (x=%d, y=%d, di=%d, rot=%d, flip=%d, lx=%d, ly=%d)\n", x, y, di, dh[di]->rotate90, dh[di]->flip, lx, ly); + return; + } + + unsigned char c1 = _RGB565_0(data); + unsigned char c2 = _RGB565_1(data); + + if (zoom == 1) + { + unsigned int i = (ly * dh[di]->dpfh->width + lx) * dh[di]->dpfh->bpp; + if (dh[di]->LCD[i] != c1 || dh[di]->LCD[i+1] != c2) + { + dh[di]->LCD[i] = c1; + dh[di]->LCD[i+1] = c2; + changed = true; + } + } + else + { + for (int dy = 0; dy < zoom; dy++) + { + unsigned int i = ((ly + dy) * dh[di]->dpfh->width + lx) * dh[di]->dpfh->bpp; + for (int dx = 0; dx < zoom * dh[di]->dpfh->bpp; dx += dh[di]->dpfh->bpp) + { + if (dh[di]->LCD[i+dx] != c1 || dh[di]->LCD[i+dx+1] != c2) + { + dh[di]->LCD[i+dx] = c1; + dh[di]->LCD[i+dx+1] = c2; + changed = true; + } + } + } + } + + if (changed) + { + if (lx < dh[di]->minx) dh[di]->minx = lx; + if (lx > dh[di]->maxx) dh[di]->maxx = lx; + if (ly < dh[di]->miny) dh[di]->miny = ly; + if (ly > dh[di]->maxy) dh[di]->maxy = ly; + } +} + +void cDriverAX206DPF::Refresh(bool refreshAll) +{ + short rect[4]; + + if (CheckSetup() > 0) + refreshAll = true; + + for (unsigned int di = 0; di < numdisplays; di++) + { + if (!dh[di]->attached) + { + time_t current = time(NULL); + if (current - lastscan >= USB_SCAN_INTERVALL) + { + lastscan = current; + if (RescanUSB()) + ; //return; // something changed, wait for next refresh + } + } + + if (!dh[di]->attached) + continue; + + if (refreshAll) + { + dh[di]->minx = 0; dh[di]->miny = 0; + dh[di]->maxx = dh[di]->dpfh->width - 1; dh[di]->maxy = dh[di]->dpfh->height - 1; + } + //fprintf(stderr, "%d: (%d,%d)-(%d,%d) ", di, dh[di]->minx, dh[di]->miny, dh[di]->maxx, dh[di]->maxy); + if (dh[di]->minx > dh[di]->maxx || dh[di]->miny > dh[di]->maxy) + continue; + + unsigned int cpylength = (dh[di]->maxx - dh[di]->minx + 1) * dh[di]->dpfh->bpp; + unsigned char *ps = dh[di]->LCD + (dh[di]->miny * dh[di]->dpfh->width + dh[di]->minx) * dh[di]->dpfh->bpp; + unsigned char *pd = tempLCD; + for (int y = dh[di]->miny; y <= dh[di]->maxy; y++) + { + memcpy(pd, ps, cpylength); + ps += dh[di]->dpfh->width * dh[di]->dpfh->bpp; + pd += cpylength; + } + + rect[0] = dh[di]->minx; rect[1] = dh[di]->miny; rect[2] = dh[di]->maxx + 1; rect[3] = dh[di]->maxy + 1; + pthread_mutex_lock(&libax_mutex); + int err = dpf_screen_blit(dh[di]->dpfh, tempLCD, rect); + pthread_mutex_unlock(&libax_mutex); + if (err < 0) + { + //fprintf(stderr, "Display %d detached (err=%d).\n", di, err); + syslog(LOG_INFO, "%s: display %d communication error (%d). Display detached\n", config->name.c_str(), di, err); + DeInitSingleDisplay(di); + RescanUSB(); + lastscan = time(NULL); + } + } + + ResetMinMax(); + //fprintf(stderr, "\n"); +} + +uint32_t cDriverAX206DPF::GetBackgroundColor(void) +{ + return GRAPHLCD_Black; +} + +void cDriverAX206DPF::SetSingleDisplayBrightness(unsigned int di, unsigned int percent) +{ + if (!dh[di]->attached) + return; + + LIBDPF::DPFValue val; + val.type = LIBDPF::TYPE_INTEGER; + + // Brightness can be 0 .. 7 + if (percent == 0) + val.value.integer = 0; + else if (percent >= 100) + val.value.integer = 7; + else + val.value.integer = (((percent * 10) + 167) * 6) / 1000; + pthread_mutex_lock(&libax_mutex); + dpf_setproperty(dh[di]->dpfh, PROPERTY_BRIGHTNESS, &val); + pthread_mutex_unlock(&libax_mutex); +} + +void cDriverAX206DPF::SetBrightness(unsigned int percent) +{ + lastbrightness = percent; + + for (unsigned int i = 0; i < numdisplays; i++) + { + SetSingleDisplayBrightness(i, percent); + } +} + +bool cDriverAX206DPF::GetDriverFeature(const std::string & Feature, int & value) +{ + if (strcasecmp(Feature.c_str(), "depth") == 0) { + value = 16; + return true; + } else if (strcasecmp(Feature.c_str(), "ismonochrome") == 0) { + value = false; + return true; + } else if (strcasecmp(Feature.c_str(), "isgreyscale") == 0 || strcasecmp(Feature.c_str(), "isgrayscale") == 0) { + value = false; + return true; + } else if (strcasecmp(Feature.c_str(), "iscolour") == 0 || strcasecmp(Feature.c_str(), "iscolor") == 0) { + value = true; + return true; + } else if (strcasecmp(Feature.c_str(), "touch") == 0 || strcasecmp(Feature.c_str(), "touchscreen") == 0) { + value = false; + return true; + } + value = 0; + return false; +} + +} // end of namespace GLCD + +//########################################################################################## +// +// ** START OF UGLY HACK ** START OF UGLY HACK ** START OF UGLY HACK ** START OF UGLY HACK * +// +// Because I choose NOT to include the static library libdpf.a and/or their header- and +// source-files from the original dpf-ax hack, I did some creative copy & paste from there +// to this place. I will delete this stuff when a usable shared library of libpdf exists. +// +//########################################################################################## + +namespace LIBDPF +{ +// ------------------------------------------------------------------- +// START SELECTIVE COPY & PASTE "dpflib.c" +// ------------------------------------------------------------------- +/** DPF access library for AX206 based HW + * + * 12/2010 + * + * This is an ugly hack, because we use existing SCSI vendor specific + * extensions to pass on our requests to the DPF. + * + * One day we might use a proper protocol like netpp. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/** Vendor command for our hacks */ +static +unsigned char g_excmd[16] = { + 0xcd, 0, 0, 0, + 0, 6, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +int wrap_scsi(DPFContext *h, unsigned char *cmd, int cmdlen, char out, + unsigned char *data, unsigned long block_len) +{ + int error; + //if (h->mode == MODE_USB) { + error = emulate_scsi(h->dev.udev, cmd, cmdlen, out, data, block_len); + //} else { + // error = do_scsi(h->dev.fd, cmd, cmdlen, out, data, block_len); + //} + return error; +} + +static +int probe(DPFHANDLE h) +{ + int ret; + + // We abuse a command that just responds with a '0' status in the + // original firmware. + static unsigned char buf[5]; + + + static + unsigned char cmd[16] = { + 0xcd, 0, 0, 0, + 0, 3, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + }; + + cmd[5] = 3; + ret = wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, 0, 0); + + switch (ret) { + case 0: + // The original protocol. + fprintf(stderr, + "Warning: This firmware can not lock the flash\n"); + break; + case 1: + // The improved hack + h->flags |= FLAG_CAN_LOCK; + break; + } + + cmd[5] = 2; // get LCD parameters + ret = wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, buf, 5); + h->width = (buf[0]) | (buf[1] << 8); + h->height = (buf[2]) | (buf[3] << 8); + h->bpp = 2; + + return ret; +} + + +int dpf_open(const char *dev, DPFHANDLE *h) +{ + int error = 0; + DPFContext *dpf; + int i; + usb_dev_handle *u; + + //int fd; + + if (!dev) { + fprintf(stderr, "Please specify a string like 'usb0' or a sg device\n"); + return DEVERR_OPEN; + } + + if (strncmp(dev, "usb", 3) == 0) { + i = dev[3] - '0'; + u = dpf_usb_open(i); + if (!u) return DEVERR_OPEN; + //i = MODE_USB; + } else { + return DEVERR_OPEN; + } + //} else { + // fprintf(stderr, "Opening generic SCSI device '%s'\n", dev); + // if (sgdev_open(dev, &fd) < 0) return DEVERR_OPEN; + // i = MODE_SG; + //} + + dpf = (DPFHANDLE) malloc(sizeof(DPFContext)); + if (!dpf) return DEVERR_MALLOC; + + dpf->flags = 0; + dpf->mode = i; + + //if (dpf->mode == MODE_USB) { + dpf->dev.udev = u; + error = probe(dpf); + //fprintf(stderr, "Got LCD dimensions: %dx%d\n", dpf->width, dpf->height); + //} else { + // dpf->dev.fd = fd; + //} + + *h = dpf; + return error; +} + +void dpf_close(DPFContext *h) +{ + //switch (h->mode) { + // case MODE_SG: + // close(h->dev.fd); + // break; + // case MODE_USB: + usb_release_interface(h->dev.udev, 0); + usb_close(h->dev.udev); + // break; + //} + free(h); +} + +const char *dev_errstr(int err) +{ + switch (err) { + case DEVERR_FILE: return "File I/O error"; + case DEVERR_OPEN: return "File open error"; + case DEVERR_HEX: return "Hex file error"; + case DEVERR_CHK: return "Checksum error"; + case DEVERR_IO: return "Common I/O error"; + default: return "Unknown error"; + } +} + +#define RGB565_0(r, g, b) \ + (( ((r) & 0xf8) ) | (((g) & 0xe0) >> 5)) +#define RGB565_1(r, g, b) \ + (( ((g) & 0x1c) << 3 ) | (((b) & 0xf8) >> 3)) + +int dpf_setcol(DPFContext *h, const unsigned char *rgb) +{ + unsigned char *cmd = g_excmd; + + cmd[6] = USBCMD_SETPROPERTY; + cmd[7] = PROPERTY_FGCOLOR; + cmd[8] = PROPERTY_FGCOLOR >> 8; + + cmd[9] = RGB565_0(rgb[0], rgb[1], rgb[2]); + cmd[10] = RGB565_1(rgb[0], rgb[1], rgb[2]); + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, NULL, 0); +} + +int dpf_screen_blit(DPFContext *h, + const unsigned char *buf, short rect[4]) +{ + unsigned long len = (rect[2] - rect[0]) * (rect[3] - rect[1]); + len <<= 1; + unsigned char *cmd = g_excmd; + + cmd[6] = USBCMD_BLIT; + cmd[7] = rect[0]; + cmd[8] = rect[0] >> 8; + cmd[9] = rect[1]; + cmd[10] = rect[1] >> 8; + cmd[11] = rect[2] - 1; + cmd[12] = (rect[2] - 1) >> 8; + cmd[13] = rect[3] - 1; + cmd[14] = (rect[3] - 1) >> 8; + cmd[15] = 0; + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, + (unsigned char*) buf, len); +} + +int dpf_setproperty(DPFContext *h, int token, const DPFValue *value) +{ + unsigned char *cmd = g_excmd; + + cmd[6] = USBCMD_SETPROPERTY; + cmd[7] = token; + cmd[8] = token >> 8; + + switch (value->type) { + case TYPE_INTEGER: + cmd[9] = value->value.integer; + cmd[10] = value->value.integer >> 8; + break; + default: + break; + } + + return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, NULL, 0); +} + +// ------------------------------------------------------------------- +// END SELECTIVE COPY & PASTE "dpflib.c" +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- +// START SELECTIVE COPY & PASTE "rawusb.c" +// ------------------------------------------------------------------- + +/* Low level USB code to access DPF. + * + * (c) 2010, 2011 + * + * This currently uses the SCSI command set + * + * The reason for this is that we want to access the hacked frame + * non-root and without having to wait for the SCSI interface to + * intialize. + * + * Later, we'll replace the SCSI command stuff. + */ + +#define ENDPT_OUT 1 +#define ENDPT_IN 0x81 + +struct known_device { + const char *desc; + unsigned short vid; + unsigned short pid; +} g_known_devices[] = { + { "AX206 DPF", 0x1908, 0x0102 }, + { 0 , 0, 0 } /* NEVER REMOVE THIS */ +}; + +int handle_error(const char *txt) +{ + fprintf(stderr, "Error: %s\n", txt); + return -1; +} + +void usb_flush(usb_dev_handle *dev) +{ + char buf[20]; + usb_bulk_read(dev, ENDPT_IN, buf, 3, 1000); +} + +int check_known_device(struct usb_device *d) +{ + struct known_device *dev = g_known_devices; + + while (dev->desc) { + if ((d->descriptor.idVendor == dev->vid) && + (d->descriptor.idProduct == dev->pid)) { + //fprintf(stderr, "Found %s at %s:%s\n", dev->desc, d->bus->dirname, d->filename); + return 1; + } + dev++; + } + return 0; +} + +static struct usb_device *find_dev(int index) +{ + struct usb_bus *b; + struct usb_device *d; + int enumeration = 0; + + b = usb_get_busses(); + + while (b) { + d = b->devices; + while (d) { + if (check_known_device(d)) { + if (enumeration == index) return d; + else enumeration++; + } + +#ifdef DEBUG + printf("%04x %04x\n", + d->descriptor.idVendor, + d->descriptor.idProduct); +#endif + d = d->next; + } + b = b->next; + } + return NULL; +} + +char g_buf[] = { + 0x55, 0x53, 0x42, 0x43, // dCBWSignature + 0xde, 0xad, 0xbe, 0xef, // dCBWTag + 0x00, 0x80, 0x00, 0x00, // dCBWLength + 0x00, // bmCBWFlags: 0x80: data in (dev to host), 0x00: Data out + 0x00, // bCBWLUN + 0x10, // bCBWCBLength + + // SCSI cmd: + 0xcd, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x11, 0xf8, + 0x70, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +int emulate_scsi(usb_dev_handle *dev, unsigned char *cmd, int cmdlen, char out, + unsigned char *data, unsigned long block_len) +{ + int len; + int ret; + static unsigned char ansbuf[13]; // Do not change size. + + g_buf[14] = cmdlen; + memcpy(&g_buf[15], cmd, cmdlen); + + g_buf[8] = block_len; + g_buf[9] = block_len >> 8; + g_buf[10] = block_len >> 16; + g_buf[11] = block_len >> 24; + + ret = usb_bulk_write(dev, ENDPT_OUT, g_buf, sizeof(g_buf), 1000); + if (ret < 0) return ret; + + if (out == DIR_OUT) { + if (data) { + ret = usb_bulk_write(dev, ENDPT_OUT, (char* )data, + block_len, 3000); + if (ret != (int) block_len) { + perror("bulk write"); + return ret; + } + } + } else if (data) { + ret = usb_bulk_read(dev, ENDPT_IN, (char *) data, block_len, 4000); + if (ret != (int) block_len) { + perror("bulk data read"); + } + } + // get ACK: + len = sizeof(ansbuf); + int retry = 0; + do { + ret = usb_bulk_read(dev, ENDPT_IN, (char *) ansbuf, len, 5000); + if (ret != len) { + perror("bulk ACK read"); + ret = DEVERR_TIMEOUT; + } + retry++; + } while (ret == DEVERR_TIMEOUT && retry < 5); + if (strncmp((char *) ansbuf, "USBS", 4)) { + return handle_error("Got invalid reply\n"); + } + // pass back return code set by peer: + return ansbuf[12]; +} + +usb_dev_handle *dpf_usb_open(int index) +{ + struct usb_device *d; + usb_dev_handle *usb_dev; + + usb_init(); + usb_find_busses(); + usb_find_devices(); + + d = find_dev(index); + if (!d) { + handle_error("No matching USB device found!"); + return NULL; + } + + usb_dev = usb_open(d); + if (usb_dev == NULL) { + handle_error("Failed to open usb device!"); + return NULL; + } + usb_claim_interface(usb_dev, 0); + return usb_dev; +} + +// ------------------------------------------------------------------- +// END SELECTIVE COPY & PASTE "rawusb.c" +// ------------------------------------------------------------------- + + +} // end of namespace LIBDPF + +//########################################################################################## +// ** END OF UGLY HACK ** END OF UGLY HACK ** END OF UGLY HACK ** END OF UGLY HACK * +//########################################################################################## diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/ax206dpf.h graphlcd-base-0.1.9+git20120310/glcddrivers/ax206dpf.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/ax206dpf.h 1970-01-01 00:00:00.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/ax206dpf.h 2012-03-10 09:18:56.000000000 +0000 @@ -0,0 +1,300 @@ +/* + * GraphLCD driver library + * + * ax206dpf.h - AX206dpf driver class + * Output goes to AX 206 based photoframe + * based on: + * simlcd device + * (c) 2001-2004 Carsten Siebholz + * (c) 2011 Dirk Heiser + * (c) 2011 Wolfgang Astleitner + * + * includes code from: + * http://sourceforge.net/projects/dpf-ax/ + * + * Original copyright: + * + * Copyright (C) 2008 Jeroen Domburg + * Modified from sample code by: + * Copyright (C) 2005 Michael Reinelt + * Copyright (C) 2005, 2006, 2007 The LCD4Linux Team + * Mods by + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2011 Lutz Neumann + * + */ + +#ifndef _GLCDDRIVERS_AX206DPF_H_ +#define _GLCDDRIVERS_AX206DPF_H_ + +#include "driver.h" + +namespace LIBDPF { +struct dpf_context; +typedef dpf_context DPFContext; +} + +namespace GLCD +{ +#define MAX_DPFS 4 + +#define DEFAULT_WIDTH 320 +#define DEFAULT_HEIGHT 240 +#define DEFAULT_BPP 2 + +#define USB_SCAN_INTERVALL 10 // seconds between usb scans for missing displays + +typedef struct display_handle { + bool attached; + char address[8]; + bool isPortrait; + bool rotate90; + bool flip; + int minx, maxx; + int miny, maxy; + LIBDPF::DPFContext *dpfh; + unsigned char * LCD; +} DISPLAYHANDLE; + + +class cDriverConfig; + +class cDriverAX206DPF : public cDriver +{ +private: + unsigned char * tempLCD; // temp transfer buffer + + bool portrait; // portrait or landscape mode + int zoom; // pixel zoom factor + unsigned int numdisplays; // number of detected displays + unsigned int numxdisplays; // number of displays (horizontal) + unsigned int numydisplays; // number of displays (vertical) + unsigned int sizex; // logical horizontal size of one display + unsigned int sizey; // logical vertical size of one display + unsigned int bpp; // bits per pixel + + DISPLAYHANDLE *dh[MAX_DPFS]; + std::string flips; + time_t lastscan; + int lastbrightness; + + + int CheckSetup(); + void ResetMinMax(); + bool RescanUSB(); + int InitSingleDisplay(unsigned int); + void DeInitSingleDisplay(unsigned int); + void ClearSingleDisplay(unsigned int); + void SetSingleDisplayBrightness(unsigned int, unsigned int); + +public: + cDriverAX206DPF(cDriverConfig * config); + + virtual int Init(); + virtual int DeInit(); + + virtual void Clear(); + virtual void SetPixel(int x, int y, uint32_t data); + virtual void Refresh(bool refreshAll = false); + virtual uint32_t GetBackgroundColor(void); + virtual void SetBrightness(unsigned int); + virtual bool GetDriverFeature (const std::string & Feature, int & value); +}; + +} // end of namespace GLCD + + +//########################################################################################## +// +// ** START OF UGLY HACK ** START OF UGLY HACK ** START OF UGLY HACK ** START OF UGLY HACK * +// +// Because I choose NOT to include the static library libdpf.a and/or their header- and +// source-files from the original dpf-ax hack, I did some creative copy & paste from there +// to this place. I will delete this stuff when a usable shared library of libpdf exists. +// +//########################################################################################## + +// ------------------------------------------------------------------- +// START SELECTIVE COPY & PASTE "dpf.h" +// ------------------------------------------------------------------- + +/** libdpf header file + * + * (c) 2010, 2011 + * + */ + +// ------------------------------------------------------------------- +// START SELECTIVE COPY & PASTE "usbuser.h" +// ------------------------------------------------------------------- + +#include + +namespace LIBDPF +{ + +/* USB user commands + * + * Only temporary. Should move to dpflib or into a dclib configuration. + * + */ + +#define PROTOCOL_VERSION 1 + +/** Our vendor specific USB commands to do stuff on the DPF */ + +#define USBCMD_GETPROPERTY 0x00 ///< Get property +#define USBCMD_SETPROPERTY 0x01 ///< Set property +#define USBCMD_MEMREAD 0x04 ///< Memory read +#define USBCMD_APPLOAD 0x05 ///< Load and run applet +#define USBCMD_FILLRECT 0x11 ///< Fill screen rectangle +#define USBCMD_BLIT 0x12 ///< Blit to screen +#define USBCMD_COPYRECT 0x13 ///< Copy screen rectangle +#define USBCMD_FLASHLOCK 0x20 ///< Lock USB for flash access +#define USBCMD_PROBE 0xff ///< Get version code (probe) + +/* Some special return codes */ +#define USB_IN_SEQUENCE 0x7f ///< We're inside a command sequence + +// Property handling: + +#define PROPERTY_BRIGHTNESS 0x01 +#define PROPERTY_FGCOLOR 0x02 +#define PROPERTY_BGCOLOR 0x03 +#define PROPERTY_ORIENTATION 0x10 + +// ------------------------------------------------------------------- +// END SELECTIVE COPY & PASTE "usbuser.h" +// ------------------------------------------------------------------- + +#define ADDR unsigned int + +//#define MODE_SG 0x00 ///< generic device mode (original) +//#define MODE_USB 0x01 ///< libusb operation mode (hacked) +#define FLAG_CAN_LOCK 0x80 ///< Has the locking feature (new firmware) + +enum { + DEVERR_FILE = -16, + DEVERR_OPEN, + DEVERR_HEX, + DEVERR_CHK, + DEVERR_IO, + DEVERR_MALLOC, + DEVERR_TIMEOUT, +}; + +/** The DPF context structure */ + +typedef +struct dpf_context { + unsigned char mode; + unsigned char flags; + union { + usb_dev_handle *udev; + int fd; + } dev; + unsigned int width; + unsigned int height; + int bpp; + int proto; + char* buff; + unsigned char* oldpix; + int offx; + int offy; +} DPFContext; + +/** A value proxy for the property API */ +typedef struct dpf_proxy { + union { + short integer; + char *sequence; + } value; + char type; +} DPFValue; + +enum { + TYPE_INTEGER, + TYPE_STRING, +}; + +#define DPFHANDLE struct dpf_context * + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Opens the DPF device. if dev is not NULL, open device, otherwise, look for + USB device. + */ +int dpf_open(const char *dev, DPFHANDLE *h); + +/** Close DPF device */ +void dpf_close(DPFHANDLE h); + +/** Blit data to screen + * + * \param buf buffer to 16 bpp RGB 565 image data + * \param rect rectangle tuple: [x0, y0, x1, y1] + */ + +int dpf_screen_blit(DPFHANDLE h, const unsigned char *buf, short rect[4]); + +/** Set property on DPF + * \param token Property token + * \param value Pointer to value + */ +int dpf_setproperty(DPFHANDLE h, int token, const DPFValue *value); + +/* USB raw */ + +int emulate_scsi(usb_dev_handle *d, unsigned char *cmd, int cmdlen, char out, + unsigned char *data, unsigned long block_len); + +const char *dev_errstr(int err); + +// Private stuff: +usb_dev_handle *dpf_usb_open(int index); +int sgdev_open(const char *portname, int *fd); + +#ifdef __cplusplus +} +#endif + +// Some internal address offsets. They may change, but so far all types +// seem to have the same +// +// w: word, : length, [LE, BE] +// +// FIXME: Use packed struct later. + +// FIXME: Should be 0x0020, once we have the firmware replaced +#define OFFSET_PROPS 0x3f0020 ///< w[2]:LE : Resolution X, Y + +// ------------------------------------------------------------------- +// END SELECTIVE COPY & PASTE "dpf.h" +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- +// START SELECTIVE COPY & PASTE "sglib.h" +// ------------------------------------------------------------------- + +/* generic SCSI device stuff: */ + +#define DIR_IN 0 +#define DIR_OUT 1 + +// ------------------------------------------------------------------- +// END SELECTIVE COPY & PASTE "sglib.h" +// ------------------------------------------------------------------- + +} // end of namespace LIBDPF_HACK + +//########################################################################################## +// ** END OF UGLY HACK ** END OF UGLY HACK ** END OF UGLY HACK ** END OF UGLY HACK * +//########################################################################################## + +#endif //_GLCDDRIVERS_AX206DPF_H_ diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/config.c graphlcd-base-0.1.9+git20120310/glcddrivers/config.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/config.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/config.c 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #include @@ -214,6 +215,12 @@ continue; if (line[0] == '[' && line[line.length() - 1] == ']') { + // no ':' in section names + if (line.substr(1, line.length() - 2).find(':') != std::string::npos) { + syslog(LOG_ERR, "Config error: section name may not contain a ':', erraneous line: '%s'\n", line.c_str()); + file.close(); + return false; + } if (!inSections) inSections = true; else diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/config.h graphlcd-base-0.1.9+git20120310/glcddrivers/config.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/config.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/config.h 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_CONFIG_H_ diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/dm140gink.c graphlcd-base-0.1.9+git20120310/glcddrivers/dm140gink.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/dm140gink.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/dm140gink.c 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Stephan Skrodzki + * (c) 2004 Stephan Skrodzki + * (c) 2011 Wolfgang Astleitner */ #include @@ -30,16 +31,10 @@ { cDriverDM140GINK::cDriverDM140GINK(cDriverConfig * config) -: config(config), +: cDriver(config), fd(-1), framebuff(0) { - oldConfig = new cDriverConfig(*config); -} - -cDriverDM140GINK::~cDriverDM140GINK() -{ - delete oldConfig; } /* hack - fix improper signed char handling - it's seeing 0x80 as a negative value*/ @@ -92,7 +87,7 @@ //************************************************************** if((err = ioctl(fd, HIDIOCSUSAGE, &uref)) < 0) { - syslog(LOG_INFO, "%s: Error with sending the USAGE ioctl %d,0x%02X;size:%d\n", config->name.c_str(), i, (int)buf[i],size); + syslog(LOG_INFO, "%s: Error with sending the USAGE ioctl %d,0x%02X;size:%d\n", config->name.c_str(), (int)i, (int)buf[i], (int)size); return err; } uref.usage_code = 0xffa10006; //unused? @@ -130,8 +125,8 @@ if (height <= 0) height = 16; - vendor = 0x040b; - product = 0x7001; + signed short vendor = 0x040b; + signed short product = 0x7001; for (unsigned int i = 0; i < config->options.size(); i++) { @@ -254,7 +249,7 @@ return 0; } -void cDriverDM140GINK::SetPixel(int x, int y) +void cDriverDM140GINK::SetPixel(int x, int y, uint32_t data) { if (x >= width || y >= height) return; @@ -267,7 +262,10 @@ int offset = (y/8) * width + x; char mask = (1 << (7 - (y%8))); - framebuff[offset] |= mask; + if (data == GRAPHLCD_White) + framebuff[offset] |= mask; + else + framebuff[offset] &= (0xFF ^ mask); } void cDriverDM140GINK::Clear() @@ -275,6 +273,7 @@ memset(framebuff, 0, screensize); } +#if 0 void cDriverDM140GINK::Set8Pixels(int x, int y, unsigned char data) { x &= 0xFFF8; @@ -282,9 +281,10 @@ for (int n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GRAPHLCD_White); } } +#endif void cDriverDM140GINK::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/dm140gink.h graphlcd-base-0.1.9+git20120310/glcddrivers/dm140gink.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/dm140gink.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/dm140gink.h 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Stephan Skrodzki + * (c) 2004 Stephan Skrodzki + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_DM140GINK_H_ @@ -24,9 +25,6 @@ class cDriverDM140GINK : public cDriver { private: - cDriverConfig * config; - cDriverConfig * oldConfig; - int fd; int vendor; @@ -38,17 +36,16 @@ int SendReport(const char *buf, size_t size); int CheckSetup(); - void SetPixel(int x, int y); public: cDriverDM140GINK(cDriverConfig * config); - virtual ~cDriverDM140GINK(); virtual int Init(); virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/driver.c graphlcd-base-0.1.9+git20120310/glcddrivers/driver.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/driver.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/driver.c 2012-03-10 09:18:56.000000000 +0000 @@ -9,23 +9,47 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner */ #include "common.h" #include "driver.h" - +#include "config.h" namespace GLCD { -cDriver::cDriver() +cSimpleTouchEvent::cSimpleTouchEvent() : x(0), y(0), touch(0) +{ +} + +cDriver::cDriver(cDriverConfig * config) : width(0), - height(0) + height(0), + config(config) { + fgcol = GetDefaultForegroundColor(); + bgcol = GetDefaultBackgroundColor(); + oldConfig = new cDriverConfig(*config); } -void cDriver::SetScreen(const unsigned char * data, int wid, int hgt, int lineSize) +cDriver::~cDriver(void) +{ + delete oldConfig; +} + +const std::string cDriver::ConfigName() { + return (config) ? config->name : ""; +} + +const std::string cDriver::DriverName() { + return (config) ? config->driver : ""; +} + + +//void cDriver::SetScreen(const unsigned char * data, int wid, int hgt, int lineSize) +void cDriver::SetScreen(const uint32_t * data, int wid, int hgt) { int x, y; @@ -34,11 +58,19 @@ if (hgt > height) hgt = height; - Clear(); + //Clear(); if (data) { for (y = 0; y < hgt; y++) { + for (x = 0; x < wid; x++) + { +// printf("%s:%s(%d) - %03d * %03d (linesize %02d), %08x\n", __FILE__, __FUNCTION__, __LINE__, x, y, lineSize, data[y * lineSize + x]); + SetPixel(x, y, data[y * wid + x]); + } + } + } +/* for (x = 0; x < (wid / 8); x++) { Set8Pixels(x * 8, y, data[y * lineSize + x]); @@ -48,7 +80,24 @@ Set8Pixels((wid / 8) * 8, y, data[y * lineSize + wid / 8] & bitmaskl[wid % 8 - 1]); } } +*/ +} + +void cDriver::Set8Pixels(int x, int y, unsigned char data) +{ + int n; + // calling GetForegroundColor() and GetBackgroundColor() is slow in some situations. + // will be replaced through setting object-wide (incl. derived objs) class members + uint32_t fg = GetForegroundColor(); + uint32_t bg = GetBackgroundColor(); + + // guarante that x starts at a position divisible by 8 + x &= 0xFFF8; + + for (n = 0; n < 8; ++n) { + SetPixel(x + n, y, (data & (0x80 >> n)) ? fg : bg); } } + } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/driver.h graphlcd-base-0.1.9+git20120310/glcddrivers/driver.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/driver.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/driver.h 2012-03-10 09:18:56.000000000 +0000 @@ -9,38 +9,123 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_DRIVER_H_ #define _GLCDDRIVERS_DRIVER_H_ #include +#include "../glcdgraphics/bitmap.h" + +// for strcasecmp +#include namespace GLCD { +class cGLCDEvent { +public: + virtual ~cGLCDEvent() {} +}; + +class cSimpleTouchEvent : public cGLCDEvent { +public: + int x; + int y; + int touch; + cSimpleTouchEvent(); +}; + +class cDriverConfig; + class cDriver { protected: - int width; - int height; + int width; + int height; + uint32_t bgcol; + uint32_t fgcol; + cDriverConfig * config; + cDriverConfig * oldConfig; + + virtual bool GetDriverFeature (const std::string & Feature, int & value) { return false; } + virtual uint32_t GetDefaultBackgroundColor(void) { return GRAPHLCD_Black; } + uint32_t GetDefaultForegroundColor(void) { return GetDefaultBackgroundColor() ^ 0x00FFFFFF; } public: - cDriver(); - virtual ~cDriver() {} + cDriver(cDriverConfig * config); + virtual ~cDriver(); int Width() const { return width; } int Height() const { return height; } + + const std::string ConfigName(); + const std::string DriverName(); virtual int Init() { return 0; } virtual int DeInit() { return 0; } virtual void Clear() {} - virtual void Set8Pixels(int x, int y, unsigned char data) {} - virtual void SetScreen(const unsigned char * data, int width, int height, int lineSize); + virtual void SetPixel(int x, int y, uint32_t data) {} + void Set8Pixels(int x, int y, unsigned char data); +// virtual void SetScreen(const unsigned char * data, int width, int height, int lineSize); + virtual void SetScreen(const uint32_t *data, int width, int height); virtual void Refresh(bool refreshAll = false) {} virtual void SetBrightness(unsigned int percent) {} + + + virtual bool SetFeature (const std::string & Feature, int value) { return false; } + + uint32_t GetBackgroundColor(bool driverdefault=false) { + return ( + (driverdefault || bgcol == GRAPHLCD_ERRCOL || bgcol == GRAPHLCD_Transparent) + ? GetDefaultBackgroundColor() + : bgcol + ); + } + uint32_t GetForegroundColor(bool driverdefault=false) { + return ( + (driverdefault || fgcol == GRAPHLCD_ERRCOL || fgcol == GRAPHLCD_Transparent) + ? GetDefaultForegroundColor() + : fgcol + ); + } + + // not to be overridden, override GetDriverFeature() instead + // the following feature names (case insensitive!) are guaranteed to give results: + // 'depth' colour depth, default: 1 + // 'ismonochrome' is lcd a monochrome display?, default: true (1) + // the following feature names are pre-defined but default to false (0) + // 'isgreyscale', 'isgrayscale' is lcd a greyscale display? + // 'iscolour', 'iscolor' is lcd a colour display? + // 'touch', 'touchscreen' is a touchscreen supported and available? + bool GetFeature (const std::string & Feature, int & value) { + if (GetDriverFeature(Feature, value)) { + return true; + } else if (strcasecmp(Feature.c_str(), "depth") == 0) { + value = 1; + return true; + } else if (strcasecmp(Feature.c_str(), "ismonochrome") == 0) { + value = 1; // true == 1, false == 0 + return true; + } else if (strcasecmp(Feature.c_str(), "isgreyscale") == 0 || strcasecmp(Feature.c_str(), "isgrayscale") == 0) { + value = 0; // true == 1, false == 0 + return true; + } else if (strcasecmp(Feature.c_str(), "iscolour") == 0 || strcasecmp(Feature.c_str(), "iscolor") == 0) { + value = 0; // true == 1, false == 0 + return true; + } else if (strcasecmp(Feature.c_str(), "touch") == 0 || strcasecmp(Feature.c_str(), "touchscreen") == 0) { + value = 0; // true == 1, false == 0 + return true; + } + value = 0; + return false; + } + + virtual cGLCDEvent * GetEvent(void) { return NULL; } + }; } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/drivers.c graphlcd-base-0.1.9+git20120310/glcddrivers/drivers.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/drivers.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/drivers.c 2012-03-10 09:18:56.000000000 +0000 @@ -30,8 +30,8 @@ #include "dm140gink.h" #include "serdisp.h" #include "g15daemon.h" -#ifdef HAVE_LIBHID -#include "futabaMDM166A.h" +#ifdef HAVE_AX206DPF_EXPERIMENTAL +#include "ax206dpf.h" #endif namespace GLCD @@ -55,11 +55,11 @@ {"network", kDriverNetwork}, {"gu126x64D-K610A4", kDriverGU126X64D_K610A4}, {"dm140gink", kDriverDM140GINK}, -#ifdef HAVE_LIBHID - {"futabaMDM166A", kDriverFutabaMDM166A}, -#endif {"serdisp", kDriverSerDisp}, {"g15daemon", kDriverG15daemon}, +#ifdef HAVE_AX206DPF_EXPERIMENTAL + {"ax206dpf", kDriverAX206DPF}, +#endif {"", kDriverUnknown} }; @@ -114,14 +114,14 @@ return new cDriverGU126X64D_K610A4(config); case kDriverDM140GINK: return new cDriverDM140GINK(config); -#ifdef HAVE_LIBHID - case kDriverFutabaMDM166A: - return new cDriverFutabaMDM166A(config); -#endif case kDriverSerDisp: return new cDriverSerDisp(config); case kDriverG15daemon: return new cDriverG15daemon(config); +#ifdef HAVE_AX206DPF_EXPERIMENTAL + case kDriverAX206DPF: + return new cDriverAX206DPF(config); +#endif case kDriverUnknown: default: return NULL; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/drivers.h graphlcd-base-0.1.9+git20120310/glcddrivers/drivers.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/drivers.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/drivers.h 2012-03-10 09:18:56.000000000 +0000 @@ -40,7 +40,9 @@ kDriverNetwork = 14, kDriverGU126X64D_K610A4 = 15, kDriverDM140GINK = 16, - kDriverFutabaMDM166A = 17, +#ifdef HAVE_AX206DPF_EXPERIMENTAL + kDriverAX206DPF = 17, +#endif kDriverSerDisp = 100, kDriverG15daemon = 200 }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/framebuffer.c graphlcd-base-0.1.9+git20120310/glcddrivers/framebuffer.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/framebuffer.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/framebuffer.c 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Stephan Skrodzki + * (c) 2004 Stephan Skrodzki + * (c) 2011 Wolfgang Astleitner */ #include @@ -28,20 +29,15 @@ { cDriverFramebuffer::cDriverFramebuffer(cDriverConfig * config) -: config(config), +: cDriver(config), offbuff(0), fbfd(-1) { - oldConfig = new cDriverConfig(*config); -} - -cDriverFramebuffer::~cDriverFramebuffer() -{ - delete oldConfig; } int cDriverFramebuffer::Init() { +#if 0 // default values width = config->width; if (width <= 0) @@ -49,7 +45,10 @@ height = config->height; if (height <= 0) height = 240; +#endif zoom = 1; + damage = 0; + depth = 1; for (unsigned int i = 0; i < config->options.size(); i++) { @@ -62,11 +61,34 @@ syslog(LOG_ERR, "%s error: zoom %d not supported, using default (%d)!\n", config->name.c_str(), z, zoom); } + else if (config->options[i].name == "ReportDamage" || config->options[i].name == "Damage" ) + { + if (config->options[i].value == "none") { + damage = 0; + } else if (config->options[i].value == "ugly") { + damage = 1; + } else if (config->options[i].value == "udlfb") { + damage = 2; + } else if (config->options[i].value == "auto") { + damage = -1; + } + else + syslog(LOG_ERR, "%s error: ReportDamage='%s' not supported, continuing w/o damage reporting!\n", + config->name.c_str(), config->options[i].value.c_str()); + } } - // Open the file for reading and writing - fbfd = open("/dev/fb0", O_RDWR); - if (1 == fbfd) + if (config->device == "") + { + fbfd = open("/dev/fb0", O_RDWR); + } + else + { + fbfd = open(config->device.c_str(), O_RDWR); + } + + //fbfd = open("/dev/fb0", O_RDWR); + if (fbfd < 0) { syslog(LOG_ERR, "%s: cannot open framebuffer device.\n", config->name.c_str()); return -1; @@ -87,11 +109,78 @@ return -1; } + if ( ! ( vinfo.bits_per_pixel == 8 || vinfo.bits_per_pixel == 16 || vinfo.bits_per_pixel == 24 || vinfo.bits_per_pixel == 32 ) ) + { + syslog(LOG_ERR, "%s: bpp %d not supported.\n", config->name.c_str(), vinfo.bits_per_pixel); + return -1; + } + + // get colour info + if (vinfo.bits_per_pixel > 8) { + rlen = vinfo.red.length; + glen = vinfo.green.length; + blen = vinfo.blue.length; + alen = vinfo.transp.length; + + roff = vinfo.red.offset; + goff = vinfo.green.offset; + boff = vinfo.blue.offset; + aoff = vinfo.transp.offset; + } else { + // init colour map + struct fb_cmap cmap; + uint16_t r[256], g[256], b[256]; + int i; + + // RGB332 code from fbsplash-project taken as guideline + for ( i = 0; i < 256; i ++ ) { + r[i] = (( i & 0xe0) << 8) + ((i & 0x20) ? 0x1fff : 0); + g[i] = (( i & 0x1c) << 11) + ((i & 0x04) ? 0x1fff : 0); + b[i] = (( i & 0x03) << 14) + ((i & 0x01) ? 0x3fff : 0); + } + cmap.start = 0; + cmap.len = 256; + cmap.red = r; + cmap.green = g; + cmap.blue = b; + cmap.transp = 0; + if (ioctl(fbfd, FBIOPUTCMAP, &cmap)) { + syslog(LOG_ERR, "%s: Error setting colour map for bpp=8.\n", config->name.c_str()); + return -1; + } + } + // Figure out the size of the screen in bytes screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; syslog(LOG_INFO, "%s: V01: xres: %d, yres %d, vyres: %d, bpp: %d, linelenght: %d\n", config->name.c_str(),vinfo.xres,vinfo.yres,vinfo.yres_virtual,vinfo.bits_per_pixel,finfo.line_length); + // auto calc w/h depending on zoom + if (zoom == 1) { + width = vinfo.xres >> 1; + height = vinfo.yres >> 1; + } else { + width = vinfo.xres; + height = vinfo.yres; + } + depth = vinfo.bits_per_pixel; + + // init bounding box + bbox[0] = width - 1; // x top + bbox[1] = height - 1; // y top + bbox[2] = 0; // x bottom + bbox[3] = 0; // y bottom + + + // damage reporting == auto: detect framebuffer driver + if (damage == -1) { + if (strncasecmp(finfo.id, "udlfb", 16) == 0) { + damage = 2; // udlfb + } else { /* not supported / not detected */ + damage = 0; // not detected -> no damage reporting + } + } + // reserve another memory to draw into offbuff = new char[screensize]; if (!offbuff) @@ -150,10 +239,12 @@ return 0; } -void cDriverFramebuffer::SetPixel(int x, int y) +void cDriverFramebuffer::SetPixel(int x, int y, uint32_t data) { int location; - int outcol; + unsigned char col1, col2, col3, alpha = 0; + uint32_t colraw; + int changed = 0; if (x >= width || y >= height) return; @@ -164,72 +255,112 @@ y = height - 1 - y; } - // Figure out where in memory to put the pixel - location = (x*(1+zoom)+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + - (y*(1+zoom)+vinfo.yoffset) * finfo.line_length; - if (vinfo.bits_per_pixel <= 8) - { - outcol = 15; - } - else - { - outcol = 255; - } + // Figure out where in memory to put the pixel + location = ( (x << zoom) + vinfo.xoffset) * (vinfo.bits_per_pixel >> 3) + + ( (y << zoom) + vinfo.yoffset) * finfo.line_length; if (vinfo.bits_per_pixel <= 8) { - *(offbuff + location) = outcol; - if (zoom == 1) - { - *(offbuff + location + 1) = outcol; - *(offbuff + location + finfo.line_length) = outcol; - *(offbuff + location + finfo.line_length + 1) = outcol; + col1 = ((data & 0x00FF0000) >> (16 + 5) << 5) | // RRRg ggbb + ((data & 0x0000FF00) >> ( 8 + 5) << 2) | // rrrG GGbb + ((data & 0x000000FF) >> ( 6) ); // rrrg ggBB + if ( *(offbuff + location) != col1) { + changed = 1; + *(offbuff + location) = col1; + if (zoom == 1) + { + *(offbuff + location + 1) = col1; + *(offbuff + location + finfo.line_length) = col1; + *(offbuff + location + finfo.line_length + 1) = col1; + } } } else if (vinfo.bits_per_pixel <= 16) { - *(offbuff + location) = outcol; - *(offbuff + location + 1) = outcol; - if (zoom == 1) - { - *(offbuff + location + 2) = outcol; - *(offbuff + location + 3) = outcol; - *(offbuff + location + finfo.line_length) = outcol; - *(offbuff + location + finfo.line_length + 1) = outcol; - *(offbuff + location + finfo.line_length + 2) = outcol; - *(offbuff + location + finfo.line_length + 3) = outcol; + + + colraw = ((data & 0x00FF0000) >> (16 + 8 - rlen) << roff) | // red + ((data & 0x0000FF00) >> ( 8 + 8 - glen) << goff) | // green + ((data & 0x000000FF) >> ( 0 + 8 - blen) << boff); // blue + col1 = colraw & 0x0000FF; + col2 = (colraw & 0x00FF00) >> 8; + if ( *(offbuff + location) != col1 || *(offbuff + location + 1) != col2 ) { + changed = 1; + *(offbuff + location) = col1; + *(offbuff + location + 1) = col2; + if (zoom == 1) + { + *(offbuff + location + 2) = col1; + *(offbuff + location + 3) = col2; + *(offbuff + location + finfo.line_length) = col1; + *(offbuff + location + finfo.line_length + 1) = col2; + *(offbuff + location + finfo.line_length + 2) = col1; + *(offbuff + location + finfo.line_length + 3) = col2; + } } } else { - *(offbuff + location) = outcol; - *(offbuff + location + 1) = outcol; - *(offbuff + location + 2) = outcol; - *(offbuff + location + 3) = 0; /* should be transparency */ - if (zoom == 1) - { - *(offbuff + location + 4) = outcol; - *(offbuff + location + 5) = outcol; - *(offbuff + location + 6) = outcol; - *(offbuff + location + 7) = 0; - *(offbuff + location + finfo.line_length) = outcol; - *(offbuff + location + finfo.line_length + 1) = outcol; - *(offbuff + location + finfo.line_length + 2) = outcol; - *(offbuff + location + finfo.line_length + 3) = 0; - *(offbuff + location + finfo.line_length + 4) = outcol; - *(offbuff + location + finfo.line_length + 5) = outcol; - *(offbuff + location + finfo.line_length + 6) = outcol; - *(offbuff + location + finfo.line_length + 7) = 0; + // remap graphlcd colour representation to framebuffer rep. + colraw = ((data & 0x00FF0000) >> (16 + 8 - rlen) << roff) | // red + ((data & 0x0000FF00) >> ( 8 + 8 - glen) << goff) | // green + ((data & 0x000000FF) >> ( 0 + 8 - blen) << boff); // blue + col1 = (colraw & 0x000000FF); + col2 = (colraw & 0x0000FF00) >> 8; + col3 = (colraw & 0x00FF0000) >> 16; + + if (vinfo.bits_per_pixel == 32) { + colraw |= ((data & 0xFF000000) >> (24 + 8 - alen) << aoff); // transp. + alpha = (colraw & 0xFF000000) >> 24; } + + if ( *(offbuff + location) != col1 || *(offbuff + location + 1) != col2 || *(offbuff + location + 2) != col3 ) { + int pos = 0; + changed = 1; + *(offbuff + location + pos++) = col1; + *(offbuff + location + pos++) = col2; + *(offbuff + location + pos++) = col3; + if (vinfo.bits_per_pixel > 24) + *(offbuff + location + pos++) = alpha; /* should be transparency */ + if (zoom == 1) + { + *(offbuff + location + pos++) = col1; + *(offbuff + location + pos++) = col2; + *(offbuff + location + pos++) = col3; + if (vinfo.bits_per_pixel > 24) + *(offbuff + location + pos++) = alpha; + pos = 0; + *(offbuff + location + finfo.line_length + pos++) = col1; + *(offbuff + location + finfo.line_length + pos++) = col2; + *(offbuff + location + finfo.line_length + pos++) = col3; + if (vinfo.bits_per_pixel > 24) + *(offbuff + location + finfo.line_length + pos++) = alpha; + *(offbuff + location + finfo.line_length + pos++) = col1; + *(offbuff + location + finfo.line_length + pos++) = col2; + *(offbuff + location + finfo.line_length + pos++) = col3; + if (vinfo.bits_per_pixel > 24) + *(offbuff + location + finfo.line_length + pos++) = alpha; + } + } + } + + if (changed) { + // bounding box changed? + if (x < bbox[0]) bbox[0] = x; + if (y < bbox[1]) bbox[1] = y; + if (x > bbox[2]) bbox[2] = x; + if (y > bbox[3]) bbox[3] = y; } } void cDriverFramebuffer::Clear() { memset(offbuff, 0, screensize); + processDamage(); } +#if 0 void cDriverFramebuffer::Set8Pixels(int x, int y, unsigned char data) { int n; @@ -239,13 +370,77 @@ for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GRAPHLCD_White); } } +#endif void cDriverFramebuffer::Refresh(bool refreshAll) { memcpy(fbp, offbuff, screensize); + processDamage(); +} + +bool cDriverFramebuffer::GetDriverFeature (const std::string & Feature, int & value) { + if (offbuff) { + if (strcasecmp(Feature.c_str(), "depth") == 0) { + value = depth; + return true; + } else if (strcasecmp(Feature.c_str(), "ismonochrome") == 0) { + value = 0; + return true; + } else if (strcasecmp(Feature.c_str(), "isgreyscale") == 0 || strcasecmp(Feature.c_str(), "isgrayscale") == 0) { + value = 0; + return true; + } else if (strcasecmp(Feature.c_str(), "iscolour") == 0 || strcasecmp(Feature.c_str(), "iscolor") == 0) { + value = 1; + return true; +#if 0 + } else if (strcasecmp(Feature.c_str(), "touch") == 0 || strcasecmp(Feature.c_str(), "touchscreen") == 0) { + if (...) { + value = (...) ? 1 : 0; + } + return true; +#endif + } + } + value = 0; + return false; +} + + +/* defines for different damage processing calls needed by _update() */ +#define DLFB_IOCTL_REPORT_DAMAGE 0xAA +void cDriverFramebuffer::processDamage (void) { + switch (damage) { + case 1: // ugly + { + unsigned char buf[3] = "\n"; + write(fbfd,buf,2); + } + break; + case 2: // udlfb + { + struct fb_rect { + int x; int y; int w; int h; + } damage = {0, 0, 0, 0}; + damage.x = bbox[0] << zoom; + damage.y = bbox[1] << zoom; + damage.w = (bbox[2] - bbox[0] + 1) << zoom; + damage.h = (bbox[3] - bbox[1] + 1) << zoom; + + ioctl(fbfd, DLFB_IOCTL_REPORT_DAMAGE, &damage); + } + break; + default: // no damage reporting + break; + } + + /* reset bounding box */ + bbox[0] = width - 1; + bbox[1] = height - 1; + bbox[2] = 0; + bbox[3] = 0; } } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/framebuffer.h graphlcd-base-0.1.9+git20120310/glcddrivers/framebuffer.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/framebuffer.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/framebuffer.h 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Stephan Skrodzki + * (c) 2004 Stephan Skrodzki + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_FRAMEBUFFER_H_ @@ -26,8 +27,6 @@ { private: unsigned char ** LCD; - cDriverConfig * config; - cDriverConfig * oldConfig; char *offbuff; int fbfd; struct fb_var_screeninfo vinfo; @@ -35,19 +34,25 @@ long int screensize; void *fbp; int zoom; + int damage; + int bbox[4]; + int depth; + uint32_t roff, boff, goff, aoff; + uint32_t rlen, blen, glen, alen; int CheckSetup(); - void SetPixel(int x, int y); - + void processDamage (void); +protected: + virtual bool GetDriverFeature (const std::string & Feature, int & value); public: cDriverFramebuffer(cDriverConfig * config); - virtual ~cDriverFramebuffer(); virtual int Init(); virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/futabaMDM166A.c graphlcd-base-0.1.9+git20120310/glcddrivers/futabaMDM166A.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/futabaMDM166A.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/futabaMDM166A.c 2012-03-10 09:18:56.000000000 +0000 @@ -1,12 +1,15 @@ /* * GraphLCD driver library * - * (C) 2010 Andreas Brachold - + * futatbaMDM166A.c - Futaba MDM166A LCD + * Output goes to a Futaba MDM166A LCD + * * This file is released under the GNU General Public License. * * See the files README and COPYING for details. * + * (c) 2010 Andreas Brachold + * (c) 2011 Wolfgang Astleitner */ #include @@ -215,26 +218,22 @@ case HID_RET_TIMEOUT: return "timeout"; #endif + default: + return "unknown error or timeout"; } return "unknown error"; } cDriverFutabaMDM166A::cDriverFutabaMDM166A(cDriverConfig * config) -: config(config) +: cDriver(config) , m_pDrawMem(0) , m_pVFDMem(0) { - oldConfig = new cDriverConfig(*config); m_nRefreshCounter = 0; lastIconState = 0; } -cDriverFutabaMDM166A::~cDriverFutabaMDM166A() -{ - delete oldConfig; -} - int cDriverFutabaMDM166A::Init() { // default values @@ -335,7 +334,7 @@ m_pDrawMem[n] = 0x00; } -void cDriverFutabaMDM166A::SetPixel(int x, int y) +void cDriverFutabaMDM166A::SetPixel(int x, int y, uint32_t data) { byte c; int n; @@ -357,9 +356,14 @@ n = x + ((y / 8) * width); c = 0x80 >> (y % 8); - m_pDrawMem[n] |= c; + //m_pDrawMem[n] |= c; + if (data == GRAPHLCD_White) + m_pDrawMem[n] |= c; + else + m_pDrawMem[n] &= (0xFF ^ c); } +#if 0 void cDriverFutabaMDM166A::Set8Pixels(int x, int y, byte data) { int n; @@ -373,6 +377,7 @@ SetPixel(x + n, y); } } +#endif void cDriverFutabaMDM166A::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/futabaMDM166A.h graphlcd-base-0.1.9+git20120310/glcddrivers/futabaMDM166A.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/futabaMDM166A.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/futabaMDM166A.h 2012-03-10 09:18:56.000000000 +0000 @@ -1,12 +1,15 @@ /* * GraphLCD driver library * - * (C) 2010 Andreas Brachold + * futatbaMDM166A.h - Futaba MDM166A LCD + * Output goes to a Futaba MDM166A LCD * * This file is released under the GNU General Public License. * * See the files README and COPYING for details. * + * (c) 2010 Andreas Brachold + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_FutabaMDM166A_H_ @@ -40,8 +43,6 @@ class cDriverFutabaMDM166A : public cDriver, cHIDQueue { - cDriverConfig * config; - cDriverConfig * oldConfig; unsigned char *m_pDrawMem; // the draw "memory" unsigned char *m_pVFDMem; // the double buffed display "memory" unsigned int m_iSizeYb; @@ -50,20 +51,19 @@ int CheckSetup(); protected: void ClearVFDMem(); - void SetPixel(int x, int y); void icons(unsigned int state); bool SendCmdClock(); bool SendCmdShutdown(); public: cDriverFutabaMDM166A(cDriverConfig * config); - virtual ~cDriverFutabaMDM166A(); virtual int Init(); virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, byte data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, byte data); virtual void Refresh(bool refreshAll = false); virtual void SetBrightness(unsigned int percent); diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/g15daemon.c graphlcd-base-0.1.9+git20120310/glcddrivers/g15daemon.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/g15daemon.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/g15daemon.c 2012-03-10 09:18:56.000000000 +0000 @@ -7,6 +7,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * +* (c) 2005-2010 Andreas Regel +* (c) 2011 Wolfgang Astleitner */ #include @@ -105,16 +107,10 @@ { cDriverG15daemon::cDriverG15daemon(cDriverConfig * config) -: config(config), +: cDriver(config), offbuff(0), sockfd(-1) { - oldConfig = new cDriverConfig(*config); -} - -cDriverG15daemon::~cDriverG15daemon() -{ - delete oldConfig; } int cDriverG15daemon::Init() @@ -180,7 +176,7 @@ return 0; } -void cDriverG15daemon::SetPixel(int x, int y) +void cDriverG15daemon::SetPixel(int x, int y, uint32_t data) { if (x >= width || y >= height) return; @@ -191,7 +187,7 @@ y = height - 1 - y; } - offbuff[x + (width * y)] = 1; + offbuff[x + (width * y)] = ( (data == GRAPHLCD_White) ? 1 : 0 ); } void cDriverG15daemon::Clear() @@ -199,6 +195,7 @@ memset(offbuff, 0, screensize); } +#if 0 void cDriverG15daemon::Set8Pixels(int x, int y, unsigned char data) { int n; @@ -208,9 +205,10 @@ for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GRAPHLCD_White); } } +#endif void cDriverG15daemon::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/g15daemon.h graphlcd-base-0.1.9+git20120310/glcddrivers/g15daemon.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/g15daemon.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/g15daemon.h 2012-03-10 09:18:56.000000000 +0000 @@ -4,6 +4,8 @@ * g15daemon.h - pseudo device for the g15daemon * Output goes to the g15daemon which then displays it * + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_G15DAEMON_H_ @@ -21,8 +23,6 @@ { private: unsigned char ** LCD; - cDriverConfig * config; - cDriverConfig * oldConfig; char *offbuff; int sockfd; long int screensize; @@ -30,17 +30,16 @@ int zoom; int CheckSetup(); - void SetPixel(int x, int y); public: cDriverG15daemon(cDriverConfig * config); - virtual ~cDriverG15daemon(); virtual int Init(); virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/gu126x64D-K610A4.c graphlcd-base-0.1.9+git20120310/glcddrivers/gu126x64D-K610A4.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/gu126x64D-K610A4.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/gu126x64D-K610A4.c 2012-03-10 09:18:56.000000000 +0000 @@ -18,7 +18,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2007 Alexander Rieger (Alexander.Rieger AT inka.de) + * (c) 2007 Alexander Rieger (Alexander.Rieger AT inka.de) + * (c) 2011 Wolfgang Astleitner */ #include @@ -90,9 +91,8 @@ //----------------------------------------------------------------------------- cDriverGU126X64D_K610A4::cDriverGU126X64D_K610A4(cDriverConfig * config) - : port (0) - , config (config) - , oldConfig (0) + : cDriver (config) + , port (0) , myNumRows (0) , myDrawMem (0) , myVFDMem (0) @@ -104,14 +104,8 @@ , myDataPendingCounter(0) , myLogFlags (0) { - oldConfig = new cDriverConfig(*config); } // cDriverGU126X64D_K610A4::cDriverGU126X64D_K610A4() -//----------------------------------------------------------------------------- -cDriverGU126X64D_K610A4::~cDriverGU126X64D_K610A4() -{ - delete oldConfig; -} // cDriverGU126X64D_K610A4::cDriverGU126X64D_K610A4() //----------------------------------------------------------------------------- int cDriverGU126X64D_K610A4::Init() @@ -417,7 +411,7 @@ } // cDriverGU126X64D_K610A4::write() //----------------------------------------------------------------------------- -void cDriverGU126X64D_K610A4::setPixel(int x, int y) +void cDriverGU126X64D_K610A4::SetPixel(int x, int y, uint32_t data) { if (!myDrawMem ) return; if (x >= width || x < 0) return; @@ -431,9 +425,13 @@ unsigned char c = 0x80 >> (y % 8); - myDrawMem[x][y/8] = myDrawMem[x][y/8] | c; -} // cDriverGU126X64D_K610A4::setPixel() + if (data == GRAPHLCD_White) + myDrawMem[x][y/8] |= c; + else + myDrawMem[x][y/8] &= ( 0xFF ^ c ); +} // cDriverGU126X64D_K610A4::SetPixel() +#if 0 //----------------------------------------------------------------------------- void cDriverGU126X64D_K610A4::Set8Pixels(int x, int y, unsigned char data) { @@ -444,10 +442,11 @@ { if ((data & (0x80 >> n)) != 0) // if bit is set { - setPixel(x + n, y); + setPixel(x + n, y, GRAPHLCD_White); } // if } // for } // cDriverGU126X64D_K610A4::Set8Pixels() +#endif //----------------------------------------------------------------------------- void cDriverGU126X64D_K610A4::Refresh(bool refreshAll) @@ -796,7 +795,7 @@ if (isLogEnabled(LL_VFD_CMD)) { - syslog(LOG_INFO, "-%2dB: WRITE_TEXT : '%s'", strlen(theText), theText); + syslog(LOG_INFO, "-%2dB: WRITE_TEXT : '%s'", (int)strlen(theText), theText); } // if for (const char *p = theText; *p != '\0'; ++p) diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/gu126x64D-K610A4.h graphlcd-base-0.1.9+git20120310/glcddrivers/gu126x64D-K610A4.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/gu126x64D-K610A4.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/gu126x64D-K610A4.h 2012-03-10 09:18:56.000000000 +0000 @@ -18,7 +18,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2007 Alexander Rieger (Alexander.Rieger AT inka.de) + * (c) 2007 Alexander Rieger (Alexander.Rieger AT inka.de) + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_GU126X64D_K610A4_H_ @@ -45,7 +46,6 @@ // constructor/destructor //--------------------------------------------------------------------------- cDriverGU126X64D_K610A4(cDriverConfig * config); - virtual ~cDriverGU126X64D_K610A4(); //--------------------------------------------------------------------------- // from cDriver @@ -54,7 +54,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel (int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); virtual void SetBrightness(unsigned int percent); @@ -68,7 +69,6 @@ , FONT_FIX_BIG }; - void setPixel (int x, int y); int cmdReset (); int cmdPower (bool fOn); @@ -108,9 +108,6 @@ //--------------------------------------------------------------------------- cParallelPort *port; - cDriverConfig *config; - cDriverConfig *oldConfig; - int myNumRows; unsigned char **myDrawMem; unsigned char **myVFDMem; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/gu140x32f.c graphlcd-base-0.1.9+git20120310/glcddrivers/gu140x32f.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/gu140x32f.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/gu140x32f.c 2012-03-10 09:18:56.000000000 +0000 @@ -14,7 +14,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003 Andreas Brachold + * (c) 2003 Andreas Brachold + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #include @@ -96,12 +98,10 @@ cDriverGU140X32F::cDriverGU140X32F(cDriverConfig * config) -: config(config), +: cDriver(config), m_pDrawMem(0), m_pVFDMem(0) { - oldConfig = new cDriverConfig(*config); - port = new cParallelPort(); m_nRefreshCounter = 0; @@ -110,7 +110,6 @@ cDriverGU140X32F::~cDriverGU140X32F() { delete port; - delete oldConfig; } int cDriverGU140X32F::Init() @@ -326,7 +325,7 @@ nSleepDeInit(); } -void cDriverGU140X32F::SetPixel(int x, int y) +void cDriverGU140X32F::SetPixel(int x, int y, uint32_t data) { unsigned char c; int n; @@ -348,9 +347,13 @@ n = x + ((y / 8) * width); c = 0x80 >> (y % 8); - m_pDrawMem[n] |= c; + if (data == GRAPHLCD_White) + m_pDrawMem[n] |= c; + else + m_pDrawMem[n] &= (0xFF ^ c); } +#if 0 void cDriverGU140X32F::Set8Pixels(int x, int y, unsigned char data) { int n; @@ -361,9 +364,10 @@ for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GRAPHLCD_White); } } +#endif void cDriverGU140X32F::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/gu140x32f.h graphlcd-base-0.1.9+git20120310/glcddrivers/gu140x32f.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/gu140x32f.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/gu140x32f.h 2012-03-10 09:18:56.000000000 +0000 @@ -14,7 +14,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003 Andreas Brachold + * (c) 2003 Andreas Brachold + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_GU140X32F_H_ @@ -37,9 +39,6 @@ cParallelPort * port; - cDriverConfig * config; - cDriverConfig * oldConfig; - int m_iSizeYb; int m_nRefreshCounter; unsigned char *m_pDrawMem; // the draw "memory" @@ -51,7 +50,6 @@ protected: void ClearVFDMem(); - void SetPixel(int x, int y); void Write(unsigned char nFlags, unsigned char bData, unsigned int nMicroSecBusyTime); public: @@ -62,7 +60,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); virtual void SetBrightness(unsigned int percent); diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/gu256x64-372.c graphlcd-base-0.1.9+git20120310/glcddrivers/gu256x64-372.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/gu256x64-372.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/gu256x64-372.c 2012-03-10 09:18:56.000000000 +0000 @@ -16,7 +16,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas 'randy' Weinberger (randy AT smue.org) + * (c) 2004-2011 Andreas 'randy' Weinberger (randy AT smue.org) + * (c) 2011 Wolfgang Astleitner */ #include @@ -83,10 +84,8 @@ cDriverGU256X64_372::cDriverGU256X64_372(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); - port = new cParallelPort(); m_nRefreshCounter = 0; @@ -94,7 +93,6 @@ cDriverGU256X64_372::~cDriverGU256X64_372() { - delete oldConfig; delete port; } @@ -345,7 +343,7 @@ nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); } -void cDriverGU256X64_372::SetPixel(int x, int y) +void cDriverGU256X64_372::SetPixel(int x, int y, uint32_t data) { unsigned char c; @@ -365,9 +363,13 @@ c = 0x80 >> (y % 8); - m_pDrawMem[x][y/8] = m_pDrawMem[x][y/8] | c; + if (data == GRAPHLCD_White) + m_pDrawMem[x][y/8] |= c; + else + m_pDrawMem[x][y/8] &= ( 0xFF ^ c ); } +#if 0 void cDriverGU256X64_372::Set8Pixels(int x, int y, unsigned char data) { int n; @@ -378,9 +380,10 @@ for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GRAPHLCD_White); } } +#endif void cDriverGU256X64_372::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/gu256x64-372.h graphlcd-base-0.1.9+git20120310/glcddrivers/gu256x64-372.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/gu256x64-372.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/gu256x64-372.h 2012-03-10 09:18:56.000000000 +0000 @@ -16,7 +16,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas 'randy' Weinberger (randy AT smue.org) + * (c) 2004-2011 Andreas 'randy' Weinberger (randy AT smue.org) + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_GU256X64_372_H_ @@ -34,9 +35,6 @@ { cParallelPort * port; - cDriverConfig * config; - cDriverConfig * oldConfig; - int m_iSizeYb; int m_nRefreshCounter; @@ -57,7 +55,6 @@ protected: void ClearVFDMem(); - void SetPixel(int x, int y); void GU256X64Cmd(unsigned char data); void GU256X64Data(unsigned char data); @@ -69,7 +66,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); virtual void SetBrightness(unsigned int percent); diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/gu256x64-3900.c graphlcd-base-0.1.9+git20120310/glcddrivers/gu256x64-3900.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/gu256x64-3900.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/gu256x64-3900.c 2012-03-10 09:18:56.000000000 +0000 @@ -20,7 +20,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Ralf Mueller (ralf AT bj-ig.de) + * (c) 2004 Ralf Mueller (ralf AT bj-ig.de) + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #include @@ -102,19 +104,12 @@ cDriverGU256X64_3900::cDriverGU256X64_3900(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); - portFd = -1; m_nRefreshCounter = 0; } -cDriverGU256X64_3900::~cDriverGU256X64_3900() -{ - delete oldConfig; -} - int cDriverGU256X64_3900::Init() { int x; @@ -503,7 +498,7 @@ WriteParallel(data); } -void cDriverGU256X64_3900::SetPixel(int x, int y) +void cDriverGU256X64_3900::SetPixel(int x, int y, uint32_t data) { unsigned char c; @@ -523,9 +518,13 @@ c = 0x80 >> (y % 8); - m_pDrawMem[x][y/8] = m_pDrawMem[x][y/8] | c; + if (data == GRAPHLCD_White) + m_pDrawMem[x][y/8] |= c; + else + m_pDrawMem[x][y/8] &= ( 0xFF ^ c ); } +#if 0 void cDriverGU256X64_3900::Set8Pixels(int x, int y, unsigned char data) { int n; @@ -536,9 +535,10 @@ for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GRAPHLCD_White); } } +#endif void cDriverGU256X64_3900::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/gu256x64-3900.h graphlcd-base-0.1.9+git20120310/glcddrivers/gu256x64-3900.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/gu256x64-3900.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/gu256x64-3900.h 2012-03-10 09:18:56.000000000 +0000 @@ -20,7 +20,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Ralf Mueller (ralf AT bj-ig.de) + * (c) 2004 Ralf Mueller (ralf AT bj-ig.de) + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_GU256X64_3900_H_ @@ -39,9 +41,6 @@ cParallelPort * port; int portFd; - cDriverConfig * config; - cDriverConfig * oldConfig; - int m_iSizeYb; int m_nRefreshCounter; int interface; @@ -59,7 +58,6 @@ protected: void ClearVFDMem(); - void SetPixel(int x, int y); int InitSerialPort(); int InitParallelPort(); void InitNormalDisplay(); @@ -70,13 +68,13 @@ void Write(unsigned char data); public: cDriverGU256X64_3900(cDriverConfig * config); - virtual ~cDriverGU256X64_3900(); virtual int Init(); virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); virtual void SetBrightness(unsigned int percent); diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/hd61830.c graphlcd-base-0.1.9+git20120310/glcddrivers/hd61830.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/hd61830.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/hd61830.c 2012-03-10 09:18:56.000000000 +0000 @@ -7,6 +7,8 @@ * to the COPYING file distributed with this package. * * (c) 2001-2004 Carsten Siebholz + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #include @@ -55,10 +57,8 @@ cDriverHD61830::cDriverHD61830(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); - port = new cParallelPort(); useSleepInit = false; @@ -70,7 +70,6 @@ cDriverHD61830::~cDriverHD61830() { delete port; - delete oldConfig; } int cDriverHD61830::Init() @@ -301,6 +300,29 @@ memset(newLCD[x], 0, height); } + +void cDriverHD61830::SetPixel(int x, int y, uint32_t data) +{ + if (x >= width || y >= height) + return; + + int pos = x % 8; + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + //} else { + pos = 7 - pos; // reverse bit position + } + + if (data == GRAPHLCD_White) + newLCD[x / 8][y] |= ( 1 << pos ); + else + newLCD[x / 8][y] &= ( 0xFF ^ ( 1 << pos ) ); +} + + +#if 0 void cDriverHD61830::Set8Pixels(int x, int y, unsigned char data) { if (x >= width || y >= height) @@ -319,6 +341,7 @@ newLCD[x / 8][y] = newLCD[x / 8][y] | data; } } +#endif void cDriverHD61830::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/hd61830.h graphlcd-base-0.1.9+git20120310/glcddrivers/hd61830.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/hd61830.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/hd61830.h 2012-03-10 09:18:56.000000000 +0000 @@ -7,6 +7,8 @@ * to the COPYING file distributed with this package. * * (c) 2001-2004 Carsten Siebholz + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_HD61830_H_ @@ -27,8 +29,6 @@ unsigned char ** newLCD; // wanted state unsigned char ** oldLCD; // current state - cDriverConfig * config; - cDriverConfig * oldConfig; int refreshCounter; long timeForPortCmdInNs; bool useSleepInit; @@ -45,7 +45,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/image.c graphlcd-base-0.1.9+git20120310/glcddrivers/image.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/image.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/image.c 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + Andreas 'randy' Weinberger */ #include @@ -23,14 +25,13 @@ { cDriverImage::cDriverImage(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); } cDriverImage::~cDriverImage() { - delete oldConfig; + DeInit(); } int cDriverImage::Init() @@ -50,12 +51,13 @@ } } - newLCD = new unsigned char[lineSize * height]; +// newLCD = new unsigned char[lineSize * height]; + newLCD = new uint32_t[width * height]; if (newLCD) - memset(newLCD, 0, lineSize * height); - oldLCD = new unsigned char[lineSize * height]; + memset(newLCD, 0, width * height); + oldLCD = new uint32_t[width * height]; if (oldLCD) - memset(oldLCD, 0, lineSize * height); + memset(oldLCD, 0, width * height); counter = 0; @@ -71,9 +73,15 @@ int cDriverImage::DeInit() { if (newLCD) + { delete[] newLCD; + newLCD = 0; + } if (oldLCD) + { delete[] oldLCD; + oldLCD = 0; + } return 0; } @@ -102,6 +110,7 @@ memset(newLCD, 0, lineSize * height); } +#if 0 void cDriverImage::Set8Pixels(int x, int y, unsigned char data) { if (x >= width || y >= height) @@ -120,6 +129,28 @@ newLCD[lineSize * y + x / 8] |= ReverseBits(data); } } +#endif + +void cDriverImage::SetPixel(int x, int y, uint32_t data) +{ + if (x >= width || y >= height) + return; + + int cols = (width + 7 ) >> 3; + int pos = x % 8; + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + } else { + pos = 7 - pos; // reverse bit position + } + + if (data == GRAPHLCD_White) + newLCD[y * cols + (x >> 3)] |= ( 1 << pos ); + else + newLCD[y * cols + (x >> 3)] &= ( 0xFF ^ ( 1 << pos) ); +} void cDriverImage::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/image.h graphlcd-base-0.1.9+git20120310/glcddrivers/image.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/image.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/image.h 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + Andreas 'randy' Weinberger */ #ifndef _GLCDDRIVERS_IMAGE_H_ @@ -24,10 +26,8 @@ class cDriverImage : public cDriver { private: - unsigned char * newLCD; - unsigned char * oldLCD; - cDriverConfig * config; - cDriverConfig * oldConfig; + uint32_t * newLCD; + uint32_t * oldLCD; int lineSize; int counter; @@ -41,7 +41,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/ks0108.c graphlcd-base-0.1.9+git20120310/glcddrivers/ks0108.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/ks0108.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/ks0108.c 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003 Andreas 'randy' Weinberger + * (c) 2003-2011 Andreas 'randy' Weinberger + * (c) 2011 Wolfgang Astleitner */ #include @@ -41,10 +42,8 @@ cDriverKS0108::cDriverKS0108(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); - port = new cParallelPort(); refreshCounter = 0; @@ -55,7 +54,6 @@ cDriverKS0108::~cDriverKS0108() { delete port; - delete oldConfig; } int cDriverKS0108::Init() @@ -420,6 +418,29 @@ memset(LCD[x], 0, height); } + +void cDriverKS0108::SetPixel(int x, int y, uint32_t data) +{ + if (x >= width || y >= height) + return; + + int pos = x % 8; + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + } else { + pos = 7 - pos; // reverse bit position + } + + if (data == GRAPHLCD_White) + LCD[x / 8][y] |= (1 << pos); + else + LCD[x / 8][y] &= ( 0xFF ^ (1 << pos) ); +} + + +#if 0 void cDriverKS0108::Set8Pixels(int x, int y, unsigned char data) { if (x >= width || y >= height) @@ -438,6 +459,7 @@ LCD[x / 8][y] = LCD[x / 8][y] | ReverseBits(data); } } +#endif void cDriverKS0108::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/ks0108.h graphlcd-base-0.1.9+git20120310/glcddrivers/ks0108.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/ks0108.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/ks0108.h 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003 Andreas 'randy' Weinberger + * (c) 2003-2011 Andreas 'randy' Weinberger + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_KS0108_H_ @@ -30,8 +31,6 @@ int refreshCounter; long timeForPortCmdInNs; long timeForLCDInNs; - cDriverConfig * config; - cDriverConfig * oldConfig; bool useSleepInit; int CheckSetup(); @@ -69,7 +68,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/Makefile graphlcd-base-0.1.9+git20120310/glcddrivers/Makefile --- graphlcd-base-0.2.0+git20101020/glcddrivers/Makefile 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/Makefile 2012-03-10 09:18:56.000000000 +0000 @@ -6,8 +6,8 @@ CXXFLAGS += -fPIC -VERMAJOR = 1 -VERMINOR = 0 +VERMAJOR = 2 +VERMINOR = 1 VERMICRO = 0 BASENAME = libglcddrivers.so @@ -25,6 +25,18 @@ DEFINES += -DHAVE_LIBHID endif + +ifeq ($(shell pkg-config --exists libusb && echo 1), 1) + DEFINES += -DHAVE_LIBUSB + ifdef HAVE_AX206DPF_EXPERIMENTAL + OBJS += ax206dpf.o + INCLUDES += $(shell pkg-config --cflags libusb) + LIBS += $(shell pkg-config --libs libusb) + DEFINES += -DHAVE_AX206DPF_EXPERIMENTAL + endif +endif + + ### Implicit rules: %.o: %.c diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/network.c graphlcd-base-0.1.9+git20120310/glcddrivers/network.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/network.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/network.c 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #include @@ -29,19 +30,13 @@ { cDriverNetwork::cDriverNetwork(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); childTid = 0; running = false; clientConnected = false; } -cDriverNetwork::~cDriverNetwork() -{ - delete oldConfig; -} - int cDriverNetwork::Init() { width = config->width; @@ -122,6 +117,29 @@ memset(newLCD, 0, lineSize * height); } + +void cDriverNetwork::SetPixel(int x, int y, uint32_t data) +{ + if (x >= width || y >= height) + return; + + int pos = x % 8; + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + } else { + pos = 7 - pos; // reverse bit position + } + + if (data == GRAPHLCD_White) + newLCD[lineSize * y + x / 8] |= (1 << pos); + else + newLCD[lineSize * y + x / 8] &= ( 0xFF ^ (1 << pos) ); +} + + +#if 0 void cDriverNetwork::Set8Pixels(int x, int y, unsigned char data) { if (x >= width || y >= height) @@ -140,6 +158,7 @@ newLCD[lineSize * y + x / 8] |= ReverseBits(data); } } +#endif void cDriverNetwork::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/network.h graphlcd-base-0.1.9+git20120310/glcddrivers/network.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/network.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/network.h 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_NETWORK_H_ @@ -28,8 +29,6 @@ private: unsigned char * newLCD; unsigned char * oldLCD; - cDriverConfig * config; - cDriverConfig * oldConfig; int lineSize; bool running; pthread_t childTid; @@ -41,13 +40,13 @@ public: cDriverNetwork(cDriverConfig * config); - virtual ~cDriverNetwork(); virtual int Init(); virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/noritake800.c graphlcd-base-0.1.9+git20120310/glcddrivers/noritake800.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/noritake800.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/noritake800.c 2012-03-10 09:18:56.000000000 +0000 @@ -27,7 +27,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Lucian Muresan + * (c) 2004-2011 Lucian Muresan + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #include @@ -89,7 +91,7 @@ #define SETPOSITION 0xff -cDriverNoritake800::cDriverNoritake800(cDriverConfig * config) +cDriverNoritake800::cDriverNoritake800(cDriverConfig * config) : cDriver(config) { int x = 0; m_bGraphScreen0_On = true; @@ -97,18 +99,15 @@ // default initilaization for the wiring m_nWiring = WIRING_LIQUIDMP3; - m_Config = config; - m_oldConfig = new cDriverConfig(* config); - m_pport = new cParallelPort(); m_nTimingAdjustCmd = 0; m_nRefreshCounter = 0; - width = m_Config->width; // 128 + width = config->width; // 128 if (width <= 0) width = 128; - height = m_Config->height; // 64 + height = config->height; // 64 if (height <= 0) height = 64; m_iSizeYb = (height + 7)/8; // 8 @@ -116,15 +115,15 @@ // // initialize wiring // - for (unsigned int i = 0; i < m_Config->options.size(); i++) + for (unsigned int i = 0; i < config->options.size(); i++) { - if (m_Config->options[i].name == "Wiring") + if (config->options[i].name == "Wiring") { - if (m_Config->options[i].value == kWiringLiquidmp3) + if (config->options[i].value == kWiringLiquidmp3) { m_nWiring = WIRING_LIQUIDMP3; } - else if (m_Config->options[i].value == kWiringMZ) + else if (config->options[i].value == kWiringMZ) { m_nWiring = WIRING_MZ; } @@ -170,19 +169,18 @@ int x; if (m_pVFDMem) - for (x = 0; x < (width + 7) / 8; x++) + for (x = 0; x < width; x++) { delete[] m_pVFDMem[x]; } delete[] m_pVFDMem; if (m_pDrawMem) - for (x = 0; x < (width + 7) / 8; x++) + for (x = 0; x < width; x++) { delete[] m_pDrawMem[x]; } delete[] m_pDrawMem; delete[] m_pWiringMaskCache; - delete m_oldConfig; delete m_pport; } @@ -211,27 +209,27 @@ int cDriverNoritake800::CheckSetup() { - if (m_Config->device != m_oldConfig->device || - m_Config->port != m_oldConfig->port || - m_Config->width != m_oldConfig->width || - m_Config->height != m_oldConfig->height) + if (config->device != oldConfig->device || + config->port != oldConfig->port || + config->width != oldConfig->width || + config->height != oldConfig->height) { DeInit(); Init(); return 0; } - if (m_Config->brightness != m_oldConfig->brightness) + if (config->brightness != oldConfig->brightness) { - m_oldConfig->brightness = m_Config->brightness; - SetBrightness(m_Config->brightness); + oldConfig->brightness = config->brightness; + SetBrightness(config->brightness); } - if (m_Config->upsideDown != m_oldConfig->upsideDown || - m_Config->invert != m_oldConfig->invert) + if (config->upsideDown != oldConfig->upsideDown || + config->invert != oldConfig->invert) { - m_oldConfig->upsideDown = m_Config->upsideDown; - m_oldConfig->invert = m_Config->invert; + oldConfig->upsideDown = config->upsideDown; + oldConfig->invert = config->invert; return 1; } return 0; @@ -242,23 +240,23 @@ int x; struct timeval tv1, tv2; - if (m_Config->device == "") + if (config->device == "") { // use DirectIO - if (m_pport->Open(m_Config->port) != 0) + if (m_pport->Open(config->port) != 0) return -1; uSleep(10); } else { // use ppdev - if (m_pport->Open(m_Config->device.c_str()) != 0) + if (m_pport->Open(config->device.c_str()) != 0) return -1; } if (nSleepInit() != 0) { - syslog(LOG_ERR, "%s: INFO: cannot change wait parameters Err: %s (cDriver::Init)\n", m_Config->name.c_str(), strerror(errno)); + syslog(LOG_ERR, "%s: INFO: cannot change wait parameters Err: %s (cDriver::Init)\n", config->name.c_str(), strerror(errno)); m_bSleepIsInit = false; } else @@ -268,21 +266,20 @@ // benchmark port access m_pport->Claim(); - syslog(LOG_DEBUG, "%s: benchmark started.\n", m_Config->name.c_str()); + syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str()); gettimeofday(&tv1, 0); - int nBenchFactor = 100000; - for (x = 0; x < nBenchFactor; x++) + int nBenchIterations = 10000; + for (x = 0; x < nBenchIterations; x++) { m_pport->WriteData(x % 0x100); } gettimeofday(&tv2, 0); nSleepDeInit(); - //m_nTimingAdjustCmd = ((tv2.tv_sec - tv1.tv_sec) * 10000 + (tv2.tv_usec - tv1.tv_usec)) / 1000; - m_nTimingAdjustCmd = long(double((tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec)) / double(nBenchFactor)); - syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", m_Config->name.c_str(), m_nTimingAdjustCmd); + // calculate port command duration in nanoseconds + m_nTimingAdjustCmd = long(double((tv2.tv_sec - tv1.tv_sec) * 1000000000 + (tv2.tv_usec - tv1.tv_usec) * 1000) / double(nBenchIterations)); + syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), m_nTimingAdjustCmd); m_pport->Release(); - // initialize display N800Cmd(Init800A); @@ -290,13 +287,13 @@ for (n=0; n < 15; n++) { N800Cmd(0x62); - nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); N800Cmd(n); - nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); N800Data(0xff); - nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); } - nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); N800Cmd(LAYERSOFF | LAYER0ON); // layer 0 of the graphic RAM on @@ -312,48 +309,51 @@ m_pport->Release(); - *m_oldConfig = *m_Config; + //*oldConfig = *config; // Set Display SetBrightness - SetBrightness(m_Config->brightness); + SetBrightness(config->brightness); // clear display ClearVFDMem(); Refresh(true); - syslog(LOG_INFO, "%s: initialization done.\n", m_Config->name.c_str()); + syslog(LOG_INFO, "%s: initialization done.\n", config->name.c_str()); return 0; } void cDriverNoritake800::Refresh(bool refreshAll) { - // - // for VFD displays, we can safely ignore refreshAll, as they are "sticky" - // int xb, yb; if (CheckSetup() > 0) - refreshAll = true; // we don't use it + refreshAll = true; if (!m_pVFDMem || !m_pDrawMem) return; -// // just refresh if the time needed between refreshes is up -// m_nRefreshCounter = (m_nRefreshCounter + 1) % m_Config->refreshDisplay; -// if(!m_nRefreshCounter) -// { + if (config->refreshDisplay > 0) + { + m_nRefreshCounter = (m_nRefreshCounter + 1) % config->refreshDisplay; + if (m_nRefreshCounter == 0) + refreshAll = true; + } + m_pport->Claim(); for (xb = 0; xb < width; ++xb) { for (yb = 0; yb < m_iSizeYb; ++yb) { - if (m_pVFDMem[xb][yb] != m_pDrawMem[xb][yb]) + // if differenet or explicitly refresh all + if ( m_pVFDMem[xb][yb] != m_pDrawMem[xb][yb] || + refreshAll ) { m_pVFDMem[xb][yb] = m_pDrawMem[xb][yb]; - // reset RefreshCounter - m_nRefreshCounter = 0; + // reset RefreshCounter if doing a full refresh + if (refreshAll) + m_nRefreshCounter = 0; // actually write to display N800WriteByte( - (m_pVFDMem[xb][yb]) ^ ((m_Config->invert != 0) ? 0xff : 0x00), + (m_pVFDMem[xb][yb]) ^ ((config->invert != 0) ? 0xff : 0x00), xb, yb, 0); @@ -361,7 +361,6 @@ } } m_pport->Release(); -// } } void cDriverNoritake800::N800Cmd(unsigned char data) @@ -373,13 +372,13 @@ m_pport->WriteControl(m_pWiringMaskCache[0x00]); // write to data port m_pport->WriteData(data); - //nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); // set /WR on the control port m_pport->WriteControl(m_pWiringMaskCache[VFDSGN_WR]); - //nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); // reset /WR on the control port m_pport->WriteControl(m_pWiringMaskCache[0x00]); - //nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); // set direction to "port_input" m_pport->WriteControl(LPT_CTL_HI_DIR | m_pWiringMaskCache[0x00]); } @@ -393,18 +392,18 @@ m_pport->WriteControl(m_pWiringMaskCache[VFDSGN_CD]); // write to data port m_pport->WriteData(data); - //nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); // set /WR on the control port m_pport->WriteControl(m_pWiringMaskCache[VFDSGN_CD | VFDSGN_WR]); - //nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); // reset /WR on the control port m_pport->WriteControl(m_pWiringMaskCache[VFDSGN_CD]); - //nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd); + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); // set direction to "port_input" m_pport->WriteControl(LPT_CTL_HI_DIR | m_pWiringMaskCache[0x00]); } -void cDriverNoritake800::SetPixel(int x, int y) +void cDriverNoritake800::SetPixel(int x, int y, uint32_t data) { unsigned char c; @@ -416,7 +415,7 @@ if (y >= height || y < 0) return; - if (m_Config->upsideDown) + if (config->upsideDown) { x = width - 1 - x; y = height - 1 - y; @@ -424,9 +423,13 @@ c = 0x80 >> (y % 8); - m_pDrawMem[x][y/8] |= c; + if (data == GRAPHLCD_White) + m_pDrawMem[x][y/8] |= c; + else + m_pDrawMem[x][y/8] &= ( 0xFF ^ c); } +#if 0 void cDriverNoritake800::Set8Pixels(int x, int y, unsigned char data) { int n; @@ -440,6 +443,7 @@ SetPixel(x + n, y); } } +#endif void cDriverNoritake800::SetBrightness(unsigned int percent) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/noritake800.h graphlcd-base-0.1.9+git20120310/glcddrivers/noritake800.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/noritake800.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/noritake800.h 2012-03-10 09:18:56.000000000 +0000 @@ -27,7 +27,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Lucian Muresan + * (c) 2004-2011 Lucian Muresan + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_NORITAKE800_H_ @@ -45,9 +47,6 @@ { cParallelPort * m_pport; - cDriverConfig * m_Config; - cDriverConfig * m_oldConfig; - int m_iSizeYb; int m_nRefreshCounter; int m_nWiring; @@ -80,8 +79,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void SetPixel(int x, int y); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); virtual void SetBrightness(unsigned int percent); diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/sed1330.c graphlcd-base-0.1.9+git20120310/glcddrivers/sed1330.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/sed1330.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/sed1330.c 2012-03-10 09:18:56.000000000 +0000 @@ -14,7 +14,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003 Roland Praml + * (c) 2003 Roland Praml + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #include @@ -129,10 +131,8 @@ cDriverSED1330::cDriverSED1330(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); - port = new cParallelPort(); refreshCounter = 0; @@ -141,7 +141,6 @@ cDriverSED1330::~cDriverSED1330() { delete port; - delete oldConfig; } int cDriverSED1330::Init() @@ -539,6 +538,29 @@ memset(newLCD[x], 0, height); } + +void cDriverSED1330::SetPixel(int x, int y, uint32_t data) +{ + if (x >= width || y >= height) + return; + + int pos = x % 8; + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + } else { + pos = 7 - pos; // reverse bit position + } + + if (data == GRAPHLCD_White) + newLCD[x / 8][y] |= (1 << pos); + else + newLCD[x / 8][y] &= ( 0xFF ^ (1 << pos) ); +} + + +#if 0 void cDriverSED1330::Set8Pixels(int x, int y, unsigned char data) { if (x >= width || y >= height) @@ -557,6 +579,7 @@ newLCD[x / 8][y] = newLCD[x / 8][y] | ReverseBits(data); } } +#endif void cDriverSED1330::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/sed1330.h graphlcd-base-0.1.9+git20120310/glcddrivers/sed1330.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/sed1330.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/sed1330.h 2012-03-10 09:18:56.000000000 +0000 @@ -14,7 +14,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003 Roland Praml + * (c) 2003 Roland Praml + * (c) 2005-2010 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_SED1330_H_ @@ -37,8 +39,6 @@ unsigned char ** oldLCD; // current state int refreshCounter; long timeForPortCmdInNs; - cDriverConfig * config; - cDriverConfig * oldConfig; bool useSleepInit; int oscillatorFrequency; @@ -69,7 +69,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/sed1520.c graphlcd-base-0.1.9+git20120310/glcddrivers/sed1520.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/sed1520.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/sed1520.c 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003 Andreas 'randy' Weinberger + * (c) 2003-2011 Andreas 'randy' Weinberger + * (c) 2011 Wolfgang Astleitner */ #include @@ -45,10 +46,8 @@ cDriverSED1520::cDriverSED1520(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); - port = new cParallelPort(); refreshCounter = 0; @@ -57,7 +56,6 @@ cDriverSED1520::~cDriverSED1520() { delete port; - delete oldConfig; } int cDriverSED1520::Init() @@ -303,6 +301,29 @@ memset(LCD[x], 0, height); } + +void cDriverSED1520::SetPixel (int x, int y, uint32_t data) +{ + if (x >= width || y >= height) + return; + + int pos = x % 8; + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + } else { + pos = 7 - pos; // reverse bit position + } + + if (data == GRAPHLCD_White) + LCD[x / 8][y] |= ( 1 << pos ); + else + LCD[x / 8][y] &= (0xFF ^ ( 1 << pos )); +} + + +#if 0 void cDriverSED1520::Set8Pixels (int x, int y, unsigned char data) { if (x >= width || y >= height) @@ -321,6 +342,7 @@ LCD[x / 8][y] = LCD[x / 8][y] | ReverseBits(data); } } +#endif void cDriverSED1520::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/sed1520.h graphlcd-base-0.1.9+git20120310/glcddrivers/sed1520.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/sed1520.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/sed1520.h 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003 Andreas 'randy' Weinberger + * (c) 2003-2011 Andreas 'randy' Weinberger + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_SED1520_H_ @@ -29,8 +30,6 @@ unsigned char ** LCD_page; // paged lcd display "memory" int refreshCounter; long timeForPortCmdInNs; - cDriverConfig * config; - cDriverConfig * oldConfig; bool useSleepInit; int SEAD; @@ -63,7 +62,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/serdisp.c graphlcd-base-0.1.9+git20120310/glcddrivers/serdisp.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/serdisp.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/serdisp.c 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,7 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003-2010 Wolfgang Astleitner + * (c) 2003-2012 Wolfgang Astleitner */ #include @@ -19,6 +19,11 @@ #include "config.h" #include "serdisp.h" +// for memcpy +#include + +#include + #define SERDISP_VERSION(a,b) ((long)(((a) << 8) + (b))) #define SERDISP_VERSION_GET_MAJOR(_c) ((int)( (_c) >> 8 )) #define SERDISP_VERSION_GET_MINOR(_c) ((int)( (_c) & 0xFF )) @@ -29,23 +34,21 @@ #define FEATURE_BACKLIGHT 0x03 #define FEATURE_ROTATE 0x04 -#define SD_COL_BLACK 0xFF000000 -#define SD_COL_WHITE 0xFFFFFFFF +// taken from serdisp_gpevents.h +#define SDGPT_SIMPLETOUCH 0x10 /* simple touch screen event, type: SDGP_evpkt_simpletouch_t */ namespace GLCD { -cDriverSerDisp::cDriverSerDisp(cDriverConfig * config) -: config(config) -{ - oldConfig = new cDriverConfig(*config); +static void wrapEventListener(void* dd, SDGP_event_t* recylce); + +static std::map touchEvents; - dd = (void *) NULL; -} -cDriverSerDisp::~cDriverSerDisp(void) +cDriverSerDisp::cDriverSerDisp(cDriverConfig * config) +: cDriver(config) { - delete oldConfig; + dd = (void *) NULL; } int cDriverSerDisp::Init(void) @@ -58,10 +61,27 @@ std::string optionstring = ""; std::string wiringstring; + int chk_major = 0; + std::string libname = ""; // dynamically load serdisplib using dlopen() & co. + sdhnd = NULL; + chk_major = 3; // max major version to check - sdhnd = dlopen("libserdisp.so", RTLD_LAZY); + while ( ! sdhnd && chk_major > 0) { + libname = "libserdisp.so."; + libname.push_back (chk_major + '0'); + sdhnd = dlopen(libname.c_str(), RTLD_LAZY); + if (!sdhnd) { // try /usr/local/lib + libname.insert(0, "/usr/local/lib/"); + sdhnd = dlopen(libname.c_str(), RTLD_LAZY); + } + chk_major --; + } + + if (!sdhnd) { // try libserdisp.so without major version + sdhnd = dlopen("libserdisp.so", RTLD_LAZY); + } if (!sdhnd) { // try /usr/local/lib sdhnd = dlopen("/usr/local/lib/libserdisp.so", RTLD_LAZY); } @@ -76,102 +96,63 @@ /* pre-init some flags, function pointers, ... */ supports_options = 0; - fg_colour = 1; - bg_colour = -1; + fgcol = GRAPHLCD_Black; /* set foreground colour to black */ + bgcol = GRAPHLCD_ERRCOL; // get serdisp version fp_serdisp_getversioncode = (long int (*)()) dlsym(sdhnd, "serdisp_getversioncode"); if (dlerror()) { // no serdisp_getversioncode() -> version of serdisplib is < 1.95 - syslog(LOG_DEBUG, "%s: INFO: symbol serdisp_getversioncode unknown: autodetecting pre 1.95 serdisplib version (cDriver::Init)\n", - config->name.c_str()); - - fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open"); - if (dlerror()) { // no SDCONN_open() -> version of serdisplib is < 1.93 - serdisp_version = SERDISP_VERSION(1,92); - syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version <= 1.92 (cDriver::Init)\n", config->name.c_str()); - - fp_PP_open = (void*(*)(const char*))dlsym(sdhnd, "PP_open"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "PP_open", errmsg); - return -1; - } - fp_PP_close = (void*(*)(void*))dlsym(sdhnd, "PP_close"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "PP_close", errmsg); - return -1; - } - } else { - serdisp_version = SERDISP_VERSION(1,94); // no serdisp_getversioncode, but SDCONN_open: 1.93 or 1.94 - syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version 1.93 or 1.94 (cDriver::Init)\n", config->name.c_str()); + syslog(LOG_ERR, "%s: error: serdisplib version >= 1.95 required\n", config->name.c_str()); + return -1; + } - fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_quit", errmsg); - return -1; - } - } + serdisp_version = fp_serdisp_getversioncode(); + syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version %d.%d (cDriver::Init)\n", + config->name.c_str(), SERDISP_VERSION_GET_MAJOR(serdisp_version), SERDISP_VERSION_GET_MINOR(serdisp_version)); - fp_serdisp_setpixcol = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setpixel"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_setpixel", errmsg); - return -1; - } - fg_colour = 1; /* set foreground to 'pixel on' */ - } else { // serdisp version >= 1.95 - serdisp_version = fp_serdisp_getversioncode(); - syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version %d.%d (cDriver::Init)\n", - config->name.c_str(), SERDISP_VERSION_GET_MAJOR(serdisp_version), SERDISP_VERSION_GET_MINOR(serdisp_version)); + fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open"); + if ( (errmsg = dlerror()) != NULL ) { // should not happen + syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", + config->name.c_str(), "SDCONN_open", errmsg); + return -1; + } + fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit"); + if ( (errmsg = dlerror()) != NULL ) { // should not happen + syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", + config->name.c_str(), "serdisp_quit", errmsg); + return -1; + } + fp_serdisp_setcolour = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setcolour"); + if ( (errmsg = dlerror()) != NULL ) { // should not happen + syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", + config->name.c_str(), "serdisp_setcolour", errmsg); + return -1; + } + if (serdisp_version >= SERDISP_VERSION(1,96) ) { + supports_options = 1; - fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open"); + fp_serdisp_isoption = (int (*)(void*, const char*)) dlsym(sdhnd, "serdisp_isoption"); if ( (errmsg = dlerror()) != NULL ) { // should not happen syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "SDCONN_open", errmsg); + config->name.c_str(), "serdisp_isoption", errmsg); return -1; } - fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit"); + fp_serdisp_setoption = (void (*)(void*, const char*, long int)) dlsym(sdhnd, "serdisp_setoption"); if ( (errmsg = dlerror()) != NULL ) { // should not happen syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_quit", errmsg); + config->name.c_str(), "serdisp_setoption", errmsg); return -1; } - fp_serdisp_setpixcol = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setcolour"); + fp_serdisp_getoption = (long int (*)(void*, const char*, int*)) dlsym(sdhnd, "serdisp_getoption"); if ( (errmsg = dlerror()) != NULL ) { // should not happen syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_setcolour", errmsg); + config->name.c_str(), "serdisp_getoption", errmsg); return -1; } - fg_colour = SD_COL_BLACK; /* set foreground colour to black */ - - if (serdisp_version >= SERDISP_VERSION(1,96) ) { - supports_options = 1; - - fp_serdisp_isoption = (int (*)(void*, const char*)) dlsym(sdhnd, "serdisp_isoption"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_isoption", errmsg); - return -1; - } - fp_serdisp_setoption = (void (*)(void*, const char*, long int)) dlsym(sdhnd, "serdisp_setoption"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_setoption", errmsg); - return -1; - } - fp_serdisp_getoption = (long int (*)(void*, const char*, int*)) dlsym(sdhnd, "serdisp_getoption"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_getoption", errmsg); - return -1; - } - } /* >= 1.96 */ - } + } /* >= 1.96 */ // load other symbols that will be required fp_serdisp_init = (void*(*)(void*, const char*, const char*)) dlsym(sdhnd, "serdisp_init"); @@ -230,6 +211,24 @@ return -1; } + fp_serdisp_getcolours = (int (*)(void*)) dlsym(sdhnd, "serdisp_getcolours"); + if ( (errmsg = dlerror()) != NULL ) { // should not happen + syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", + config->name.c_str(), "serdisp_getcolours", errmsg); + return -1; + } + + // don't care if the following functions are not available + fp_serdisp_getdepth = (int (*)(void*)) dlsym(sdhnd, "serdisp_getdepth"); + + fp_SDGPI_search = (uint8_t (*)(void*, const char*)) dlsym(sdhnd, "SDGPI_search"); + fp_SDGPI_isenabled = (int (*)(void*, uint8_t)) dlsym(sdhnd, "SDGPI_isenabled"); + fp_SDGPI_enable = (int (*)(void*, uint8_t, int)) dlsym(sdhnd, "SDGPI_enable"); + fp_SDEVLP_add_listener = (int (*)(void*, uint8_t, fp_eventlistener_t)) dlsym(sdhnd, "SDEVLP_add_listener"); + fp_serdisp_defaultdevice = (const char* (*)(const char*)) dlsym(sdhnd, "serdisp_defaultdevice"); + + + // done loading all required symbols // setting up the display @@ -245,12 +244,12 @@ } else if (config->options[i].name == "Wiring") { wiringstring = config->options[i].value; } else if (config->options[i].name == "FGColour") { - fg_colour = strtoul(config->options[i].value.c_str(), (char **)NULL, 0); - fg_colour |= 0xFF000000L; /* force alpha to 0xFF */ + fgcol = (uint32_t)strtoul(config->options[i].value.c_str(), (char **)NULL, 0); + fgcol |= 0xFF000000; /* force alpha to 0xFF */ fg_forced = 1; } else if (config->options[i].name == "BGColour") { - bg_colour = strtoul(config->options[i].value.c_str(), (char **)NULL, 0); - bg_colour |= 0xFF000000L; /* force alpha to 0xFF */ + bgcol = (uint32_t)strtoul(config->options[i].value.c_str(), (char **)NULL, 0); + bgcol |= 0xFF000000; /* force alpha to 0xFF */ bg_forced = 1; } } @@ -266,22 +265,13 @@ } - if (config->device == "") + if (config->device == "" && config->port > 0) /* port will only be used if device is not set */ { // use DirectIO - - // neither device nor port is set - if (config->port == 0) - return -1; - char temp[10]; snprintf(temp, 8, "0x%x", config->port); - if (serdisp_version < SERDISP_VERSION(1,93) ) { - sdcd = fp_PP_open(temp); - } else { - sdcd = fp_SDCONN_open(temp); - } + sdcd = fp_SDCONN_open(temp); if (sdcd == 0) { syslog(LOG_ERR, "%s: error: unable to open port 0x%x for display %s. (cDriver::Init)\n", @@ -293,9 +283,13 @@ } else { - // use ppdev - if (serdisp_version < SERDISP_VERSION(1,93) ) { - sdcd = fp_PP_open(config->device.c_str()); + if (config->device == "") { + if (fp_serdisp_defaultdevice) { // supported only in serdisplib >= v2.00 + sdcd = fp_SDCONN_open(fp_serdisp_defaultdevice(controller.c_str())); + } else { + // neither device nor port is set and getting default device expression is not supported -> exit + return -1; + } } else { sdcd = fp_SDCONN_open(config->device.c_str()); } @@ -307,10 +301,7 @@ } } - if (serdisp_version < SERDISP_VERSION(1,95) ) - dd = fp_serdisp_init(sdcd, controller.c_str(), ""); - else - dd = fp_serdisp_init(sdcd, controller.c_str(), optionstring.c_str()); + dd = fp_serdisp_init(sdcd, controller.c_str(), optionstring.c_str()); if (!dd) { @@ -322,9 +313,9 @@ // self-emitting displays (like OLEDs): default background colour => black if ( supports_options && fp_serdisp_isoption(dd, "SELFEMITTING") && (fp_serdisp_getoption(dd, "SELFEMITTING", 0)) ) { if (!bg_forced) - bg_colour = SD_COL_BLACK; /* set background colour to black */ + bgcol = GRAPHLCD_Black; /* set background colour to black */ if (!fg_forced) - fg_colour = SD_COL_WHITE; /* set foreground colour to white */ + fgcol = GRAPHLCD_White; /* set foreground colour to white */ } width = config->width; @@ -367,21 +358,27 @@ // clear display Clear(); + touchEvent = new tTouchEvent; + touchEvent->simpleTouchChanged = false; + touchEvents[dd] = touchEvent; + syslog(LOG_INFO, "%s: SerDisp with %s initialized.\n", config->name.c_str(), controller.c_str()); return 0; } int cDriverSerDisp::DeInit(void) { - if (serdisp_version < SERDISP_VERSION(1,93) ) { - fp_serdisp_close(dd); - fp_PP_close(sdcd); - sdcd = NULL; - } else { - //fp_serdisp_quit(dd); - /* use serdisp_close instead of serdisp_quit so that showpic and showtext are usable together with serdisplib */ - fp_serdisp_close(dd); - } + if (!dd) + return 0; + + touchEvents.erase(dd); + delete touchEvent; + touchEvent = NULL; + + //fp_serdisp_quit(dd); + /* use serdisp_close instead of serdisp_quit so that showpic and showtext are usable together with serdisplib */ + fp_serdisp_close(dd); + (int) dlclose(sdhnd); sdhnd = NULL; @@ -434,6 +431,7 @@ update = true; } +#if 0 /* driver dependend options */ if ( supports_options ) { for (unsigned int i = 0; i < config->options.size(); i++) { @@ -448,7 +446,7 @@ } } } - +#endif if (update) return 1; @@ -457,16 +455,17 @@ void cDriverSerDisp::Clear(void) { - if (bg_colour == -1) + if (bgcol == GRAPHLCD_ERRCOL) // bgcol not set fp_serdisp_clearbuffer(dd); - else { /* if bg_colour is set, draw background 'by hand' */ + else { /* if bgcol is set, draw background 'by hand' */ int x,y; for (y = 0; y < fp_serdisp_getheight(dd); y++) for (x = 0; x < fp_serdisp_getwidth(dd); x++) - fp_serdisp_setpixcol(dd, x, y, bg_colour); /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */ + fp_serdisp_setcolour(dd, x, y, (long)bgcol); } } +#if 0 void cDriverSerDisp::Set8Pixels(int x, int y, unsigned char data) { int i, start, pixel; @@ -476,12 +475,50 @@ for (i = 0; i < 8; i++) { pixel = data & (1 << i); - if (pixel) - fp_serdisp_setpixcol(dd, start + i, y, fg_colour); /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */ - else if (!pixel && bg_colour != -1) /* if bg_colour is set: use it if pixel is not set */ - fp_serdisp_setpixcol(dd, start + i, y, bg_colour); /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */ + if (pixel) { + SetPixel(start + i, y, (long)fgcol); + } else if (!pixel && bgcol != GRAPHLCD_ERRCOL) { /* if bgcol is set: use it if pixel is not set */ + SetPixel(start + i, y, (long)bgcol); + } } } +#endif + +void cDriverSerDisp::SetPixel(int x, int y, uint32_t data) +{ + fp_serdisp_setcolour(dd, x, y, (long)data); +} + +#if 0 +// temporarily overwrite SetScreen() until problem with 'to Clear() or not to Clear()' is solved +void cDriverSerDisp::SetScreen(const unsigned char * data, int wid, int hgt, int lineSize) +{ + int x, y; + + if (wid > width) + wid = width; + if (hgt > height) + hgt = height; + + //Clear(); + if (data) + { + for (y = 0; y < hgt; y++) + { + for (x = 0; x < (wid / 8); x++) + { + Set8Pixels(x * 8, y, data[y * lineSize + x]); + } + if (width % 8) + { + Set8Pixels((wid / 8) * 8, y, data[y * lineSize + wid / 8] & bitmaskl[wid % 8 - 1]); + } + } + } else { + Clear(); + } +} +#endif void cDriverSerDisp::Refresh(bool refreshAll) { @@ -495,9 +532,99 @@ } void cDriverSerDisp::SetBrightness(unsigned int percent) -{ - if ( supports_options && (fp_serdisp_isoption(dd, "BRIGHTNESS") == 1) ) /* if == 1: option is existing AND r/w */ - fp_serdisp_setoption(dd, "BRIGHTNESS", (long)percent); +{ + if ( dd && supports_options && (fp_serdisp_isoption(dd, "BRIGHTNESS") == 1) ) /* if == 1: option is existing AND r/w */ + fp_serdisp_setoption(dd, "BRIGHTNESS", (long)percent); +} + +uint32_t cDriverSerDisp::GetDefaultBackgroundColor(void) { + if ( dd && supports_options && fp_serdisp_isoption(dd, "SELFEMITTING") && (fp_serdisp_getoption(dd, "SELFEMITTING", 0)) ) { + return GRAPHLCD_Black; + } + return GRAPHLCD_White; +} + + +bool cDriverSerDisp::SetFeature (const std::string & Feature, int value) +{ + if (dd && (strcasecmp(Feature.c_str(), "TOUCHSCREEN") == 0 || strcasecmp(Feature.c_str(), "TOUCH") == 0)) { + if (fp_SDGPI_search && fp_SDGPI_isenabled && fp_SDGPI_enable) { + uint8_t gpid = fp_SDGPI_search(dd, Feature.c_str()); + if (gpid == 0xFF) + return false; + + int ena = fp_SDGPI_isenabled(dd, gpid); + bool enable = (value == 1) ? true : false; + if (ena == enable) { // already enabled or disabled + return true; + } else { + bool rc = (fp_SDGPI_enable(dd, gpid, ((enable) ? 1 : 0)) >= 0) ? true : false; + + if (enable && rc && fp_SDEVLP_add_listener) { + fp_SDEVLP_add_listener(dd, gpid, wrapEventListener); + } + return true; + } + } + } + return false; +} + +bool cDriverSerDisp::GetDriverFeature (const std::string & Feature, int & value) { + if (dd) { + if (strcasecmp(Feature.c_str(), "depth") == 0) { + value = fp_serdisp_getdepth(dd); + return true; + } else if (strcasecmp(Feature.c_str(), "ismonochrome") == 0) { + value = (fp_serdisp_getdepth(dd) == 1) ? 1 : 0; + return true; + } else if (strcasecmp(Feature.c_str(), "isgreyscale") == 0 || strcasecmp(Feature.c_str(), "isgrayscale") == 0) { + value = (fp_serdisp_getdepth(dd) > 1 && fp_serdisp_getdepth(dd) < 8) ? 1 : 0; + return true; + } else if (strcasecmp(Feature.c_str(), "iscolour") == 0 || strcasecmp(Feature.c_str(), "iscolor") == 0) { + value = (fp_serdisp_getdepth(dd) >= 8) ? 1 : 0; + return true; + } else if (strcasecmp(Feature.c_str(), "touch") == 0 || strcasecmp(Feature.c_str(), "touchscreen") == 0) { + if (fp_SDGPI_search && fp_SDGPI_isenabled) { + uint8_t gpid = fp_SDGPI_search(dd, Feature.c_str()); + value = (gpid != 0xFF && fp_SDGPI_isenabled(dd, gpid)) ? 1 : 0; + } + return true; + } + } + value = 0; + return false; +} + +cGLCDEvent * cDriverSerDisp::GetEvent(void) { + tTouchEvent* tev = touchEvents[dd]; + if (tev && tev->simpleTouchChanged == false) + return NULL; + + cSimpleTouchEvent * ev = new cSimpleTouchEvent(); + + ev->x = tev->simpleTouchX; + ev->y = tev->simpleTouchY; + ev->touch = tev->simpleTouchT; + tev->simpleTouchChanged = false; + + return ev; +} + +static void wrapEventListener(void* dd, SDGP_event_t* event) { + if (!event) return; + if (event->type == SDGPT_SIMPLETOUCH) { + SDGP_evpkt_simpletouch_t simpletouch; + memcpy(&simpletouch, &event->data, sizeof(SDGP_evpkt_simpletouch_t)); + + tTouchEvent* tev = touchEvents[dd]; + if (tev) { + tev->simpleTouchChanged = true; + tev->simpleTouchX = simpletouch.norm_x; + tev->simpleTouchY = simpletouch.norm_y; + tev->simpleTouchT = simpletouch.norm_touch; + } + } } } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/serdisp.h graphlcd-base-0.1.9+git20120310/glcddrivers/serdisp.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/serdisp.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/serdisp.h 2012-03-10 09:18:56.000000000 +0000 @@ -7,32 +7,70 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003-2010 Wolfgang Astleitner + * (c) 2003-2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_SERDISP_H_ #define _GLCDDRIVERS_SERDISP_H_ #include "driver.h" - +#include namespace GLCD { +/* event-type for GPIs, GPOs, and data exchange messages. min. size: 16 byte, max size: 12 + 64) */ +typedef struct SDGP_event_s { /* 16 to 78 bytes */ + /* byte 0 */ + uint8_t type; /* one of SDGPT_* */ + uint8_t cmdid; /* command-ID (one of SD_CMD_*) */ + uint8_t devid; /* device ID, 0 == local */ + uint8_t subid; /* gp-ID or page-ID */ + /* byte 4 */ + struct timeval timestamp; /* timestamp (8 bytes) */ + /* byte 12 */ + union { + int32_t value; /* if single value event: value */ + struct { /* if streaming event or package: */ + uint16_t length; /* length of stream if known or 0 if some stop tag is used */ + uint8_t word_size; /* stream elements are bytes/chars (0 or 1), shorts (2), or longs (4) */ + uint8_t _reserved; /* reserved for later use */ + }; + uint8_t data[64]; /* if data-package type: max. 64 byte payload */ + }; +} SDGP_event_t; + +/* event-payload-type for simple touchscreen events (no multitouch or similar) */ +typedef struct SDGP_evpkt_simpletouch_s { /* 16 bytes */ + /* 12 bytes */ + int16_t raw_x; /* raw coordinate X */ + int16_t raw_y; /* raw coordinate Y */ + int16_t raw_touch; /* raw touch value */ + int16_t norm_x; /* normalised coordinate X (norm_x <= dd->width) */ + int16_t norm_y; /* normalised coordinate Y (norm_y <= dd->height) */ + int16_t norm_touch; /* normalised touch value */ +} SDGP_evpkt_simpletouch_t; + + +typedef struct { + bool simpleTouchChanged; + int simpleTouchX; + int simpleTouchY; + int simpleTouchT; +} tTouchEvent; + + +typedef void (*fp_eventlistener_t) (void* dd, SDGP_event_t* recylce); + class cDriverConfig; class cDriverSerDisp : public cDriver { private: - cDriverConfig * config; - cDriverConfig * oldConfig; - long serdisp_version; int supports_options; - long fg_colour; - long bg_colour; void* sdhnd; // serdisplib handle void* dd; // display descriptor @@ -42,39 +80,57 @@ void* (*fp_SDCONN_open) (const char sdcdev[]); - void* (*fp_PP_open) (const char sdcdev[]); - void* (*fp_PP_close) (void* sdcd); - void* (*fp_serdisp_init) (void* sdcd, const char dispname[], const char extra[]); void (*fp_serdisp_rewrite) (void* dd); void (*fp_serdisp_update) (void* dd); void (*fp_serdisp_clearbuffer) (void* dd); - void (*fp_serdisp_setpixcol) (void* dd, int x, int y, long colour); // serdisp_setpixel or serdisp_setcolour + void (*fp_serdisp_setcolour) (void* dd, int x, int y, long colour); int (*fp_serdisp_feature) (void* dd, int feature, int value); int (*fp_serdisp_isoption) (void* dd, const char* optionname); void (*fp_serdisp_setoption) (void* dd, const char* optionname, long value); long (*fp_serdisp_getoption) (void* dd, const char* optionname, int* typesize); int (*fp_serdisp_getwidth) (void* dd); int (*fp_serdisp_getheight) (void* dd); + int (*fp_serdisp_getcolours) (void* dd); + int (*fp_serdisp_getdepth) (void* dd); void (*fp_serdisp_quit) (void* dd); void (*fp_serdisp_close) (void* dd); + uint8_t (*fp_SDGPI_search) (void* dd, const char* gpname); + int (*fp_SDGPI_isenabled) (void* dd, uint8_t gpid); + int (*fp_SDGPI_enable) (void* dd, uint8_t gpid, int enable); + int (*fp_SDEVLP_add_listener) (void* dd, uint8_t gpid, fp_eventlistener_t eventlistener ); + const char* + (*fp_serdisp_defaultdevice) (const char* dispname); int CheckSetup(); + void eventListener (void* dd, SDGP_event_t* recycle); + + tTouchEvent* touchEvent; + +protected: + virtual bool GetDriverFeature (const std::string & Feature, int & value); + virtual uint32_t GetDefaultBackgroundColor(void); + public: cDriverSerDisp(cDriverConfig * config); - virtual ~cDriverSerDisp(); virtual int Init(); virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + virtual void Refresh(bool refreshAll = false); virtual void SetBrightness(unsigned int percent); + + virtual bool SetFeature (const std::string & Feature, int value); + + virtual cGLCDEvent * GetEvent(void); + }; +} // end of namespace #endif -} // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/simlcd.c graphlcd-base-0.1.9+git20120310/glcddrivers/simlcd.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/simlcd.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/simlcd.c 2012-03-10 09:18:56.000000000 +0000 @@ -9,6 +9,8 @@ * to the COPYING file distributed with this package. * * (c) 2001-2004 Carsten Siebholz + * (c) 2011 Dirk Heiser + * (c) 2011 Wolfgang Astleitner */ #include @@ -19,22 +21,22 @@ #include "config.h" #include "simlcd.h" +#define DISPLAY_REFRESH_FILE "/tmp/simlcd.sem" +#define DISPLAY_DATA_FILE "/tmp/simlcd.dat" +#define TOUCH_REFRESH_FILE "/tmp/simtouch.sem" +#define TOUCH_DATA_FILE "/tmp/simtouch.dat" -namespace GLCD -{ +#define FG_CHAR "#" +#define BG_CHAR "." -cDriverSimLCD::cDriverSimLCD(cDriverConfig * config) -: config(config) +namespace GLCD { - oldConfig = new cDriverConfig(*config); -} -cDriverSimLCD::~cDriverSimLCD() +cDriverSimLCD::cDriverSimLCD(cDriverConfig * config) : cDriver(config) { - delete oldConfig; } -int cDriverSimLCD::Init() +int cDriverSimLCD::Init(void) { width = config->width; if (width <= 0) @@ -51,13 +53,13 @@ } // setup lcd array - LCD = new unsigned char *[(width + 7) / 8]; + LCD = new uint32_t *[width]; if (LCD) { - for (int x = 0; x < (width + 7) / 8; x++) + for (int x = 0; x < width; x++) { - LCD[x] = new unsigned char[height]; - memset(LCD[x], 0, height); + LCD[x] = new uint32_t[height]; + //memset(LCD[x], 0, height); } } @@ -70,12 +72,12 @@ return 0; } -int cDriverSimLCD::DeInit() +int cDriverSimLCD::DeInit(void) { // free lcd array if (LCD) { - for (int x = 0; x < (width + 7) / 8; x++) + for (int x = 0; x < width; x++) { delete[] LCD[x]; } @@ -85,7 +87,7 @@ return 0; } -int cDriverSimLCD::CheckSetup() +int cDriverSimLCD::CheckSetup(void) { if (config->width != oldConfig->width || config->height != oldConfig->height) @@ -105,29 +107,29 @@ return 0; } -void cDriverSimLCD::Clear() +void cDriverSimLCD::Clear(void) { - for (int x = 0; x < (width + 7) / 8; x++) - memset(LCD[x], 0, height); + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + LCD[x][y] = GRAPHLCD_White; + } + } } -void cDriverSimLCD::Set8Pixels(int x, int y, unsigned char data) +void cDriverSimLCD::SetPixel(int x, int y, uint32_t data) { if (x >= width || y >= height) return; - if (!config->upsideDown) - { - // normal orientation - LCD[x / 8][y] = LCD[x / 8][y] | data; - } - else + if (config->upsideDown) { // upside down orientation x = width - 1 - x; y = height - 1 - y; - LCD[x / 8][y] = LCD[x / 8][y] | ReverseBits(data); } + LCD[x][y] = data; } void cDriverSimLCD::Refresh(bool refreshAll) @@ -135,36 +137,41 @@ FILE * fp = NULL; int x; int y; - int i; - unsigned char c; if (CheckSetup() > 0) refreshAll = true; - fp = fopen("/tmp/simlcd.sem", "r"); + fp = fopen(DISPLAY_REFRESH_FILE, "r"); if (!fp || refreshAll) { if (fp) fclose(fp); - fp = fopen("/tmp/simlcd.dat", "w"); + fp = fopen(DISPLAY_DATA_FILE, "w"); if (fp) { for (y = 0; y < height; y++) { - for (x = 0; x < (width + 7) / 8; x++) + for (x = 0; x < width; x++) { - c = LCD[x][y] ^ (config->invert ? 0xff : 0x00); - for (i = 0; i < 8; i++) + if (LCD[x][y] == GRAPHLCD_Black) { - if (c & 0x80) + if (!config->invert) { - fprintf(fp,"#"); + fprintf(fp,FG_CHAR); + } else + { + fprintf(fp,BG_CHAR); } - else + } + else + { + if (!config->invert) { - fprintf(fp,"."); + fprintf(fp,BG_CHAR); + } else + { + fprintf(fp,FG_CHAR); } - c = c << 1; } } fprintf(fp,"\n"); @@ -172,7 +179,7 @@ fclose(fp); } - fp = fopen("/tmp/simlcd.sem", "w"); + fp = fopen(DISPLAY_REFRESH_FILE, "w"); fclose(fp); } else @@ -181,4 +188,31 @@ } } +uint32_t cDriverSimLCD::GetBackgroundColor(void) +{ + return GRAPHLCD_White; +} + +bool cDriverSimLCD::GetDriverFeature(const std::string & Feature, int & value) +{ + if (strcasecmp(Feature.c_str(), "depth") == 0) { + value = 1; + return true; + } else if (strcasecmp(Feature.c_str(), "ismonochrome") == 0) { + value = true; + return true; + } else if (strcasecmp(Feature.c_str(), "isgreyscale") == 0 || strcasecmp(Feature.c_str(), "isgrayscale") == 0) { + value = false; + return true; + } else if (strcasecmp(Feature.c_str(), "iscolour") == 0 || strcasecmp(Feature.c_str(), "iscolor") == 0) { + value = false; + return true; + } else if (strcasecmp(Feature.c_str(), "touch") == 0 || strcasecmp(Feature.c_str(), "touchscreen") == 0) { + value = false; + return true; + } + value = 0; + return false; +} + } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/simlcd.h graphlcd-base-0.1.9+git20120310/glcddrivers/simlcd.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/simlcd.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/simlcd.h 2012-03-10 09:18:56.000000000 +0000 @@ -9,6 +9,8 @@ * to the COPYING file distributed with this package. * * (c) 2001-2004 Carsten Siebholz + * (c) 2011 Dirk Heiser + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_SIMLCD_H_ @@ -25,22 +27,20 @@ class cDriverSimLCD : public cDriver { private: - unsigned char ** LCD; - cDriverConfig * config; - cDriverConfig * oldConfig; - + uint32_t ** LCD; int CheckSetup(); public: cDriverSimLCD(cDriverConfig * config); - virtual ~cDriverSimLCD(); virtual int Init(); virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); virtual void Refresh(bool refreshAll = false); + virtual uint32_t GetBackgroundColor(void); + virtual bool GetDriverFeature (const std::string & Feature, int & value); }; } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/t6963c.c graphlcd-base-0.1.9+git20120310/glcddrivers/t6963c.c --- graphlcd-base-0.2.0+git20101020/glcddrivers/t6963c.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/t6963c.c 2012-03-10 09:18:56.000000000 +0000 @@ -8,7 +8,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003, 2004 Andreas Regel + * (c) 2003-2004 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #include @@ -107,10 +108,8 @@ cDriverT6963C::cDriverT6963C(cDriverConfig * config) -: config(config) +: cDriver(config) { - oldConfig = new cDriverConfig(*config); - port = new cParallelPort(); //width = config->width; @@ -125,7 +124,6 @@ cDriverT6963C::~cDriverT6963C() { delete port; - delete oldConfig; } int cDriverT6963C::Init() @@ -376,6 +374,52 @@ memset(newLCD[x], 0, height); } + +void cDriverT6963C::SetPixel(int x, int y, uint32_t data) +{ + if (x >= width || y >= height) + return; + + if (FS == 6) + { + int pos = x % 6; + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + } else { + pos = 5 - pos; // reverse bit position + } + + // columns_per_line = (width + FS6-1) / FS6 (FS6 == 6 bits per byte used) + //int cols = (width + 6 - 1 ) / 6; + int col = x / 6; + + if (data == GRAPHLCD_White) + newLCD[col][y] |= (1 << pos); + else + newLCD[col][y] &= ( 0x3F ^ (1 << pos) ); + } + else + { + int pos = x % 8; + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + } else { + pos = 7 - pos; // reverse bit position + } + + if (data == GRAPHLCD_White) + newLCD[x / 8][y] |= (1 << pos); + else + newLCD[x / 8][y] &= ( 0xFF ^ (1 << pos) ); + } +} + + +#if 0 void cDriverT6963C::Set8Pixels(int x, int y, unsigned char data) { if (x >= width || y >= height) @@ -446,6 +490,7 @@ } } } +#endif void cDriverT6963C::Refresh(bool refreshAll) { diff -Nru graphlcd-base-0.2.0+git20101020/glcddrivers/t6963c.h graphlcd-base-0.1.9+git20120310/glcddrivers/t6963c.h --- graphlcd-base-0.2.0+git20101020/glcddrivers/t6963c.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcddrivers/t6963c.h 2012-03-10 09:18:56.000000000 +0000 @@ -8,7 +8,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003, 2004 Andreas Regel + * (c) 2003-2004 Andreas Regel + * (c) 2011 Wolfgang Astleitner */ #ifndef _GLCDDRIVERS_T6963C_H_ @@ -28,8 +29,6 @@ cParallelPort * port; unsigned char ** newLCD; // wanted state unsigned char ** oldLCD; // current state - cDriverConfig * config; - cDriverConfig * oldConfig; int refreshCounter; int bidirectLPT; int displayMode; @@ -67,7 +66,8 @@ virtual int DeInit(); virtual void Clear(); - virtual void Set8Pixels(int x, int y, unsigned char data); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/bitmap.c graphlcd-base-0.1.9+git20120310/glcdgraphics/bitmap.c --- graphlcd-base-0.2.0+git20101020/glcdgraphics/bitmap.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/bitmap.c 2012-03-10 09:18:56.000000000 +0000 @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #include @@ -25,21 +27,100 @@ namespace GLCD { +const uint32_t cColor::Black = GRAPHLCD_Black; +const uint32_t cColor::White = GRAPHLCD_White; +const uint32_t cColor::Red = 0xFFFF0000; +const uint32_t cColor::Green = 0xFF00FF00; +const uint32_t cColor::Blue = 0xFF0000FF; +const uint32_t cColor::Magenta = 0xFFFF00FF; +const uint32_t cColor::Cyan = 0xFF00FFFF; +const uint32_t cColor::Yellow = 0xFFFFFF00; +const uint32_t cColor::Transparent = GRAPHLCD_Transparent; +const uint32_t cColor::ERRCOL = GRAPHLCD_ERRCOL; + + +cColor cColor::ParseColor(std::string col) { + if (col == "black") return cColor(cColor::Black); + else if (col == "white") return cColor(cColor::White); + else if (col == "red") return cColor(cColor::Red); + else if (col == "green") return cColor(cColor::Green); + else if (col == "blue") return cColor(cColor::Blue); + else if (col == "magenta") return cColor(cColor::Magenta); + else if (col == "cyan") return cColor(cColor::Cyan); + else if (col == "yellow") return cColor(cColor::Yellow); + else if (col == "transparent") return cColor(cColor::Transparent); + else if (col.substr(0, 2) == "0x" || col.substr(0, 2) == "0X") { + if (col.length() <= 2 || col.length() > 10) + return cColor(cColor::ERRCOL); + + char* tempptr; + const char* str = col.c_str(); + uint32_t rv = (uint32_t) strtoul(str, &tempptr, 16); + + if ((str == tempptr) || (*tempptr != '\0')) + return cColor(cColor::ERRCOL); + + if (col.length() <= 8) // eg. 0xRRGGBB -> 0xFFRRGGBB + rv |= 0xFF000000; + return cColor(rv); + } + return cColor(cColor::ERRCOL); +} + +cColor cColor::Invert(void) +{ + return cColor( (uint32_t)(color ^ 0x00FFFFFF) ) ; +} + +uint32_t cColor::AlignAlpha (uint32_t col) { + switch (col) { + case Transparent: + case ERRCOL: + return col; + default: + return (col & 0xFF000000) ? col : (col | 0xFF000000); + } +} + const unsigned char bitmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; const unsigned char bitmaskl[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; const unsigned char bitmaskr[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; -cBitmap::cBitmap(int width, int height, unsigned char * data) +cBitmap::cBitmap(int width, int height, uint32_t * data) : width(width), height(height), - bitmap(NULL) + bitmap(NULL), + ismonochrome(false), + processAlpha(true) { - // lines are byte aligned - lineSize = (width + 7) / 8; +#ifdef DEBUG + printf("%s:%s(%d) cBitmap Size %03d * %03d\n", __FILE__, __FUNCTION__, __LINE__, width, height); +#endif + if (width > 0 && height > 0) { + bitmap = new uint32_t[width * height]; + if (data && bitmap) { + memcpy(bitmap, data, width * height * sizeof(uint32_t)); + } + } + backgroundColor = cColor::White; +} - bitmap = new unsigned char[lineSize * height]; - if (data) - memcpy(bitmap, data, lineSize * height); + +cBitmap::cBitmap(int width, int height, uint32_t initcol) +: width(width), + height(height), + bitmap(NULL), + ismonochrome(false), + processAlpha(true) +{ +#ifdef DEBUG + printf("%s:%s(%d) cBitmap Size %03d * %03d\n", __FILE__, __FUNCTION__, __LINE__, width, height); +#endif + + if (width > 0 && height > 0) { + bitmap = new uint32_t[width * height]; + Clear(initcol); + } } cBitmap::cBitmap(const cBitmap & b) @@ -47,63 +128,91 @@ width = b.width; height = b.height; lineSize = b.lineSize; - bitmap = new unsigned char[lineSize * height]; - if (b.bitmap) - memcpy(bitmap, b.bitmap, lineSize * height); + backgroundColor = b.backgroundColor; + ismonochrome = b.ismonochrome; + processAlpha = b.processAlpha; + bitmap = new uint32_t[b.width * b.height]; + if (b.bitmap && bitmap) { + memcpy(bitmap, b.bitmap, b.width * b.height * sizeof(uint32_t)); + } } cBitmap::~cBitmap() { - delete[] bitmap; + if (bitmap) + delete[] bitmap; + bitmap = NULL; } -void cBitmap::Clear() +void cBitmap::Clear(uint32_t color) { - memset(bitmap, 0, lineSize * height); +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, width, height, color); +#endif + //uint32_t col = initcol; //(initcol == cColor::Transparent) ? backgroundColor : initcol; + + // force clearing (== background) colour to contain alpha level = 0xFF + if ( color != cColor::Transparent ) + color = (color & 0x00FFFFFF) | 0xFF000000; + + for (int i = 0; i < width * height; i++) + bitmap[i] = color; + backgroundColor = color; } void cBitmap::Invert() { int i; - for (i = 0; i < lineSize * height; i++) + for (i = 0; i < width * height; i++) { - bitmap[i] ^= 0xFF; + bitmap[i] ^= 0xFFFFFF; } } -void cBitmap::DrawPixel(int x, int y, eColor color) +void cBitmap::DrawPixel(int x, int y, uint32_t color) { if (x < 0 || x > width - 1) return; if (y < 0 || y > height - 1) return; - unsigned char c = 0x80 >> (x % 8); - if (color == clrBlack) - bitmap[lineSize * y + x / 8] |= c; - else - bitmap[lineSize * y + x / 8] &= ~c; + if (color != GLCD::cColor::Transparent) { + uint32_t col = cColor::AlignAlpha(color); + if (processAlpha) { + uint32_t bg = bitmap[x + (width * y)]; + uint32_t afg = (col & 0xFF000000) >> 24; + uint32_t rfg = (col & 0x00FF0000) >> 16; + uint32_t gfg = (col & 0x0000FF00) >> 8; + uint32_t bfg = (col & 0x000000FF); + + uint32_t rbg = (bg & 0x00FF0000) >> 16; + uint32_t gbg = (bg & 0x0000FF00) >> 8; + uint32_t bbg = (bg & 0x000000FF); + + // calculate colour channels of new colour depending on alpha channel and background colour + rfg = (rfg * afg + rbg * (255 - afg)) / 255; + gfg = (gfg * afg + gbg * (255 - afg)) / 255; + bfg = (bfg * afg + bbg * (255 - afg)) / 255; + + // as we draw from bottom to top, the new colour will always have alpha level == 0xFF + // (it will serve as background colour for future objects that will be drawn onto the current object) + col = 0xFF000000 | (rfg << 16) | (gfg << 8) | bfg; + } + bitmap[x + (width * y)] = col; + } + //else + // bitmap[x + (width * y)] = cColor::AlignAlpha(backgroundColor); } -void cBitmap::Draw8Pixels(int x, int y, unsigned char pixels, eColor color) -{ - if (x < 0 || x > width - 1) - return; - if (y < 0 || y > height - 1) - return; - - if (color == clrBlack) - bitmap[lineSize * y + x / 8] |= pixels; - else - bitmap[lineSize * y + x / 8] &= ~pixels; -} -void cBitmap::DrawLine(int x1, int y1, int x2, int y2, eColor color) +void cBitmap::DrawLine(int x1, int y1, int x2, int y2, uint32_t color) { int d, sx, sy, dx, dy; unsigned int ax, ay; + color = cColor::AlignAlpha(color); + dx = x2 - x1; ax = abs(dx) << 1; if (dx < 0) @@ -151,43 +260,43 @@ } } -void cBitmap::DrawHLine(int x1, int y, int x2, eColor color) +void cBitmap::DrawHLine(int x1, int y, int x2, uint32_t color) { - sort(x1,x2); +#ifdef DEBUG + printf("%s:%s(%d) %03d -> %03d, %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x1, x2, y, color); +#endif + color = cColor::AlignAlpha(color); - if (x1 / 8 == x2 / 8) - { - // start and end in the same byte - Draw8Pixels(x1, y, bitmaskr[x1 % 8] & bitmaskl[x2 % 8], color); - } - else - { - // start and end in different bytes - Draw8Pixels(x1, y, bitmaskr[x1 % 8], color); - x1 = ((x1 + 8) / 8) * 8; - while (x1 < (x2 / 8) * 8) - { - Draw8Pixels(x1, y, 0xff, color); - x1 += 8; - } - Draw8Pixels(x2, y, bitmaskl[x2 % 8], color); - } + sort(x1,x2); + while (x1 <= x2) { + DrawPixel(x1, y, color); + x1++; + }; } -void cBitmap::DrawVLine(int x, int y1, int y2, eColor color) -{ - int y; +void cBitmap::DrawVLine(int x, int y1, int y2, uint32_t color) +{ +#ifdef DEBUG + printf("%s:%s(%d) %03d, %03d -> %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x, y1, y2, color); +#endif + color = cColor::AlignAlpha(color); sort(y1,y2); - - for (y = y1; y <= y2; y++) - DrawPixel(x, y, color); + while (y1 <= y2) { + DrawPixel(x, y1, color); + y1++; + } } -void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled) +void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, uint32_t color, bool filled) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d -> %03d * %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2, color); +#endif int y; + color = cColor::AlignAlpha(color); + sort(x1,x2); sort(y1,y2); @@ -207,8 +316,13 @@ } } -void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled, int type) +void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, uint32_t color, bool filled, int type) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d -> %03d * %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2, color); +#endif + color = cColor::AlignAlpha(color); + sort(x1,x2); sort(y1,y2); @@ -230,10 +344,14 @@ if (type == 4) { // round the ugly fat box... - DrawPixel(x1 + 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); - DrawPixel(x1 + 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); - DrawPixel(x2 - 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); - DrawPixel(x2 - 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); +// DrawPixel(x1 + 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); +// DrawPixel(x1 + 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); +// DrawPixel(x2 - 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); +// DrawPixel(x2 - 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); + DrawPixel(x1 + 1, y1 + 1, backgroundColor); + DrawPixel(x1 + 1, y2 - 1, backgroundColor); + DrawPixel(x2 - 1, y1 + 1, backgroundColor); + DrawPixel(x2 - 1, y2 - 1, backgroundColor); } } else @@ -256,8 +374,13 @@ } } -void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, eColor color, bool filled, int quadrants) +void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, uint32_t color, bool filled, int quadrants) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d -> %03d * %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2, color); +#endif + color = cColor::AlignAlpha(color); + // Algorithm based on http://homepage.smc.edu/kennedy_john/BELIPSE.PDF int rx = x2 - x1; int ry = y2 - y1; @@ -397,8 +520,13 @@ } } -void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type) +void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, uint32_t color, int type) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d -> %03d * %03d\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2); +#endif + color = cColor::AlignAlpha(color); + bool upper = type & 0x01; bool falling = type & 0x02; bool vertical = type & 0x04; @@ -410,7 +538,7 @@ if (falling) c = -c; int x = int((x2 - x1 + 1) * c / 2); - if (upper && !falling || !upper && falling) + if ((upper && !falling) || (!upper && falling)) DrawRectangle(x1, y, (x1 + x2) / 2 + x, y, color, true); else DrawRectangle((x1 + x2) / 2 + x, y, x2, y, color, true); @@ -432,82 +560,58 @@ } } -void cBitmap::DrawBitmap(int x, int y, const cBitmap & bitmap, eColor color) +void cBitmap::DrawBitmap(int x, int y, const cBitmap & bitmap, uint32_t color, uint32_t bgcolor, int opacity) { - unsigned char cl = 0; - int xt, yt; - const unsigned char * data = bitmap.Data(); - unsigned short temp; - int h, w; +#ifdef DEBUG + printf("%s:%s(%d) '%03d' x '%03d' \n", __FILE__, __FUNCTION__, __LINE__, x, y); +#endif + color = cColor::AlignAlpha(color); + bgcolor = cColor::AlignAlpha(bgcolor); + + uint32_t cl = 0; + const uint32_t * data = bitmap.Data(); + bool ismonochrome = bitmap.IsMonochrome(); - w = bitmap.Width(); - h = bitmap.Height(); + int xt, yt; + uint32_t alpha; if (data) { - if (!(x % 8)) - { - // Bitmap is byte alligned (0,8,16,...) - for (yt = 0; yt < h; yt++) - { - for (xt = 0; xt < (w / 8); xt++) - { - cl = *data; - Draw8Pixels(x + (xt * 8), y + yt, cl, color); - data++; - } - if (w % 8) - { - cl = *data; - Draw8Pixels(x + ((w / 8) * 8), y + yt, cl & bitmaskl[w % 8 - 1], color); - data++; - } - } - } - else + for (yt = 0; yt < bitmap.Height(); yt++) { - // Bitmap is not byte alligned - for (yt = 0; yt < h; yt++) - { - temp = 0; - for (xt = 0; xt < (w + (x % 8)) / 8; xt++) - { - cl = *(data + yt * ((w + 7) / 8) + xt); - temp = temp | ((unsigned short) cl << (8 - (x % 8))); - cl = (temp & 0xff00) >> 8; - if (!xt) - { - // first byte - Draw8Pixels(x - (x % 8) + (xt * 8), y + yt, cl & bitmaskr[x % 8], color); - } - else - { - // not the first byte - Draw8Pixels(x - (x % 8) + (xt * 8), y + yt, cl, color); - } - temp <<= 8; - } - if ((w + (x % 8) + 7) / 8 != (w + (x % 8)) / 8) - { - // print the rest - cl = *(data + (yt + 1) * ((w + 7) / 8) - 1); - temp = temp | ((unsigned short) cl << (8 - (x % 8))); - cl = (temp & 0xff00) >> 8; - Draw8Pixels(x - (x % 8) + (((w + (x % 8)) / 8) * 8), y + yt, cl & bitmaskl[(w + x) % 8 - 1], color); - } - } - } + for (xt = 0; xt < bitmap.Width(); xt++) + { + cl = data[(yt * bitmap.Width())+xt]; + if (cl != cColor::Transparent) { + if (ismonochrome) { + cl = (cl == cColor::Black) ? color : bgcolor; + } + if (opacity != 255) { + alpha = (cl & 0xFF000000) >> 24; + alpha = (alpha * opacity) / 255; + cl = (cl & 0x00FFFFFF) | (alpha << 24); + } + DrawPixel(xt+x, yt+y, cl); + } + } + } } } int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cFont * font, - eColor color, bool proportional, int skipPixels) + uint32_t color, uint32_t bgcolor, bool proportional, int skipPixels) { +#ifdef DEBUG + printf("%s:%s(%d) text '%s', color '%08x'/'%08x'\n", __FILE__, __FUNCTION__, __LINE__, text.c_str(), color, bgcolor); +#endif int xt; int yt; - int i; - char c; - int start; + unsigned int i; + uint32_t c; + unsigned int start; + + color = cColor::AlignAlpha(color); + bgcolor = cColor::AlignAlpha(bgcolor); clip(x, 0, width - 1); clip(y, 0, height - 1); @@ -536,17 +640,23 @@ if (skipPixels >= font->Width(text)) start = text.length(); else - while (skipPixels > font->Width(text[start])) + { + while (skipPixels > font->SpaceBetween() + font->Width(text.substr(start), 1 /*text[start]*/)) { - skipPixels -= font->Width(text[start]); + encodedCharAdjustCounter(font->IsUTF8(), text, c, start); + skipPixels -= font->Width(c/*text[start]*/); skipPixels -= font->SpaceBetween(); start++; } + } } } - for (i = start; i < (int) text.length(); i++) + + i = start; + while ( i < (unsigned int)text.length() ) { - c = text[i]; + encodedCharAdjustCounter(font->IsUTF8(), text, c, i); + if (xt > xmax) { i = text.length(); @@ -557,13 +667,13 @@ { if (skipPixels > 0) { - DrawCharacter(xt, yt, xmax, c, font, color, skipPixels); + DrawCharacter(xt, yt, xmax, c, font, color, bgcolor, skipPixels); xt += font->TotalWidth() - skipPixels; skipPixels = 0; } else { - DrawCharacter(xt, yt, xmax, c, font, color); + DrawCharacter(xt, yt, xmax, c, font, color, bgcolor); xt += font->TotalWidth(); } } @@ -571,12 +681,12 @@ { if (skipPixels > 0) { - xt += DrawCharacter(xt, yt, xmax, c, font, color, skipPixels); + xt += DrawCharacter(xt, yt, xmax, c, font, color, bgcolor, skipPixels); skipPixels = 0; } else { - xt += DrawCharacter(xt, yt, xmax, c, font, color); + xt += DrawCharacter(xt, yt, xmax, c, font, color, bgcolor); } if (xt <= xmax) { @@ -584,15 +694,26 @@ } } } + i++; } } return xt; } -int cBitmap::DrawCharacter(int x, int y, int xmax, char c, const cFont * font, - eColor color, int skipPixels) +int cBitmap::DrawCharacter(int x, int y, int xmax, uint32_t c, const cFont * font, + uint32_t color, uint32_t bgcolor, int skipPixels) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d char '%c' color '%08x' bgcolor '%08x'\n", __FILE__, __FUNCTION__, __LINE__, x, y, c, color, bgcolor); +#endif const cBitmap * charBitmap; + cBitmap * drawBitmap; + + //color = cColor::AlignAlpha(color); + //bgcolor = cColor::AlignAlpha(bgcolor); + + uint32_t dot = 0; + int xt, yt; clip(x, 0, width - 1); clip(y, 0, height - 1); @@ -600,32 +721,54 @@ charBitmap = font->GetCharacter(c); if (charBitmap) { - cBitmap * drawBitmap = charBitmap->SubBitmap(skipPixels, 0, xmax - x + skipPixels, charBitmap->Height() - 1); - if (drawBitmap) - DrawBitmap(x, y, *drawBitmap, color); - delete drawBitmap; - return charBitmap->Width() - skipPixels; + int drawWidth = charBitmap->Width() - skipPixels; + if ( x + drawWidth-1 > xmax) + drawWidth = xmax - x + 1; + + drawBitmap = new cBitmap(drawWidth /*charBitmap->Width()-skipPixels*/,charBitmap->Height()); + if (drawBitmap) { + drawBitmap->SetProcessAlpha(false); + drawBitmap->Clear(bgcolor); + + for (xt = 0; xt < drawWidth; xt++) { + for (yt = 0; yt < charBitmap->Height() ; yt++) { + dot = charBitmap->GetPixel(xt+skipPixels,yt); + if ((dot | 0xFF000000) == cColor::Black) { // todo: does not work with antialising? + drawBitmap->DrawPixel(xt, yt, color); + } else { + drawBitmap->DrawPixel(xt, yt, bgcolor); + } + } + } + DrawBitmap(x, y, *drawBitmap); + delete drawBitmap; + } + return drawWidth; //charBitmap->Width() - skipPixels; } return 0; } -unsigned char cBitmap::GetPixel(int x, int y) const +uint32_t cBitmap::GetPixel(int x, int y) const { - unsigned char value; + if (x < 0 || x > width - 1) + return cColor::Transparent; + if (y < 0 || y > height - 1) + return cColor::Transparent; - value = bitmap[y * lineSize + x / 8]; - value = (value >> (7 - (x % 8))) & 1; + uint32_t value; + value = bitmap[y * width + x]; return value; } cBitmap * cBitmap::SubBitmap(int x1, int y1, int x2, int y2) const { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d / %03d * %03d\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2); +#endif int w, h; int xt, yt; cBitmap * bmp; - unsigned char cl; - unsigned char * data; - unsigned short temp; + uint32_t cl; sort(x1,x2); sort(y1,y2); @@ -642,62 +785,80 @@ if (!bmp || !bmp->Data()) return NULL; bmp->Clear(); - if (x1 % 8 == 0) + bmp->SetMonochrome(this->IsMonochrome()); + + for (yt = 0; yt < h; yt++) { - // Bitmap is byte alligned (0,8,16,...) - for (yt = 0; yt < h; yt++) - { - data = &bitmap[(y1 + yt) * lineSize + x1 / 8]; - for (xt = 0; xt < (w / 8) * 8; xt += 8) - { - cl = *data; - bmp->Draw8Pixels(xt, yt, cl, clrBlack); - data++; - } - if (w % 8 != 0) - { - cl = *data; - bmp->Draw8Pixels(xt, yt, cl & bitmaskl[w % 8 - 1], clrBlack); + for (xt = 0; xt < w; xt++) + { + cl = this->GetPixel(xt+x1, yt+y1); + bmp->DrawPixel(xt,yt, cl); + } + } + return bmp; +} + + +// convert a new 32 bpp bitmap to an old style 1bpp bitmap (bit order: from least to most sig. bit: byte: [ 0, 1, 2, 3, 4, 5, 6, 7 ]) +// if IsMonochrome(): ignore threshold +const unsigned char* cBitmap::ConvertTo1BPP(const cBitmap & bitmap, int threshold) +{ + if (bitmap.Width() <= 0 || bitmap.Height() <= 0) + return NULL; + + int cols = (bitmap.Width() + 7 ) / 8; + unsigned char* monobmp = new unsigned char[ cols * bitmap.Height() ]; + if (!monobmp) + return NULL; + + memset(monobmp, 0, cols * bitmap.Height()); + + uint32_t col; + unsigned char greyval = 0; + bool ismono = bitmap.IsMonochrome(); + + for (int y = 0; y < bitmap.Height(); y++) { + for (int x = 0; x < bitmap.Width(); x++) { + col = bitmap.GetPixel(x, y); + if (! ismono) { + // col -> grey level + greyval = (((0x00FF0000 & col) >> 16) * 77 + ((0x0000FF00 * col) >> 8) * 150 + (0x000000FF & col) * 28) / 255; + col = (greyval >= threshold) ? cColor::White : cColor::Black; } + + if ( col == cColor::Black) + monobmp[ y * cols + (x >> 3) ] |= ( 1 << ( 7 - (x % 8) ) ); } } - else - { - // Bitmap is not byte alligned - for (yt = 0; yt < h; yt++) - { - temp = 0; - data = &bitmap[(y1 + yt) * lineSize + x1 / 8]; - for (xt = 0; xt <= ((w / 8)) * 8; xt += 8) - { - cl = *data; - temp = temp | ((unsigned short) cl << (x1 % 8)); - cl = (temp & 0xff00) >> 8; - if (xt > 0) - { - bmp->Draw8Pixels(xt - 8, yt, cl, clrBlack); - } - temp <<= 8; - data++; - } - if (w % 8 != 0) - { - // print the rest - if (8 - (x1 % 8) < w % 8) - { - cl = *data; - temp = temp | ((unsigned short) cl << (x1 % 8)); - } - cl = (temp & 0xff00) >> 8; - bmp->Draw8Pixels(xt - 8, yt, cl & bitmaskl[(w % 8) - 1], clrBlack); - } + return monobmp; +} + + +// convert an old style 1 bpp bitmap to new 32 bpp bitmap (bit order: from least to most sig. bit: byte: [ 0, 1, 2, 3, 4, 5, 6, 7 ]) +const cBitmap* cBitmap::ConvertFrom1BPP(const unsigned char* monobmp, int w, int h, uint32_t fg, uint32_t bg) +{ + if (w <= 0 || h <= 0 || !monobmp) + return NULL; + + cBitmap* bmp = new cBitmap(w, h, bg); + if (bmp == NULL) + return NULL; + + int cols = (w + 7 ) / 8; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + bmp->DrawPixel(x, y, ( monobmp[ y * cols + (x >> 3) ] & ( 1 << (7 - (x % 8)) ) ) ? fg : bg ); } } return bmp; } +#if 0 bool cBitmap::LoadPBM(const std::string & fileName) { +#ifdef DEBUG + printf("%s:%s(%d)\n", __FILE__, __FUNCTION__, __LINE__); +#endif FILE * pbmFile; char str[32]; int i; @@ -773,13 +934,12 @@ str[i] = 0; h = atoi(str); - delete[] bitmap; + if (bitmap) + delete[] bitmap; width = w; height = h; - // lines are byte aligned - lineSize = (width + 7) / 8; - bitmap = new unsigned char[lineSize * height]; - fread(bitmap, lineSize * height, 1, pbmFile); + bitmap = new uint32_t [width * height]; + fread(bitmap, width * height, 1, pbmFile); fclose(pbmFile); return true; @@ -787,6 +947,9 @@ void cBitmap::SavePBM(const std::string & fileName) { +#ifdef DEBUG + printf("%s:%s(%d)\n", __FILE__, __FUNCTION__, __LINE__); +#endif int i; char str[32]; FILE * fp; @@ -803,5 +966,6 @@ fclose(fp); } } +#endif } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/bitmap.h graphlcd-base-0.1.9+git20120310/glcdgraphics/bitmap.h --- graphlcd-base-0.2.0+git20101020/glcdgraphics/bitmap.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/bitmap.h 2012-03-10 09:18:56.000000000 +0000 @@ -9,22 +9,79 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #ifndef _GLCDGRAPHICS_BITMAP_H_ #define _GLCDGRAPHICS_BITMAP_H_ #include +#include + +// graphlcd-base uses ARGB bitmaps instead of 1bit ones +// this flag will be checked in current versions of vdr-graphlcd-plugin +#define GRAPHLCD_CBITMAP_ARGB + +// colour definitions for glcddrivers so that libglcddrivers.so isn't link-dependent on libglcdgraphics.so +#define GRAPHLCD_Black 0xFF000000 +#define GRAPHLCD_White 0xFFFFFFFF +#define GRAPHLCD_Transparent 0x00FFFFFF +#define GRAPHLCD_ERRCOL 0x00000000 + namespace GLCD { +#if 0 enum eColor { - clrBlack, - clrWhite + clrTransparent, + clrGray50, + clrBlack, + clrRed, + clrGreen, + clrYellow, + clrMagenta, + clrBlue, + clrCyan, + clrWhite }; +#endif + + +class cColor +{ +protected: + uint32_t color; + +public: + cColor(uint32_t col) { color = col; } + cColor(const cColor & col) { color = col.color; } + + static const uint32_t Black; + static const uint32_t White; + static const uint32_t Red; + static const uint32_t Green; + static const uint32_t Blue; + static const uint32_t Magenta; + static const uint32_t Cyan; + static const uint32_t Yellow; + static const uint32_t Transparent; + static const uint32_t ERRCOL; + + uint32_t GetColor (void) { return color; } + void SetColor (uint32_t col) { color = col; } + + cColor Invert (void); + + operator uint32_t(void) { return GetColor(); } + + static cColor ParseColor (std::string col); + static uint32_t AlignAlpha (uint32_t col); +}; + class cFont; @@ -34,40 +91,55 @@ int width; int height; int lineSize; - unsigned char * bitmap; + uint32_t * bitmap; + bool ismonochrome; + bool processAlpha; + + uint32_t backgroundColor; public: - cBitmap(int width, int height, unsigned char * data = NULL); + cBitmap(int width, int height, uint32_t * data = NULL); + cBitmap(int width, int height, uint32_t initcol); cBitmap(const cBitmap & b); ~cBitmap(); int Width() const { return width; } int Height() const { return height; } int LineSize() const { return lineSize; } - const unsigned char * Data() const { return bitmap; } + const uint32_t * Data() const { return bitmap; } - void Clear(); + void Clear(uint32_t color = cColor::Transparent); void Invert(); - void DrawPixel(int x, int y, eColor color); - void Draw8Pixels(int x, int y, unsigned char pixels, eColor color); - void DrawLine(int x1, int y1, int x2, int y2, eColor color); - void DrawHLine(int x1, int y, int x2, eColor color); - void DrawVLine(int x, int y1, int y2, eColor color); - void DrawRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled); - void DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled, int size); - void DrawEllipse(int x1, int y1, int x2, int y2, eColor color, bool filled, int quadrants); - void DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type); - void DrawBitmap(int x, int y, const cBitmap & bitmap, eColor color); + void DrawPixel(int x, int y, uint32_t color); + void DrawLine(int x1, int y1, int x2, int y2, uint32_t color); + void DrawHLine(int x1, int y, int x2, uint32_t color); + void DrawVLine(int x, int y1, int y2, uint32_t color); + void DrawRectangle(int x1, int y1, int x2, int y2, uint32_t color, bool filled); + void DrawRoundRectangle(int x1, int y1, int x2, int y2, uint32_t color, bool filled, int size); + void DrawEllipse(int x1, int y1, int x2, int y2, uint32_t color, bool filled, int quadrants); + void DrawSlope(int x1, int y1, int x2, int y2, uint32_t color, int type); + void DrawBitmap(int x, int y, const cBitmap & bitmap, uint32_t color = cColor::White, uint32_t bgcolor = cColor::Black, int opacity = 255); int DrawText(int x, int y, int xmax, const std::string & text, const cFont * font, - eColor color = clrBlack, bool proportional = true, int skipPixels = 0); - int DrawCharacter(int x, int y, int xmax, char c, const cFont * font, - eColor color = clrBlack, int skipPixels = 0); + uint32_t color = cColor::White, uint32_t bgcolor = cColor::Black, bool proportional = true, int skipPixels = 0); + int DrawCharacter(int x, int y, int xmax, uint32_t c, const cFont * font, + uint32_t color = cColor::White, uint32_t bgcolor = cColor::Black, int skipPixels = 0); cBitmap * SubBitmap(int x1, int y1, int x2, int y2) const; - unsigned char GetPixel(int x, int y) const; + uint32_t GetPixel(int x, int y) const; + + void SetMonochrome(bool mono) { ismonochrome = mono; } + bool IsMonochrome(void) const { return ismonochrome; } + void SetProcessAlpha(bool procAlpha) { processAlpha = procAlpha; } + bool IsProcessAlpha(void) const { return processAlpha; } + + static const unsigned char* ConvertTo1BPP(const cBitmap & bitmap, int threshold = 127); + static const cBitmap* ConvertFrom1BPP(const unsigned char* monobmp, int w, int h, uint32_t fg = cColor::White, uint32_t bg = cColor::Black); + +#if 0 bool LoadPBM(const std::string & fileName); void SavePBM(const std::string & fileName); +#endif }; } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/common.c graphlcd-base-0.1.9+git20120310/glcdgraphics/common.c --- graphlcd-base-0.2.0+git20101020/glcdgraphics/common.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/common.c 2012-03-10 09:18:56.000000000 +0000 @@ -10,6 +10,7 @@ */ #include +#include #include "common.h" @@ -57,4 +58,66 @@ return s.substr(start, end - start + 1); } + +bool encodedCharAdjustCounter(const bool isutf8, const std::string & str, uint32_t & c, unsigned int & i, const uint32_t errChar) +{ + bool rv = false; + + if (i >= str.length()) + return rv; + + if ( isutf8 ) { + uint8_t c0,c1,c2,c3; + c = str[i]; + c0 = str[i]; + c1 = (i+1 < str.length()) ? str[i+1] : 0; + c2 = (i+2 < str.length()) ? str[i+2] : 0; + c3 = (i+3 < str.length()) ? str[i+3] : 0; + + if ( (c0 & 0x80) == 0x00) { + // one byte: 0xxxxxxx + c = c0; + rv = true; + } else if ( (c0 & 0xE0) == 0xC0 ) { + // two byte utf8: 110yyyyy 10xxxxxx -> 00000yyy yyxxxxxx + if ( (c1 & 0xC0) == 0x80 ) { + c = ( (c0 & 0x1F) << 6 ) | ( (c1 & 0x3F) ); + rv = true; + } else { + //syslog(LOG_INFO, "GraphLCD: illegal 2-byte UTF-8 sequence found: %02x %02x, pos=%d, str: %s\n", c0,c1,i,str.c_str()); + c = errChar; + } + i += 1; + } else if ( (c0 & 0xF0) == 0xE0 ) { + // three byte utf8: 1110zzzz 10yyyyyy 10xxxxxx -> zzzzyyyy yyxxxxxx + if ( ((c1 & 0xC0) == 0x80) && ((c2 & 0xC0) == 0x80) ) { + c = ( (c0 & 0x0F) << 12 ) | ( (c1 & 0x3F) << 6 ) | ( c2 & 0x3F ); + rv = true; + } else { + //syslog(LOG_INFO, "GraphLCD: illegal 3-byte UTF-8 sequence found: %02x %02x %02x, pos=%d, str: %s\n", c0,c1,c2,i,str.c_str()); + c = errChar; + } + i += 2; + } else if ( (c0 & 0xF8) == 0xF0 ) { + // four byte utf8: 11110www 10zzzzzz 10yyyyyy 10xxxxxx -> 000wwwzz zzzzyyyy yyxxxxxx + if ( ((c1 & 0xC0) == 0x80) && ((c2 & 0xC0) == 0x80) && ((c3 & 0xC0) == 0x80) ) { + c = ( (c0 & 0x07) << 18 ) | ( (c1 & 0x3F) << 12 ) | ( (c2 & 0x3F) << 6 ) | (c3 & 0x3F); + rv = true; + } else { + //syslog(LOG_INFO, "GraphLCD: illegal 4-byte UTF-8 sequence found: %02x %02x %02x %02x, pos=%d, str: %s\n", c0,c1,c2,c3,i,str.c_str()); + c = errChar; + } + i += 3; + } else { + // 1xxxxxxx is invalid! + //syslog(LOG_INFO, "GraphLCD: illegal 1-byte UTF-8 char found: %02x, pos=%d, str: %s\n", c0,i,str.c_str()); + c = errChar; + } + } else { + c = str[i]; + rv = true; + } + return rv; +} + } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/common.h graphlcd-base-0.1.9+git20120310/glcdgraphics/common.h --- graphlcd-base-0.2.0+git20101020/glcdgraphics/common.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/common.h 2012-03-10 09:18:56.000000000 +0000 @@ -13,6 +13,13 @@ #define _GLCDGRAPHICS_COMMON_H_ #include +#include + +// character to return when erraneous utf-8 sequence (for now: space) +//#define UTF8_ERRCHAR 0x0020 +// for debugging issues return '_' instead: +#define UTF8_ERRCHAR 0x005F + namespace GLCD { @@ -20,6 +27,7 @@ void clip(int & value, int min, int max); void sort(int & value1, int & value2); std::string trim(const std::string & s); +bool encodedCharAdjustCounter(const bool isutf8, const std::string & str, uint32_t & c, unsigned int & i, const uint32_t errChar = UTF8_ERRCHAR); } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/extformats.c graphlcd-base-0.1.9+git20120310/glcdgraphics/extformats.c --- graphlcd-base-0.2.0+git20101020/glcdgraphics/extformats.c 1970-01-01 00:00:00.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/extformats.c 2012-03-10 09:18:56.000000000 +0000 @@ -0,0 +1,181 @@ +/* + * GraphLCD graphics library + * + * extformats.c - loading and saving of external formats (via ImageMagick) + * + * based on bitmap.[ch] from text2skin: http://projects.vdr-developer.org/projects/show/plg-text2skin + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2011 Wolfgang Astleitner + */ + +#include +#include +#include + +#include + +#include "bitmap.h" +#include "extformats.h" +#include "image.h" + +#ifdef HAVE_IMAGEMAGICK +#include +using namespace Magick; +//#elif defined(HAVE_IMLIB2) +//#include "quantize.h" +//#include +#endif + + +namespace GLCD +{ + +using namespace std; + + +cExtFormatFile::cExtFormatFile() +{ +#ifdef HAVE_IMAGEMAGICK + InitializeMagick(NULL); +#endif +} + +cExtFormatFile::~cExtFormatFile() +{ +} + +bool cExtFormatFile::Load(cImage & image, const string & fileName) +{ + uint16_t scalew = 0; + uint16_t scaleh = 0; + return LoadScaled(image, fileName, scalew, scaleh); +} + +bool cExtFormatFile::LoadScaled(cImage & image, const string & fileName, uint16_t & scalew, uint16_t & scaleh) +{ +#ifdef HAVE_IMAGEMAGICK + std::vector extimages; + try { + uint16_t width = 0; + uint16_t height = 0; + //uint16_t count; + uint32_t delay; + + std::vector::iterator it; + readImages(&extimages, fileName); + if (extimages.size() == 0) { + syslog(LOG_ERR, "ERROR: graphlcd: Couldn't load %s", fileName.c_str()); + return false; + } + + delay = (uint32_t)(extimages[0].animationDelay() * 10); + + image.Clear(); + image.SetDelay(delay); + + bool firstImage = true; + + for (it = extimages.begin(); it != extimages.end(); ++it) { + bool ignoreImage = false; + + //(*it).quantizeColorSpace( RGBColorspace ); + //(*it).quantizeColors( 256*256*256 /*colors*/ ); + //(*it).quantize(); + + if (firstImage) { + width = (uint16_t)((*it).columns()); + height = (uint16_t)((*it).rows()); + firstImage = false; + + // one out of scalew/h == 0 ? -> auto aspect ratio + if (scalew && ! scaleh) { + scaleh = (uint16_t)( ((uint32_t)scalew * (uint32_t)height) / (uint32_t)width ); + } else if (!scalew && scaleh) { + scalew = (uint16_t)( ((uint32_t)scaleh * (uint32_t)width) / (uint32_t)height ); + } + + // scale image + if (scalew && ! (scalew == width && scaleh == height)) { + (*it).scale(Geometry(scalew, scaleh)); + width = scalew; + height = scaleh; + } else { + // not scaled => reset to 0 + scalew = 0; + scaleh = 0; + } + + image.SetWidth(width); + image.SetHeight(height); + } else { + if (scalew && scaleh) { + (*it).scale(Geometry(scalew, scaleh)); + } else + if ( (width != (uint16_t)((*it).columns())) || (height != (uint16_t)((*it).rows())) ) { + ignoreImage = true; + } + } + + if (! ignoreImage) { + /* + if ((*it).depth() > 8) { + esyslog("ERROR: text2skin: More than 8bpp images are not supported"); + return false; + } + */ + uint32_t * bmpdata = new uint32_t[height * width]; + //Dprintf("this image has %d colors\n", (*it).totalColors()); + + bool isMatte = (*it).matte(); + //bool isMonochrome = ((*it).totalColors() <= 2) ? true : false; + const PixelPacket *pix = (*it).getConstPixels(0, 0, (int)width, (int)height); + + for (int iy = 0; iy < (int)height; ++iy) { + for (int ix = 0; ix < (int)width; ++ix) { + if ( isMatte && pix->opacity == MaxRGB ) { + bmpdata[iy*width+ix] = cColor::Transparent; + } else { + //bmpdata[iy*width+ix] = (uint32_t)( 0xFF000000 | (int(pix->red * 255 / MaxRGB) << 16) | (int(pix->green * 255 / MaxRGB) << 8) | int(pix->blue * 255 / MaxRGB)); + bmpdata[iy*width+ix] = (uint32_t)( (int(255 - (pix->opacity * 255 / MaxRGB)) << 24) | (int(pix->red * 255 / MaxRGB) << 16) | (int(pix->green * 255 / MaxRGB) << 8) | int(pix->blue * 255 / MaxRGB)); + //if ( isMonochrome ) { // if is monochrome: exchange black and white + // uint32_t c = bmpdata[iy*width+ix]; + // switch(c) { + // case cColor::White: c = cColor::Black; break; + // case cColor::Black: c = cColor::White; break; + // } + // bmpdata[iy*width+ix] = c; + //} + } + ++pix; + } + } + cBitmap * b = new cBitmap(width, height, bmpdata); + //b->SetMonochrome(isMonochrome); + image.AddBitmap(b); + delete[] bmpdata; + bmpdata = NULL; + } + } + } catch (Exception &e) { + syslog(LOG_ERR, "ERROR: graphlcd: Couldn't load %s: %s", fileName.c_str(), e.what()); + return false; + } catch (...) { + syslog(LOG_ERR, "ERROR: graphlcd: Couldn't load %s: Unknown exception caught", fileName.c_str()); + return false; + } + return true; +#else + return false; +#endif +} + +// to be done ... +bool cExtFormatFile::Save(cImage & image, const string & fileName) +{ + return false; +} + +} // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/extformats.h graphlcd-base-0.1.9+git20120310/glcdgraphics/extformats.h --- graphlcd-base-0.2.0+git20101020/glcdgraphics/extformats.h 1970-01-01 00:00:00.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/extformats.h 2012-03-10 09:18:56.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * GraphLCD graphics library + * + * extformats.h - loading and saving of external formats (via ImageMagick) + * + * based on bitmap.[ch] from text2skin: http://projects.vdr-developer.org/projects/show/plg-text2skin + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2011 Wolfgang Astleitner + */ + +#ifndef _GLCDGRAPHICS_EXTFORMATS_H_ +#define _GLCDGRAPHICS_EXTFORMATS_H_ + +#include "imagefile.h" + +namespace GLCD +{ + +class cImage; + +class cExtFormatFile : public cImageFile +{ +public: + cExtFormatFile(); + virtual ~cExtFormatFile(); + virtual bool Load(cImage & image, const std::string & fileName); + virtual bool Save(cImage & image, const std::string & fileName); + + virtual bool LoadScaled(cImage & image, const std::string & fileName, uint16_t & scalew, uint16_t & scaleh); +}; + +} // end of namespace + +#endif diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/font.c graphlcd-base-0.1.9+git20120310/glcdgraphics/font.c --- graphlcd-base-0.2.0+git20101020/glcdgraphics/font.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/font.c 2012-03-10 09:18:56.000000000 +0000 @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #include @@ -55,6 +57,64 @@ //}; //#pragma pack() +#ifdef HAVE_FREETYPE2 + +class cBitmapCache +{ +private: +protected: + cBitmapCache *next; // next bitmap + cBitmap *ptr; + uint32_t charcode; +public: + cBitmapCache(); + ~cBitmapCache(); + + void PushBack(uint32_t ch, cBitmap *bitmap); + cBitmap *GetBitmap(uint32_t ch) const; +}; + +cBitmapCache::cBitmapCache() +: next(NULL), + ptr(NULL), + charcode(0) +{ +} + +cBitmapCache::~cBitmapCache() +{ + delete ptr; + delete next; +} + +void cBitmapCache::PushBack(uint32_t ch, cBitmap *bitmap) +{ + if (!ptr) + { + charcode = ch; + ptr = bitmap; + } + else if (!next) + { + next = new cBitmapCache(); + next->ptr = bitmap; + next->charcode = ch; + } else + next->PushBack(ch, bitmap); +} + +cBitmap *cBitmapCache::GetBitmap(uint32_t ch) const +{ + if (ptr && charcode==ch) + return ptr; + else if (next) + return next->GetBitmap(ch); + else + return NULL; +} + +#endif + cFont::cFont() { Init(); @@ -65,10 +125,12 @@ Unload(); } -bool cFont::LoadFNT(const std::string & fileName) +bool cFont::LoadFNT(const std::string & fileName, const std::string & encoding) { // cleanup if we already had a loaded font Unload(); + fontType = 1; //original fonts + isutf8 = (encoding == "UTF-8"); FILE * fontFile; int i; @@ -88,6 +150,7 @@ buffer[3] != kFontFileSign[3]) { fclose(fontFile); + syslog(LOG_ERR, "cFont::LoadFNT(): Cannot open file: %s - not the correct fileheader.\n",fileName.c_str()); return false; } @@ -105,11 +168,32 @@ character = chdr[0] | (chdr[1] << 8); charWidth = chdr[2] | (chdr[3] << 8); fread(buffer, fontHeight * ((charWidth + 7) / 8), 1, fontFile); - if (characters[character]) - delete characters[character]; - characters[character] = new cBitmap(charWidth, fontHeight, buffer); - if (characters[character]->Width() > maxWidth) - maxWidth = characters[character]->Width(); +#ifdef DEBUG + printf ("fontHeight %0d - charWidth %0d - character %0d - bytes %0d\n", fontHeight, charWidth, character,fontHeight * ((charWidth + 7) / 8)); +#endif + + int y; int loop; + int num = 0; + uint dot; uint b; + cBitmap * charBitmap = new cBitmap(charWidth, fontHeight); + charBitmap->SetMonochrome(true); + charBitmap->Clear(); + for (num=0; num> b); + if (dot) { + charBitmap->DrawPixel(b+((loop*8)),num/y,cColor::Black); + } + } + } + num=num+y-1; + } + SetCharacter(character, charBitmap); + + if (charWidth > maxWidth) + maxWidth = charWidth; } fclose(fontFile); @@ -137,7 +221,7 @@ numChars = 0; for (i = 0; i < 256; i++) { - if (characters[i]) + if (GetCharacter(i)) { numChars++; } @@ -160,16 +244,20 @@ // write font file header fwrite(fhdr, kFontHeaderSize, 1, fontFile); + const cBitmap* charbmp = NULL; for (i = 0; i < 256; i++) { - if (characters[i]) + charbmp = GetCharacter(i); + if (charbmp) { chdr[0] = (uint8_t) i; chdr[1] = (uint8_t) (i >> 8); - chdr[2] = (uint8_t) characters[i]->Width(); - chdr[3] = (uint8_t) (characters[i]->Width() >> 8); + chdr[2] = (uint8_t) charbmp->Width(); + chdr[3] = (uint8_t) (charbmp->Width() >> 8); fwrite(chdr, kCharHeaderSize, 1, fontFile); - fwrite(characters[i]->Data(), totalHeight * characters[i]->LineSize(), 1, fontFile); + const unsigned char* monobmp = cBitmap::ConvertTo1BPP(*charbmp); + fwrite(monobmp /*characters[i]->Data()*/, totalHeight * ((charbmp->Width() + 7) / 8), 1, fontFile); + delete[] monobmp; } } @@ -185,6 +273,9 @@ { // cleanup if we already had a loaded font Unload(); + fontType = 2; // ft2 fonts + isutf8 = (encoding == "UTF-8"); + #ifdef HAVE_FREETYPE2 if (access(fileName.c_str(), F_OK) != 0) { @@ -194,7 +285,6 @@ // file exists FT_Library library; FT_Face face; - FT_GlyphSlot slot; int error = FT_Init_FreeType(&library); if (error) @@ -223,36 +313,11 @@ return false; } - // set slot - slot = face->glyph; - // set Size FT_Set_Char_Size(face, 0, size * 64, 0, 0); - wchar_t utf_buff[256]; - if (dingBats) - { -/* - FT_CharMap charmap = 0; - for (int n = 0; n < face->num_charmaps; n++) - { - if (face->charmaps[n]->platform_id == 3 && - face->charmaps[n]->encoding_id == 0) - { - charmap = face->charmaps[n]; - //break; - } - } - if (charmap) - syslog(LOG_ERR, "cFont::LoadFT2: platform_id: %d, encoding_id: %d", charmap->platform_id, charmap->encoding_id); - error = FT_Set_Charmap(_face, charmap); - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: FT_Select_Charmap encoding not supported: %d", charmap->encoding_id); - } -*/ - } - else + // generate lookup table for encoding conversions (encoding != UTF8) + if (! (isutf8 || dingBats) ) { iconv_t cd; if ((cd = iconv_open("WCHAR_T", encoding.c_str())) == (iconv_t) -1) @@ -276,87 +341,26 @@ in_buff = (char *) &char_buff; out_buff = (char *) &wchar_buff; count = iconv(cd, &in_buff, &in_len, &out_buff, &out_len); - if ((size_t) -1 == count) - { - utf_buff[c] = 0; - } - utf_buff[c] = wchar_buff; + iconv_lut[c] = ((size_t) -1 == count) ? (wchar_t)'?' : wchar_buff; } iconv_close(cd); + } else { + // don't leave LUT uninitialised + for (int c = 0; c < 256; c++) + iconv_lut[c] = (wchar_t)c; } // get some global parameters - totalHeight = (face->size->metrics.ascender >> 6) - (face->size->metrics.descender >> 6); - totalWidth = face->size->metrics.max_advance >> 6; - totalAscent = face->size->metrics.ascender >> 6; - lineHeight = face->size->metrics.height >> 6; - spaceBetween = 0; -#if 0 - syslog(LOG_DEBUG, "cFont::LoadFT2: totalHeight = %d", totalHeight); - syslog(LOG_DEBUG, "cFont::LoadFT2: totalWidth = %d", totalWidth); - syslog(LOG_DEBUG, "cFont::LoadFT2: totalAscent = %d", totalAscent); - syslog(LOG_DEBUG, "cFont::LoadFT2: lineHeight = %d", lineHeight); - syslog(LOG_DEBUG, "cFont::LoadFT2: spaceBetween = %d", spaceBetween); -#endif - // render glyphs for ASCII codes 0 to 255 in our bitmap class - FT_UInt glyph_index; - int num_char; - - for (num_char = 0; num_char < 256; num_char++) - { - if (dingBats) - { - //Get FT char index & load the char - error = FT_Load_Char(face, num_char, FT_LOAD_DEFAULT); - } - else - { - //Get FT char index - glyph_index = FT_Get_Char_Index(face, utf_buff[num_char]); - //Load the char - error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); - } - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Load_Glyph: %x", error); - } + SetTotalHeight( (face->size->metrics.ascender >> 6) - (face->size->metrics.descender >> 6) ); + SetTotalWidth ( face->size->metrics.max_advance >> 6 ); + SetTotalAscent( face->size->metrics.ascender >> 6 ); + SetLineHeight ( face->size->metrics.height >> 6 ); + SetSpaceBetween( 0 ); - // convert to a mono bitmap - error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Render_Glyph: %x", error); - } + ft2_library = library; + ft2_face = face; - // now, fill our pixel data - cBitmap * charBitmap = new cBitmap(face->glyph->advance.x >> 6, totalHeight); - charBitmap->Clear(); - unsigned char * bufPtr = face->glyph->bitmap.buffer; - unsigned char pixel; - for (int y = 0; y < face->glyph->bitmap.rows; y++) - { - for (int x = 0; x < face->glyph->bitmap.width; x++) - { - pixel = (bufPtr[x / 8] >> (7 - x % 8)) & 1; - if (pixel) - charBitmap->DrawPixel((face->glyph->metrics.horiBearingX >> 6) + x, - (face->size->metrics.ascender >> 6) - (face->glyph->metrics.horiBearingY >> 6) + y, - GLCD::clrBlack); - } - bufPtr += face->glyph->bitmap.pitch; - } - SetCharacter((char) num_char, charBitmap); - } - error = FT_Done_Face(face); - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error); - } - error = FT_Done_FreeType(library); - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error); - } + characters_cache=new cBitmapCache(); return true; #else syslog(LOG_ERR, "cFont::LoadFT2: glcdgraphics was compiled without FreeType2 support!!!"); @@ -364,50 +368,45 @@ #endif } -int cFont::Width(char ch) const +int cFont::Width(uint32_t ch) const { - if (characters[(unsigned char) ch]) - return characters[(unsigned char) ch]->Width(); + const cBitmap *bitmap = GetCharacter(ch); + if (bitmap) + return bitmap->Width(); else return 0; } int cFont::Width(const std::string & str) const { - unsigned int i; - int sum = 0; - - for (i = 0; i < str.length(); i++) - { - sum += Width(str[i]); - } - if (str.length() > 1) - { - sum += spaceBetween * (str.length() - 1); - } - return sum; + return Width(str, (unsigned int) str.length()); } int cFont::Width(const std::string & str, unsigned int len) const { unsigned int i; int sum = 0; + unsigned int symcount=0; + uint32_t c; - for (i = 0; i < str.length() && i < len; i++) + i = 0; + while (i < (unsigned int)str.length() && symcount < len) { - sum += Width(str[i]); - } - if (std::min(str.length(), (size_t) len) > 1) - { - sum += spaceBetween * (std::min(str.length(), (size_t) len) - 1); + encodedCharAdjustCounter(IsUTF8(), str, c, i); + symcount++; + sum += Width(c); + i++; } + sum += spaceBetween * (symcount - 1); + return sum; } -int cFont::Height(char ch) const +int cFont::Height(uint32_t ch) const { - if (characters[(unsigned char) ch]) - return characters[(unsigned char) ch]->Height(); + const cBitmap *bitmap = GetCharacter(ch); + if (bitmap) + return bitmap->Height(); else return 0; } @@ -432,13 +431,84 @@ return sum; } -const cBitmap * cFont::GetCharacter(char ch) const +const cBitmap * cFont::GetCharacter(uint32_t ch) const { +#ifdef HAVE_FREETYPE2 + if ( fontType == 2 ) { + //lookup in cache + cBitmap *ptr=characters_cache->GetBitmap(ch); + if (ptr) + return ptr; + + FT_Face face = (FT_Face) ft2_face; + FT_UInt glyph_index; + //Get FT char index + if (isutf8) { + glyph_index = FT_Get_Char_Index(face, ch); + } else { + glyph_index = FT_Get_Char_Index(face, iconv_lut[(unsigned char)ch]); + } + + //Load the char + int error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Load_Glyph: %x", error); + return NULL; + } + + FT_Render_Mode rmode = FT_RENDER_MODE_MONO; +#if ( (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 1 && FREETYPE_PATCH >= 7) || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 2 && FREETYPE_PATCH <= 1) ) + if (ch == 32) rmode = FT_RENDER_MODE_NORMAL; +#endif + + // convert to a mono bitmap + error = FT_Render_Glyph(face->glyph, rmode); + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Render_Glyph: %x", error); + return NULL; + } else { + // now, fill our pixel data + cBitmap *charBitmap = new cBitmap(face->glyph->advance.x >> 6, TotalHeight()); + charBitmap->Clear(cColor::White); + charBitmap->SetMonochrome(true); + unsigned char * bufPtr = face->glyph->bitmap.buffer; + unsigned char pixel; + for (int y = 0; y < face->glyph->bitmap.rows; y++) + { + for (int x = 0; x < face->glyph->bitmap.width; x++) + { + pixel = (bufPtr[x / 8] >> (7 - x % 8)) & 1; + if (pixel) + charBitmap->DrawPixel((face->glyph->metrics.horiBearingX >> 6) + x, + (face->size->metrics.ascender >> 6) - (face->glyph->metrics.horiBearingY >> 6) + y, + /*GLCD::clrBlack*/ cColor::Black); + } + bufPtr += face->glyph->bitmap.pitch; + } + + // adjust maxwidth if necessary + //if (totalWidth < charBitmap->Width()) + // totalWidth = charBitmap->Width(); + + characters_cache->PushBack(ch, charBitmap); + return charBitmap; + } + return NULL; // if any + } // else +#endif return characters[(unsigned char) ch]; } void cFont::SetCharacter(char ch, cBitmap * bitmapChar) { +#ifdef HAVE_FREETYPE2 + if ( fontType == 2 ) { + syslog(LOG_ERR, "cFont::SetCharacter: is not supported with FreeType2 fonts!!!"); + return; + } +#endif // adjust maxwidth if necessary if (totalWidth < bitmapChar->Width()) totalWidth = bitmapChar->Width(); @@ -462,6 +532,12 @@ { characters[i] = NULL; } +#ifdef HAVE_FREETYPE2 + ft2_library = NULL; + ft2_face = NULL; + characters_cache = NULL; +#endif + fontType = 1; } void cFont::Unload() @@ -474,6 +550,13 @@ delete characters[i]; } } +#ifdef HAVE_FREETYPE2 + delete characters_cache; + if (ft2_face) + FT_Done_Face((FT_Face)ft2_face); + if (ft2_library) + FT_Done_FreeType((FT_Library)ft2_library); +#endif // re-init Init(); } @@ -485,97 +568,84 @@ int lineCount; int textWidth; std::string::size_type start; - std::string::size_type pos; + unsigned int pos; std::string::size_type posLast; + uint32_t c; Lines.clear(); - maxLines = 2000; + maxLines = 100; if (Height > 0) { maxLines = Height / LineHeight(); - if (maxLines == 0) - maxLines = 1; + //if (maxLines == 0) + maxLines += 1; } - lineCount = 0; + lineCount = 0; pos = 0; start = 0; posLast = 0; textWidth = 0; - while (pos < Text.length() && (Height == 0 || lineCount < maxLines)) + + while ((pos < Text.length()) && (lineCount <= maxLines)) { - if (Text[pos] == '\n') + unsigned int posraw = pos; + encodedCharAdjustCounter(IsUTF8(), Text, c, posraw); + + if (c == '\n') { Lines.push_back(trim(Text.substr(start, pos - start))); - start = pos + 1; - posLast = pos + 1; + start = pos /*+ 1*/; + posLast = pos /*+ 1*/; textWidth = 0; lineCount++; } - else if (textWidth > Width && (lineCount + 1) < maxLines) + else if (textWidth + this->Width(c) > Width && (lineCount + 1) < maxLines) { if (posLast > start) { Lines.push_back(trim(Text.substr(start, posLast - start))); - start = posLast + 1; + start = posLast /*+ 1*/; posLast = start; textWidth = this->Width(Text.substr(start, pos - start + 1)) + spaceBetween; } else { Lines.push_back(trim(Text.substr(start, pos - start))); - start = pos + 1; + start = pos /*+ 1*/; posLast = start; - textWidth = this->Width(Text[pos]) + spaceBetween; + textWidth = this->Width(c) + spaceBetween; } lineCount++; } - else if (Text[pos] == ' ') + else if (isspace(c)) { posLast = pos; - textWidth += this->Width(Text[pos]) + spaceBetween; + textWidth += this->Width(c) + spaceBetween; + } + else if ( (c < 0x80) && strchr("-.,:;!?_", (int)c) ) + { + posLast = pos+1; + textWidth += this->Width(c) + spaceBetween; } else { - textWidth += this->Width(Text[pos]) + spaceBetween; + textWidth += this->Width(c) + spaceBetween; } + pos = posraw; pos++; } + if (start < Text.length()) { + Lines.push_back(trim(Text.substr(start))); + } - if (Height == 0 || lineCount < maxLines) - { - if (textWidth > Width && (lineCount + 1) < maxLines) - { - if (posLast > start) - { - Lines.push_back(trim(Text.substr(start, posLast - start))); - start = posLast + 1; - posLast = start; - textWidth = this->Width(Text.substr(start, pos - start + 1)) + spaceBetween; - } - else - { - Lines.push_back(trim(Text.substr(start, pos - start))); - start = pos + 1; - posLast = start; - textWidth = this->Width(Text[pos]) + spaceBetween; - } - lineCount++; - } - if (pos > start) - { - Lines.push_back(trim(Text.substr(start))); - lineCount++; - } + if (ActualWidth) { textWidth = 0; for (int i = 0; i < lineCount; i++) textWidth = std::max(textWidth, this->Width(Lines[i])); textWidth = std::min(textWidth, Width); - } - else - textWidth = Width; - if (ActualWidth) *ActualWidth = textWidth; + } } } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/font.h graphlcd-base-0.1.9+git20120310/glcdgraphics/font.h --- graphlcd-base-0.2.0+git20101020/glcdgraphics/font.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/font.h 2012-03-10 09:18:56.000000000 +0000 @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #ifndef _GLCDGRAPHICS_FONT_H_ @@ -23,6 +25,8 @@ namespace GLCD { +class cBitmapCache; + class cFont { private: @@ -33,6 +37,14 @@ int lineHeight; cBitmap * characters[256]; + int fontType; //original or FT2 font, 1-original, 2-ft2 + + bool isutf8; + wchar_t iconv_lut[256]; // lookup table needed if encoding != UTF-8 + + cBitmapCache *characters_cache; + void *ft2_library; //FT_Library + void *ft2_face; //FT_Face protected: void Init(); void Unload(); @@ -40,7 +52,7 @@ cFont(); ~cFont(); - bool LoadFNT(const std::string & fileName); + bool LoadFNT(const std::string & fileName, const std::string & encoding = "UTF-8"); bool SaveFNT(const std::string & fileName) const; bool LoadFT2(const std::string & fileName, const std::string & encoding, int size, bool dingBats = false); @@ -56,18 +68,19 @@ void SetSpaceBetween(int width) { spaceBetween = width; }; void SetLineHeight(int height) { lineHeight = height; }; - int Width(char ch) const; + int Width(uint32_t ch) const; int Width(const std::string & str) const; int Width(const std::string & str, unsigned int len) const; - int Height(char ch) const; + int Height(uint32_t ch) const; int Height(const std::string & str) const; int Height(const std::string & str, unsigned int len) const; - const cBitmap * GetCharacter(char ch) const; + const cBitmap * GetCharacter(uint32_t ch) const; void SetCharacter(char ch, cBitmap * bitmapChar); void WrapText(int Width, int Height, std::string & Text, std::vector & Lines, int * TextWidth = NULL) const; + bool IsUTF8(void) const { return isutf8; } }; } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/glcd.c graphlcd-base-0.1.9+git20120310/glcdgraphics/glcd.c --- graphlcd-base-0.2.0+git20101020/glcdgraphics/glcd.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/glcd.c 2012-03-10 09:18:56.000000000 +0000 @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #include @@ -163,30 +165,53 @@ image.SetWidth(width); image.SetHeight(height); image.SetDelay(delay); - unsigned char * bmpdata = new unsigned char[height * ((width + 7) / 8)]; - if (bmpdata) + unsigned char * bmpdata_raw = new unsigned char[height * ((width + 7) / 8)]; + uint32_t * bmpdata = new uint32_t[height * width]; + if (bmpdata && bmpdata_raw) { for (unsigned int n = 0; n < count; n++) { - if (fread(bmpdata, height * ((width + 7) / 8), 1, fp) != 1) + if (fread(bmpdata_raw, height * ((width + 7) / 8), 1, fp) != 1) { delete[] bmpdata; fclose(fp); image.Clear(); return false; } - image.AddBitmap(new cBitmap(width, height, bmpdata)); + int colsize = (width+7)/8; + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + if ( bmpdata_raw[j*colsize + (i>>3)] & (1 << (7-(i%8))) ) { + bmpdata[j*width+i] = cColor::Black; + } else { + bmpdata[j*width+i] = cColor::White; + } + } + } +#ifdef DEBUG + printf("%s:%s(%d) - filename: '%s', count %d\n", __FILE__, __FUNCTION__, __LINE__, fileName.c_str(), n); +#endif + cBitmap * b = new cBitmap(width, height, bmpdata); + b->SetMonochrome(true); + //image.AddBitmap(new cBitmap(width, height, bmpdata)); + image.AddBitmap(b); } delete[] bmpdata; } else { syslog(LOG_ERR, "glcdgraphics: malloc failed (cGLCDFile::Load)."); + if (bmpdata) + delete[] bmpdata; + if (bmpdata_raw) + delete[] bmpdata_raw; fclose(fp); image.Clear(); return false; } fclose(fp); + if (bmpdata_raw) + delete[] bmpdata_raw; syslog(LOG_DEBUG, "glcdgraphics: image %s loaded.", fileName.c_str()); return true; @@ -260,7 +285,8 @@ { if (bitmap->Width() == width && bitmap->Height() == height) { - if (fwrite(bitmap->Data(), height * ((width + 7) / 8), 1, fp) != 1) +// if (fwrite(bitmap->Data(), height * ((width + 7) / 8), 1, fp) != 1) + if (fwrite(bitmap->Data(), height * width, 1, fp) != 1) { fclose(fp); return false; diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/imagefile.c graphlcd-base-0.1.9+git20120310/glcdgraphics/imagefile.c --- graphlcd-base-0.2.0+git20101020/glcdgraphics/imagefile.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/imagefile.c 2012-03-10 09:18:56.000000000 +0000 @@ -11,6 +11,7 @@ #include "image.h" #include "imagefile.h" +#include "bitmap.h" namespace GLCD { @@ -32,4 +33,132 @@ return false; } + +uint32_t cImageFile::Blend(uint32_t FgColour, uint32_t BgColour, uint8_t Level, double antiAliasGranularity) const +{ + if (antiAliasGranularity > 0.0) + Level = uint8_t(int(Level / antiAliasGranularity + 0.5) * antiAliasGranularity); + int Af = (FgColour & 0xFF000000) >> 24; + int Rf = (FgColour & 0x00FF0000) >> 16; + int Gf = (FgColour & 0x0000FF00) >> 8; + int Bf = (FgColour & 0x000000FF); + int Ab = (BgColour & 0xFF000000) >> 24; + int Rb = (BgColour & 0x00FF0000) >> 16; + int Gb = (BgColour & 0x0000FF00) >> 8; + int Bb = (BgColour & 0x000000FF); + int A = (Ab + (Af - Ab) * Level / 0xFF) & 0xFF; + int R = (Rb + (Rf - Rb) * Level / 0xFF) & 0xFF; + int G = (Gb + (Gf - Gb) * Level / 0xFF) & 0xFF; + int B = (Bb + (Bf - Bb) * Level / 0xFF) & 0xFF; + return (A << 24) | (R << 16) | (G << 8) | B; +} + +bool cImageFile::Scale(cImage & image, uint16_t scalew, uint16_t scaleh, bool AntiAlias) +{ + if (! (scalew || scaleh) ) + return false; + + // one out of scalew/h == 0 ? -> auto aspect ratio + if (scalew && ! scaleh) { + scaleh = (uint16_t)( ((uint32_t)scalew * (uint32_t)image.Height()) / (uint32_t)image.Width() ); + } else if (!scalew && scaleh) { + scalew = (uint16_t)( ((uint32_t)scaleh * (uint32_t)image.Width()) / (uint32_t)image.Height() ); + } + + cImage tempImg = cImage(); + tempImg.SetWidth(scalew); + tempImg.SetHeight(scaleh); + + // Scaling/Blending based on VDR / osd.c + // Fixed point scaling code based on www.inversereality.org/files/bitmapscaling.pdf + // by deltener@mindtremors.com + // + // slightly improved by Wolfgang Astleitner (modify factors and ratios so that scaled image is centered when upscaling) + + double FactorX, FactorY; + int RatioX, RatioY; + + if (!AntiAlias) { + FactorX = (double)scalew / (double)image.Width(); + FactorY = (double)scaleh / (double)image.Height(); + RatioX = (image.Width() << 16) / scalew; + RatioY = (image.Height() << 16) / scaleh; + } else { + FactorX = (double)scalew / (double)(image.Width()-1); + FactorY = (double)scaleh / (double)(image.Height()-1); + RatioX = ((image.Width()-1) << 16) / scalew; + RatioY = ((image.Height()-1) << 16) / scaleh; + } + + bool downscale = (!AntiAlias || (FactorX <= 1.0 && FactorY <= 1.0)); + + for (unsigned int frame = 0; frame < image.Count() ; frame ++ ) { + cBitmap *b = new cBitmap(scalew, scaleh, GRAPHLCD_Transparent); + + cBitmap *currFrame = image.GetBitmap(frame); + + if (downscale) { + // Downscaling - no anti-aliasing: + const uint32_t *DestRow = b->Data(); + int SourceY = 0; + for (int y = 0; y < scaleh; y++) { + int SourceX = 0; + const uint32_t *SourceRow = currFrame->Data() + (SourceY >> 16) * image.Width(); + uint32_t *Dest = (uint32_t*) DestRow; + for (int x = 0; x < scalew; x++) { + *Dest++ = SourceRow[SourceX >> 16]; + SourceX += RatioX; + } + SourceY += RatioY; + DestRow += scalew; + } + } else { + // Upscaling - anti-aliasing: + int SourceY = 0; + for (int y = 0; y < scaleh /*- 1*/; y++) { + int SourceX = 0; + int sy = SourceY >> 16; + uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF); + for (int x = 0; x < scalew /*- 1*/; x++) { + int sx = SourceX >> 16; + uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF); + // TODO: antiAliasGranularity + uint32_t c1 = Blend(currFrame->GetPixel(sx, sy), currFrame->GetPixel(sx + 1, sy), BlendX); + uint32_t c2 = Blend(currFrame->GetPixel(sx, sy + 1), currFrame->GetPixel(sx + 1, sy + 1), BlendX); + uint32_t c3 = Blend(c1, c2, BlendY); + b->DrawPixel(x, y, c3); + SourceX += RatioX; + } + SourceY += RatioY; + } + } + tempImg.AddBitmap(b); + } + // clear all bitmaps from image + image.Clear(); + // set new resolution + image.SetWidth(scalew); + image.SetHeight(scaleh); + // re-add bitmaps from scaled image container + for (unsigned int frame = 0; frame < tempImg.Count(); frame ++) { + image.AddBitmap(new cBitmap(scalew, scaleh, (uint32_t*)tempImg.GetBitmap(frame)->Data())); + } + return true; +} + +bool cImageFile::LoadScaled(cImage & image, const std::string & fileName, uint16_t & scalew, uint16_t & scaleh) +{ + if (Load(image, fileName)) { + if (scalew || scaleh) { + return Scale(image, scalew, scaleh, true); + } else { + return true; + } + } else { + scalew = 0; + scaleh = 0; + return false; + } +} + } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/imagefile.h graphlcd-base-0.1.9+git20120310/glcdgraphics/imagefile.h --- graphlcd-base-0.2.0+git20101020/glcdgraphics/imagefile.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/imagefile.h 2012-03-10 09:18:56.000000000 +0000 @@ -21,11 +21,19 @@ class cImageFile { +private: + uint32_t Blend(uint32_t fgcol, uint32_t bgcol, uint8_t level, double antiAliasGranularity = 0.0) const; +protected: + bool Scale(cImage & image, uint16_t scalew, uint16_t scaleh, bool AntiAlias = false); public: cImageFile(); virtual ~cImageFile(); virtual bool Load(cImage & image, const std::string & fileName); virtual bool Save(cImage & image, const std::string & fileName); + + //virtual bool SupportsScaling(void) { return true; } + + virtual bool LoadScaled(cImage & image, const std::string & fileName, uint16_t & scalew, uint16_t & scaleh); }; } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/Makefile graphlcd-base-0.1.9+git20120310/glcdgraphics/Makefile --- graphlcd-base-0.2.0+git20101020/glcdgraphics/Makefile 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/Makefile 2012-03-10 09:18:56.000000000 +0000 @@ -4,19 +4,30 @@ -include ../Make.config +# External image lib to use: imagemagick, graphicsmagick, or none +# (two ifdef/endif are used because older installations may not support 'else ifdef') +IMAGELIB = +ifdef HAVE_GRAPHICSMAGICK + IMAGELIB = graphicsmagick +endif +ifdef HAVE_IMAGEMAGICK + IMAGELIB = imagemagick +endif + + CXXFLAGS += -fPIC VERMAJOR = 2 -VERMINOR = 0 +VERMINOR = 1 VERMICRO = 0 BASENAME = libglcdgraphics.so LIBNAME = $(BASENAME).$(VERMAJOR).$(VERMINOR).$(VERMICRO) -OBJS = bitmap.o common.o font.o glcd.o image.o imagefile.o pbm.o +OBJS = bitmap.o common.o font.o glcd.o image.o imagefile.o pbm.o extformats.o -HEADERS = bitmap.h font.h glcd.h image.h imagefile.h pbm.h +HEADERS = bitmap.h font.h glcd.h image.h imagefile.h pbm.h extformats.h ### Implicit rules: @@ -43,6 +54,20 @@ DEFINES += -DHAVE_FREETYPE2 endif### Targets: + +# two ifdef/endif are used because older installations may not support 'else ifdef' +ifeq ($(IMAGELIB), imagemagick) + DEFINES += -DHAVE_IMAGEMAGICK + INCLUDES += $(shell pkg-config --cflags ImageMagick++) + LIBS += $(shell pkg-config --libs ImageMagick++) +endif +ifeq ($(IMAGELIB), graphicsmagick) + DEFINES += -DHAVE_IMAGEMAGICK # yep, really HAVE_IMAGEMAGICK here + INCLUDES += $(shell pkg-config --cflags GraphicsMagick++) + LIBS += $(shell pkg-config --libs GraphicsMagick++) +endif + + all: $(LIBNAME) $(LIBNAME): $(OBJS) diff -Nru graphlcd-base-0.2.0+git20101020/glcdgraphics/pbm.c graphlcd-base-0.1.9+git20120310/glcdgraphics/pbm.c --- graphlcd-base-0.2.0+git20101020/glcdgraphics/pbm.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdgraphics/pbm.c 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2006 Andreas Regel + * (c) 2006-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #include @@ -113,18 +115,35 @@ image.SetWidth(w); image.SetHeight(h); image.SetDelay(100); - unsigned char * bmpdata = new unsigned char[h * ((w + 7) / 8)]; - if (bmpdata) + + unsigned char * bmpdata_raw = new unsigned char[h * ((w + 7) / 8)]; + uint32_t * bmpdata = new uint32_t[h * w]; + if (bmpdata && bmpdata_raw) { - if (fread(bmpdata, h * ((w + 7) / 8), 1, pbmFile) != 1) - { + if (fread(bmpdata_raw, h * ((w + 7) / 8), 1, pbmFile) != 1) + { + delete[] bmpdata; + fclose(pbmFile); + image.Clear(); + return false; + } + int colsize = (w+7)/8; + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + if ( bmpdata_raw[j*colsize + (i>>3)] & (1 << (7-(i%8))) ) { + bmpdata[j*w+i] = cColor::Black; + } else { + bmpdata[j*w+i] = cColor::White; + } + } + } + delete [] bmpdata_raw; + + cBitmap * b = new cBitmap(w, h, bmpdata); + b->SetMonochrome(true); + //image.AddBitmap(new cBitmap(width, height, bmpdata)); + image.AddBitmap(b); delete[] bmpdata; - fclose(pbmFile); - image.Clear(); - return false; - } - image.AddBitmap(new cBitmap(w, h, bmpdata)); - delete[] bmpdata; } else { @@ -143,6 +162,9 @@ FILE * fp; char str[32]; const cBitmap * bitmap; + unsigned char* rawdata = NULL; + int rawdata_size = 0; + const uint32_t * bmpdata = NULL; if (image.Count() == 1) { @@ -150,13 +172,29 @@ if (fp) { bitmap = image.GetBitmap(0); - if (bitmap) + rawdata_size = ((bitmap->Width() + 7) / 8) * bitmap->Height(); + rawdata = new unsigned char[ rawdata_size ]; + bmpdata = bitmap->Data(); + + if (bitmap && rawdata && bmpdata) { + memset(rawdata, 0, rawdata_size ); + for (int y = 0; y < bitmap->Height(); y++) { + int startpos = y * ((bitmap->Width() + 7) / 8); + for (int x = 0; x < bitmap->Width(); x++) { + if (bmpdata[ y * bitmap->Width() + x ] == cColor::White) { + rawdata[ startpos + (x / 8) ] |= (1 << ( 7 - ( x % 8 ) )); + } + } + } sprintf(str, "P4\n%d %d\n", bitmap->Width(), bitmap->Height()); fwrite(str, strlen(str), 1, fp); - fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); +// fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); + fwrite(rawdata, rawdata_size, 1, fp); } fclose(fp); + delete[] rawdata; + rawdata = NULL; } } else @@ -171,13 +209,29 @@ if (fp) { bitmap = image.GetBitmap(i); - if (bitmap) + rawdata_size = ((bitmap->Width() + 7) / 8) * bitmap->Height(); + rawdata = new unsigned char[ rawdata_size ]; + bmpdata = bitmap->Data(); + + if (bitmap && rawdata && bmpdata) { + memset(rawdata, 0, rawdata_size ); + for (int y = 0; y < bitmap->Height(); y++) { + int startpos = y * ((bitmap->Width() + 7) / 8); + for (int x = 0; x < bitmap->Width(); x++) { + if (bmpdata[ y * bitmap->Width() + x ] == cColor::Black) { + rawdata[ startpos + (x / 8) ] |= (1 << ( 7 - ( x % 8 ) )); + } + } + } sprintf(str, "P4\n%d %d\n", bitmap->Width(), bitmap->Height()); fwrite(str, strlen(str), 1, fp); - fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); +// fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); + fwrite(rawdata, rawdata_size, 1, fp); } fclose(fp); + delete[] rawdata; + rawdata = NULL; } } } diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/cache.c graphlcd-base-0.1.9+git20120310/glcdskin/cache.c --- graphlcd-base-0.2.0+git20101020/glcdskin/cache.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/cache.c 2012-03-10 09:18:56.000000000 +0000 @@ -12,20 +12,25 @@ #include #include #include +#include #include #include +#include + #include "cache.h" #include "skin.h" namespace GLCD { -cImageItem::cImageItem(const std::string & path, cImage * image) +cImageItem::cImageItem(const std::string & path, cImage * image, uint16_t scalew, uint16_t scaleh) : path(path), counter(0), - image(image) + image(image), + scale_width(scalew), + scale_height(scaleh) { } @@ -43,25 +48,40 @@ cImageCache::~cImageCache() { + Clear(); +} + +void cImageCache::Clear(void) +{ for (unsigned int i = 0; i < images.size(); i++) { delete images[i]; } images.clear(); + failedpaths.clear(); } -cImage * cImageCache::Get(const std::string & path) +cImage * cImageCache::Get(const std::string & path, uint16_t & scalew, uint16_t & scaleh) { std::vector ::iterator it; cImageItem * item; uint64_t maxCounter; std::vector ::iterator oldest; + // test if this path has already been stored as invalid path / invalid/non-existent image + for (size_t i = 0; i < failedpaths.size(); i++) { + if (failedpaths[i] == path) { + return NULL; + } + } + maxCounter = 0; item = NULL; for (it = images.begin(); it != images.end(); it++) { - if (item == NULL && path == (*it)->Path()) + uint16_t scw = 0, sch = 0; + (*it)->ScalingGeometry(scw, sch); + if (item == NULL && path == (*it)->Path() && ( (scw == 0 && sch == 0 && ! (scalew || scaleh)) || (scw == scalew && sch == scaleh))) { (*it)->ResetCounter(); item = (*it); @@ -81,21 +101,25 @@ return item->Image(); } - item = LoadImage(path); + item = LoadImage(path, scalew, scaleh); if (item) { + syslog(LOG_INFO, "INFO: graphlcd: successfully loaded image '%s'\n", path.c_str()); if (images.size() == size) { images.erase(oldest); } images.push_back(item); return item->Image(); + } else { + failedpaths.push_back(path); } return NULL; } -cImageItem * cImageCache::LoadImage(const std::string & path) +cImageItem * cImageCache::LoadImage(const std::string & path, uint16_t scalew, uint16_t scaleh) { + //fprintf(stderr, "### loading image %s\n", path.c_str()); cImageItem * item; cImage * image; char str[8]; @@ -138,6 +162,28 @@ } file += path; } + + cImageFile* imgFile = NULL; + + if (strcmp(str, "PBM") == 0) { + imgFile = new cPBMFile(); + } else if (strcmp(str, "GLCD") == 0) { + imgFile = new cGLCDFile(); + } else { + imgFile = new cExtFormatFile(); + } + + uint16_t scale_width = scalew; + uint16_t scale_height = scaleh; + // scale_width and scale_height are set to 0 if image was NOT scaled + if (!imgFile || (imgFile->LoadScaled(*image, file, scalew /*scale_width*/, scaleh /*scale_height*/) == false) ) { + delete image; + if (imgFile) delete imgFile; + return NULL; + } + delete imgFile; + +#if 0 if (strcmp(str, "PBM") == 0) { cPBMFile pbm; @@ -160,11 +206,17 @@ } else { - delete image; - return NULL; + cExtFormatFile extformat; + + if (extformat.Load(*image, file) == false) + { + delete image; + return NULL; + } } +#endif - item = new cImageItem(path, image); + item = new cImageItem(path, image, scale_width, scale_height); if (!item) { delete image; diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/cache.h graphlcd-base-0.1.9+git20120310/glcdskin/cache.h --- graphlcd-base-0.2.0+git20101020/glcdskin/cache.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/cache.h 2012-03-10 09:18:56.000000000 +0000 @@ -29,11 +29,13 @@ std::string path; uint64_t counter; cImage * image; + uint16_t scale_width, scale_height; public: - cImageItem(const std::string & path, cImage * image); + cImageItem(const std::string & path, cImage * image, uint16_t scalew, uint16_t scaleh); ~cImageItem(); const std::string & Path() const { return path; } + void ScalingGeometry(uint16_t & scalew, uint16_t & scaleh) { scalew = scale_width; scaleh = scale_height; } uint64_t Counter() const { return counter; } cImage * Image() { return image; } void ResetCounter() { counter = 0; } @@ -46,13 +48,21 @@ cSkin * skin; size_t size; std::vector images; + std::vector failedpaths; - cImageItem * LoadImage(const std::string & path); + cImageItem * LoadImage(const std::string & path, uint16_t scalew, uint16_t scaleh); public: cImageCache(cSkin * Parent, int Size); ~cImageCache(); - cImage * Get(const std::string & path); + cImage * Get(const std::string & path, uint16_t & scalew, uint16_t & scaleh); + cImage * Get(const std::string & path) { + uint16_t scalew = 0; + uint16_t scaleh = 0; + return Get(path, scalew, scaleh) ; + } + + void Clear(void); }; } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/config.h graphlcd-base-0.1.9+git20120310/glcdskin/config.h --- graphlcd-base-0.2.0+git20101020/glcdskin/config.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/config.h 2012-03-10 09:18:56.000000000 +0000 @@ -17,12 +17,15 @@ #include +#include "../glcddrivers/driver.h" + namespace GLCD { class cType; class cFont; struct tSkinToken; +class cDriver; class cSkinConfig { @@ -37,6 +40,7 @@ virtual int GetTokenId(const std::string & Name); virtual int GetTabPosition(int Index, int MaxWidth, const cFont & Font); virtual uint64_t Now(void); + virtual cDriver * GetDriver(void) const { return NULL; } }; } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/display.c graphlcd-base-0.1.9+git20120310/glcdskin/display.c --- graphlcd-base-0.2.0+git20101020/glcdskin/display.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/display.c 2012-03-10 09:18:56.000000000 +0000 @@ -39,6 +39,21 @@ } +std::string cSkinDisplay::CheckAction(cGLCDEvent * ev) { + std::string rv = ""; + + if (!ev) + return ""; + + for (uint32_t i = 0; i < NumObjects(); ++i) { + if ( (rv = GetObject(i)->CheckAction(ev) ) != "" ) { + return rv; + } + } + return ""; +} + + cSkinDisplays::cSkinDisplays(void) { } diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/display.h graphlcd-base-0.1.9+git20120310/glcdskin/display.h --- graphlcd-base-0.2.0+git20101020/glcdskin/display.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/display.h 2012-03-10 09:18:56.000000000 +0000 @@ -45,6 +45,8 @@ void Render(cBitmap * screen); bool NeedsUpdate(uint64_t CurrentTime); + + std::string CheckAction(cGLCDEvent * ev); }; class cSkinDisplays: public std::vector diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/function.c graphlcd-base-0.1.9+git20120310/glcdskin/function.c --- graphlcd-base-0.2.0+git20101020/glcdskin/function.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/function.c 2012-03-10 09:18:56.000000000 +0000 @@ -22,7 +22,7 @@ static const char * Internals[] = { - "not", "and", "or", "equal", "gt", "lt", "ge", "le", "ne", "file", "trans", + "not", "and", "or", "equal", "eq", "gt", "lt", "ge", "le", "ne", "file", "trans", "add", "sub", "mul", "div", "FontTotalWidth", "FontTotalHeight", @@ -33,6 +33,7 @@ "FontTextHeight", "ImageWidth", "ImageHeight", + "QueryFeature", NULL }; @@ -74,7 +75,7 @@ delete mParams[i]; } -bool cSkinFunction::Parse(const std::string & Text) +bool cSkinFunction::Parse(const std::string & Text, bool reparse) { const char *text = Text.c_str(); const char *ptr = text, *last = text; @@ -89,7 +90,8 @@ || (*ptr == '\'' && *(ptr + strlen(ptr) - 1) != '\'') || (*ptr == '{' && *(ptr + strlen(ptr) - 1) != '}')) { - syslog(LOG_ERR, "ERROR: Unmatched string end\n"); + if (!reparse) // only log this error when not reparsing + syslog(LOG_ERR, "ERROR: graphlcd/skin/function: Unmatched string end\n"); return false; } @@ -113,7 +115,8 @@ // must be a variable id if (strlen(ptr) < 2) { - syslog(LOG_ERR, "ERROR: No variable id given\n"); + if (!reparse) // only log this error when not reparsing + syslog(LOG_ERR, "ERROR: graphlcd/skin/function: No variable id given\n"); return false; } @@ -127,7 +130,8 @@ int num = strtol(ptr, &end, 10); if (end == ptr || *end != '\0') { - syslog(LOG_ERR, "ERROR: Invalid numeric value\n"); + // don't log this because when parsing a string starting with a digit (eg: 0%) this may result in a load of false positives + //syslog(LOG_ERR, "ERROR: Invalid numeric value (%s)\n", Text.c_str()); return false; } @@ -136,9 +140,17 @@ } else { + bool inToken = false; + // expression for (; *ptr; ++ptr) { + + if (*ptr == '{') + inToken = true; + else if (inToken && *ptr == '}') + inToken = false; + if (*ptr == '(') { if (inExpr++ == 0) @@ -156,17 +168,19 @@ if (Internals[i] == NULL) { - syslog(LOG_ERR, "ERROR: Unknown function %.*s", (int)(ptr - last), last); + if (!reparse) // only log this error when not reparsing + syslog(LOG_ERR, "ERROR: graphlcd/skin/function: Unknown function %.*s", (int)(ptr - last), last); return false; } last = ptr + 1; } } - else if (*ptr == ',' || *ptr == ')') + else if ( ( (!inToken) && (*ptr == ',') ) || *ptr == ')') { if (inExpr == 0) { - syslog(LOG_ERR, "ERROR: Unmatched '%c' in expression", *ptr); + if (!reparse) // only log this error when not reparsing + syslog(LOG_ERR, "ERROR: graphlcd/skin/function: Unmatched '%c' in expression (%s)", *ptr, Text.c_str()); return false; } @@ -181,8 +195,9 @@ if (mNumParams == MAXPARAMETERS) { - syslog(LOG_ERR, "ERROR: Too many parameters to function, maximum is %d", - MAXPARAMETERS); + if (!reparse) // only log this error when not reparsing + syslog(LOG_ERR, "ERROR: graphlcd/skin/function: Too many parameters to function, maximum is %d", + MAXPARAMETERS); return false; } @@ -204,6 +219,7 @@ params = -1; break; + case fun_equal: case fun_eq: case fun_ne: case fun_gt: @@ -247,13 +263,17 @@ params = 1; break; + case funQueryFeature: + params = 1; + break; + default: break; } if (params != -1 && mNumParams != (uint32_t) params) { - syslog(LOG_ERR, "ERROR: Text2Skin: Wrong number of parameters to %s, " + syslog(LOG_ERR, "ERROR: graphlcd/skin/function: Wrong number of parameters to %s, " "expecting %d", Internals[mType - INTERNAL], params); return false; } @@ -266,7 +286,9 @@ if (inExpr > 0) { - syslog(LOG_ERR, "ERROR: Expecting ')' in expression"); + // only log this error when not reparsing + if (!reparse) + syslog(LOG_ERR, "ERROR: Expecting ')' in expression"); return false; } } @@ -345,8 +367,21 @@ case variable: { cSkinVariable * variable = mSkin->GetVariable(mVariableId); - if (variable) - return variable->Value(); + if (variable) { + cType rv = variable->Value(); + if (rv.IsString()) { + std::string val = rv; + if (val.find("{") != std::string::npos || val.find("#") != std::string::npos) { + cSkinString *result = new cSkinString(mObject, false); + if (result->Parse(val)) { + val = (std::string) result->Evaluate(); + rv = cType(val); + } + delete result; + } + } + return rv; + } return false; } @@ -369,6 +404,7 @@ } return false; + case fun_equal: case fun_eq: return mParams[0]->Evaluate() == mParams[1]->Evaluate(); @@ -443,9 +479,18 @@ case funImageHeight: return FunImage(mType, mParams[0]->Evaluate()); + case funQueryFeature: { + int value; + if (mSkin->Config().GetDriver()->GetFeature((const std::string)(mParams[0]->Evaluate()), value)) { + return (value) ? true : false; + } else { + return false; + } + } + default: //Dprintf("unknown function code\n"); - syslog(LOG_ERR, "ERROR: Unknown function code called (this shouldn't happen)"); + syslog(LOG_ERR, "ERROR: graphlcd/skin/function: Unknown function code called (this shouldn't happen)"); break; } return false; diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/function.h graphlcd-base-0.1.9+git20120310/glcdskin/function.h --- graphlcd-base-0.2.0+git20101020/glcdskin/function.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/function.h 2012-03-10 09:18:56.000000000 +0000 @@ -47,6 +47,7 @@ fun_not = INTERNAL, fun_and, fun_or, + fun_equal, fun_eq, fun_gt, fun_lt, @@ -70,7 +71,9 @@ funFontTextHeight, funImageWidth, - funImageHeight + funImageHeight, + + funQueryFeature }; private: @@ -94,7 +97,7 @@ cSkinFunction(const cSkinFunction &Src); ~cSkinFunction(); - bool Parse(const std::string &Text); + bool Parse(const std::string &Text, bool reparse = false); cType Evaluate(void) const; void SetListIndex(int MaxItems, int Index); diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/Makefile graphlcd-base-0.1.9+git20120310/glcdskin/Makefile --- graphlcd-base-0.2.0+git20101020/glcdskin/Makefile 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/Makefile 2012-03-10 09:18:56.000000000 +0000 @@ -7,8 +7,8 @@ CXXFLAGS += -fPIC -VERMAJOR = 1 -VERMINOR = 0 +VERMAJOR = 2 +VERMINOR = 1 VERMICRO = 0 BASENAME = libglcdskin.so @@ -19,6 +19,11 @@ HEADERS = cache.h config.h display.h font.h function.h object.h parser.h skin.h string.h type.h variable.h xml.h + +### Inner graphlcd-base dependencies +LIBS += -L../glcdgraphics -lglcdgraphics -L../glcddrivers -lglcddrivers + + ### Implicit rules: %.o: %.c diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/object.c graphlcd-base-0.1.9+git20120310/glcdskin/object.c --- graphlcd-base-0.2.0+git20101020/glcdskin/object.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/object.c 2012-03-10 09:18:56.000000000 +0000 @@ -4,6 +4,8 @@ #include "cache.h" #include "function.h" +#include + namespace GLCD { @@ -19,18 +21,27 @@ "text", "scrolltext", "scrollbar", + "button", "block", "list", - "item" + "item", + "condblock" }; cSkinObject::cSkinObject(cSkinDisplay * Parent) : mDisplay(Parent), mSkin(Parent->Skin()), mType((eType) __COUNT_OBJECT__), - mPos1(0, 0), - mPos2(-1, -1), - mColor(GLCD::clrBlack), + //mPos1(0, 0), + //mPos2(-1, -1), + mX1(this, false), + mY1(this, false), + mX2(this, false), + mY2(this, false), + mWidth(this, false), + mHeight(this, false), + mColor(this, cColor(cColor::Black)), + mBackgroundColor(this, cColor(cColor::Transparent)), mFilled(false), mRadius(0), mArc(0), @@ -41,13 +52,20 @@ mPath(this, false), mCurrent(this, false), mTotal(this, false), + mPeak(this, false), mFont(this, false), mText(this, false), mCondition(NULL), + mEffect(tfxNone), + mEffectColor(this, cColor(cColor::White)), + mPeakGradientColor(this, cColor(cColor::ERRCOL)), // color for peak or gradient; if ERRCOL -> use mColor + mGradient(tgrdNone), // default: no gradient mLastChange(0), mChangeDelay(-1), // delay between two images frames: -1: not animated / don't care mStoredImagePath(""), mImageFrameId(0), // start with 1st frame + mOpacity(255), // default: full opacity + mScale(tscNone), // scale image: default: don't scale mScrollLoopMode(-1), // scroll (text) or loop (image) mode: default (-1) mScrollLoopReached(false), // if scroll/loop == once: already looped once? mScrollSpeed(0), // scroll speed: default (0) @@ -56,17 +74,29 @@ mCurrText(""), // current text (for checks if text has changed) mAltText(""), // alternative text source for text-objects mAltCondition(NULL), // condition when alternative sources are used + mAction(""), // action (e.g. touchscreen action) + mMultilineScrollPosition(0), + mMultilineRelScroll(this, false), mObjects(NULL) { + mColor.SetColor(Parent->Skin()->Config().GetDriver()->GetForegroundColor()); + mBackgroundColor.SetColor(Parent->Skin()->Config().GetDriver()->GetBackgroundColor()); } cSkinObject::cSkinObject(const cSkinObject & Src) : mDisplay(Src.mDisplay), mSkin(Src.mSkin), mType(Src.mType), - mPos1(Src.mPos1), - mPos2(Src.mPos2), + //mPos1(Src.mPos1), + //mPos2(Src.mPos2), + mX1(Src.mX1), + mY1(Src.mY1), + mX2(Src.mX2), + mY2(Src.mY2), + mWidth(Src.mWidth), + mHeight(Src.mHeight), mColor(Src.mColor), + mBackgroundColor(Src.mBackgroundColor), mFilled(Src.mFilled), mRadius(Src.mRadius), mArc(Src.mArc), @@ -77,13 +107,20 @@ mPath(Src.mPath), mCurrent(Src.mCurrent), mTotal(Src.mTotal), + mPeak(Src.mPeak), mFont(Src.mFont), mText(Src.mText), mCondition(Src.mCondition), + mEffect(Src.mEffect), + mEffectColor(Src.mEffectColor), + mPeakGradientColor(Src.mPeakGradientColor), + mGradient(Src.mGradient), mLastChange(0), mChangeDelay(-1), mStoredImagePath(Src.mStoredImagePath), mImageFrameId(0), + mOpacity(Src.mOpacity), + mScale(Src.mScale), mScrollLoopMode(Src.mScrollLoopMode), mScrollLoopReached(Src.mScrollLoopReached), mScrollSpeed(Src.mScrollSpeed), @@ -92,6 +129,9 @@ mCurrText(Src.mCurrText), mAltText(Src.mAltText), mAltCondition(Src.mAltCondition), + mAction(Src.mAction), + mMultilineScrollPosition(Src.mMultilineScrollPosition), + mMultilineRelScroll(Src.mMultilineRelScroll), mObjects(NULL) { if (Src.mObjects) @@ -116,14 +156,27 @@ return false; } -bool cSkinObject::ParseColor(const std::string & Text) +bool cSkinObject::ParseColor(const std::string & Text, cSkinColor & ParamColor) { - if (Text == "white") - mColor = GLCD::clrWhite; - else if (Text == "black") - mColor = GLCD::clrBlack; - else + std::string text = (std::string) Text; + cColor color = cColor::ERRCOL; + if (text[0] == '#') { + cSkinVariable * variable = mSkin->GetVariable(text.substr(1)); + if (variable) { + color = cColor::ParseColor(variable->Value().String()); + if (color == cColor::ERRCOL) { + return false; + } + ParamColor.SetVarId(text.substr(1)); + return true; + } return false; + } + color = cColor::ParseColor(text); + if (color == cColor::ERRCOL) { + return false; + } + ParamColor.SetColor(color); return true; } @@ -165,6 +218,51 @@ return true; } +bool cSkinObject::ParseEffect(const std::string & Text) +{ + if (Text == "none") + mEffect = tfxNone; + else if (Text == "shadow") + mEffect = tfxShadow; + else if (Text == "outline") + mEffect = tfxOutline; + else + return false; + return true; +} + +bool cSkinObject::ParseScale(const std::string & Text) +{ + if (Text == "none") + mScale = tscNone; + else if (Text == "auto") + mScale = tscAuto; + else if (Text == "autox") + mScale = tscAutoX; + else if (Text == "autoy") + mScale = tscAutoY; + else if (Text == "fill") + mScale = tscFill; + else + return false; + return true; +} + +bool cSkinObject::ParseGradient(const std::string & Text) +{ + if (Text == "none") + mGradient = tgrdNone; + else if (Text == "total" || Text == "default") + mGradient = tgrdTotal; + else if (Text == "current" || Text == "currentonly") + mGradient = tgrdCurrent; + else if (Text == "vertical") + mGradient = tgrdVertical; + else + return false; + return true; +} + bool cSkinObject::ParseIntParam(const std::string &Text, int & Param) { if (isalpha(Text[0]) || Text[0] == '#') @@ -189,6 +287,7 @@ return true; } +#if 0 bool cSkinObject::ParseWidth(const std::string &Text) { int w; @@ -214,6 +313,7 @@ } return false; } +#endif bool cSkinObject::ParseFontFace(const std::string & Text) { @@ -292,16 +392,33 @@ tPoint cSkinObject::Pos(void) const { - return tPoint(mPos1.x < 0 ? mSkin->BaseSize().w + mPos1.x : mPos1.x, - mPos1.y < 0 ? mSkin->BaseSize().h + mPos1.y : mPos1.y); + int x1 = mX1.Evaluate(); + int y1 = mY1.Evaluate(); + return tPoint(x1 < 0 ? mSkin->BaseSize().w + x1 : x1, + y1 < 0 ? mSkin->BaseSize().h + y1 : y1); } tSize cSkinObject::Size(void) const { - tPoint p1(mPos1.x < 0 ? mSkin->BaseSize().w + mPos1.x : mPos1.x, - mPos1.y < 0 ? mSkin->BaseSize().h + mPos1.y : mPos1.y); - tPoint p2(mPos2.x < 0 ? mSkin->BaseSize().w + mPos2.x : mPos2.x, - mPos2.y < 0 ? mSkin->BaseSize().h + mPos2.y : mPos2.y); + int x1 = mX1.Evaluate(); + int y1 = mY1.Evaluate(); + tPoint p1(x1 < 0 ? mSkin->BaseSize().w + x1 : x1, + y1 < 0 ? mSkin->BaseSize().h + y1 : y1); + + int w = mWidth.Evaluate(); + int h = mHeight.Evaluate(); + + int x2 = mX2.Evaluate(); + if (w != 0 && x2 == -1) { + x2 = x1 + w - 1; + } + int y2 = mY2.Evaluate(); + if (h != 0 && y2 == -1) { + y2 = y1 + h - 1; + } + + tPoint p2((x2 < 0) ? mSkin->BaseSize().w + x2 : x2, + (y2 < 0) ? mSkin->BaseSize().h + y2 : y2); return tSize(p2.x - p1.x + 1, p2.y - p1.y + 1); } @@ -332,7 +449,47 @@ mChangeDelay = -1; } - GLCD::cImage * image = cache->Get(evalPath); + uint16_t scalew = 0; + uint16_t scaleh = 0; + + switch (mScale) { + case tscAuto: + { + uint16_t w_temp = 0; + uint16_t h_temp = 0; + // get dimensions of unscaled image + GLCD::cImage * image = cache->Get(evalPath, w_temp, h_temp); + if (image) { + w_temp = image->Width(); + h_temp = image->Height(); + if (w_temp != Size().w || h_temp != Size().h) { + double fw = (double)Size().w / (double)w_temp; + double fh = (double)Size().h / (double)h_temp; + if (fw < fh) { + scalew = Size().w; + } else { + scaleh = Size().h; + } + } + } + } + break; + case tscAutoX: + scalew = Size().w; + break; + case tscAutoY: + scaleh = Size().h; + break; + case tscFill: + scalew = Size().w; + scaleh = Size().h; + break; + default: + scalew = 0; + scaleh = 0; + } + + GLCD::cImage * image = cache->Get(evalPath, scalew, scaleh); if (image) { int framecount = image->Count(); @@ -341,7 +498,20 @@ if (bitmap) { - screen->DrawBitmap(Pos().x, Pos().y, *bitmap, mColor); + uint16_t xoff = 0; + uint16_t yoff = 0; + if (scalew || scaleh) { + if (image->Width() < (uint16_t)Size().w) { + xoff = (Size().w - image->Width() ) / 2; + } else if (image->Height() < (uint16_t)Size().h) { + yoff = (Size().h - image->Height() ) / 2; + } + } + + if (mColor == cColor::ERRCOL) + screen->DrawBitmap(Pos().x + xoff, Pos().y + yoff, *bitmap); + else + screen->DrawBitmap(Pos().x + xoff, Pos().y + yoff, *bitmap, mColor, mBackgroundColor, mOpacity); } if (mScrollLoopMode != -1) // if == -1: currScrollLoopMode already contains correct value @@ -350,7 +520,7 @@ if (framecount > 1 && currScrollLoopMode > 0 && !mScrollLoopReached) { mChangeDelay = image->Delay(); - if ( (int)(timestamp - mLastChange) >= mChangeDelay) { + if ( (uint32_t)(timestamp - mLastChange) >= (uint32_t)mChangeDelay) { if (currScrollLoopMode == 1 && mImageFrameId+1 == framecount) { mScrollLoopReached = true; // stop looping and switch to 1st frame @@ -405,33 +575,135 @@ { int current = mCurrent.Evaluate(); int total = mTotal.Evaluate(); + int peak = mPeak.Evaluate(); if (total == 0) total = 1; if (current > total) current = total; - if (mDirection == 0) - { - int w = Size().w * current / total; - if (w > 0) - screen->DrawRectangle(Pos().x, Pos().y, Pos().x + w - 1, Pos().y + Size().h - 1, mColor, true); - } - else if (mDirection == 1) - { - int h = Size().h * current / total; - if (h > 0) - screen->DrawRectangle(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + h - 1, mColor, true); - } - else if (mDirection == 2) - { - int w = Size().w * current / total; - if (w > 0) - screen->DrawRectangle(Pos().x + Size().w - w, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mColor, true); + if (peak > total) + peak = total; + + int maxSize = ( (mDirection % 2) == 0 ) ? Size().w : Size().h; + int currSize = maxSize * current / total; + + int peakSize = 0; + int peakBarSize = 2; + uint32_t peakGradientColor = (mPeakGradientColor == cColor::ERRCOL) ? mColor : mPeakGradientColor; + + bool gradient = false; + + if (peakGradientColor != mColor) { + if (mGradient != tgrdNone) { + gradient = true; + } else if (peak > 0) { + peakSize = maxSize * peak / total; + if (mRadius <= 0) { + peakBarSize = maxSize / 20; + if (peakBarSize < 2) + peakBarSize = 2; + } else { + peakBarSize = mRadius; + } + // at least peakBarSize of empty space between normal progress bar and peak marker. if too small: don't show peak marker + if (currSize + peakBarSize + (peakBarSize / 2) >= peakSize) + peakSize = 0; // don't show at all + } } - else if (mDirection == 3) - { - int h = Size().h * current / total; - if (h > 0) - screen->DrawRectangle(Pos().x, Pos().y + Size().h - h, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mColor, true); + + if (! gradient) { + if (mDirection == 0) + { + if (currSize > 0) + screen->DrawRectangle(Pos().x , Pos().y, + Pos().x + currSize - 1, Pos().y + Size().h - 1, mColor, true); + if (peakSize > 0) + screen->DrawRectangle(Pos().x + peakSize-1 , Pos().y, + Pos().x + peakSize-1 + peakBarSize-1, Pos().y + Size().h - 1, peakGradientColor, true); + } + else if (mDirection == 1) + { + if (currSize > 0) + screen->DrawRectangle(Pos().x , Pos().y, + Pos().x + Size().w - 1, Pos().y + currSize - 1, mColor, true); + if (peakSize > 0) + screen->DrawRectangle(Pos().x , Pos().y + peakSize-1, + Pos().x + Size().w - 1, Pos().y + peakSize-1 + peakBarSize-1, peakGradientColor, true); + } + else if (mDirection == 2) + { + if (currSize > 0) + screen->DrawRectangle(Pos().x + Size().w - currSize, Pos().y, + Pos().x + Size().w - 1 , Pos().y + Size().h - 1, mColor, true); + if (peakSize > 0) + screen->DrawRectangle(Pos().x + Size().w + maxSize - peakSize , Pos().y, + Pos().x + maxSize - peakSize + peakBarSize-1, Pos().y + Size().h - 1, peakGradientColor, true); + } + else if (mDirection == 3) + { + if (currSize > 0) + screen->DrawRectangle(Pos().x , Pos().y + Size().h - currSize, + Pos().x + Size().w - 1, Pos().y + Size().h - 1 , mColor, true); + if (peakSize > 0) + screen->DrawRectangle(Pos().x , Pos().y + maxSize - peakSize, + Pos().x + Size().w - 1, Pos().y + maxSize - peakSize + peakBarSize-1, peakGradientColor, true); + } + } else { + if (currSize > 0) { + int s_a = (mColor & 0xFF000000) >> 24; + int s_r = (mColor & 0x00FF0000) >> 16; + int s_g = (mColor & 0x0000FF00) >> 8; + int s_b = (mColor & 0x000000FF) ; + int delta_a = ((peakGradientColor & 0xFF000000) >> 24) - s_a; + int delta_r = ((peakGradientColor & 0x00FF0000) >> 16) - s_r; + int delta_g = ((peakGradientColor & 0x0000FF00) >> 8) - s_g; + int delta_b = ((peakGradientColor & 0x000000FF) ) - s_b; + int c_a, c_r, c_g, c_b; + double fact; + uint32_t currCol; + int gradSize = 0; + switch (mGradient) { + case tgrdCurrent: gradSize = currSize; break; + case tgrdVertical: gradSize = (mDirection % 2 == 0) ? Size().h : Size().w ; break; + default: gradSize = maxSize; break; + } + + for (int i = 0; i < ((mGradient == tgrdVertical) ? gradSize : currSize); i++) { + fact = (double)i / (double)(gradSize - 1); + c_a = s_a + int( double(delta_a) * fact ); + c_r = s_r + int( double(delta_r) * fact ); + c_g = s_g + int( double(delta_g) * fact ); + c_b = s_b + int( double(delta_b) * fact ); + currCol = (c_a << 24) | (c_r << 16) | (c_g << 8) | c_b; + //fprintf(stderr, "i: %d / %08x -> %08x / currCol: %08x\n", i, (uint32_t)mColor, peakGradientColor, currCol); + if (mGradient == tgrdVertical) { + if (mDirection == 0) + screen->DrawLine(Pos().x, Pos().y + i, + Pos().x + currSize - 1, Pos().y + i, currCol); + else if (mDirection == 2) + screen->DrawLine(Pos().x + Size().w - currSize, Pos().y + i, + Pos().x + Size().w - 1, Pos().y + i, currCol); + else if (mDirection == 1) + screen->DrawLine(Pos().x + Size().w - 1 - i, Pos().y, + Pos().x + Size().w - 1 - i, Pos().y + currSize - 1, currCol); + else if (mDirection == 3) + screen->DrawLine(Pos().x + i, Pos().y + Size().h - currSize, + Pos().x + i, Pos().y + Size().h - 1 , currCol); + } else { + if (mDirection == 0) + screen->DrawLine(Pos().x + i, Pos().y, + Pos().x + i, Pos().y + Size().h - 1, currCol); + else if (mDirection == 2) + screen->DrawLine(Pos().x + Size().w - 1 - i, Pos().y, + Pos().x + Size().w - 1 - i, Pos().y + Size().h - 1, currCol); + else if (mDirection == 1) + screen->DrawLine(Pos().x , Pos().y + i, + Pos().x + Size().w - 1, Pos().y + i, currCol); + else if (mDirection == 3) + screen->DrawLine(Pos().x , Pos().y + Size().h - 1 - i, + Pos().x + Size().w - 1, Pos().y + Size().h - 1 - i , currCol); + } + } + } } break; } @@ -462,8 +734,48 @@ currScrollTime = (int)(t); } + // amount of loops for effects (no effect: 1 loop) + int loop; + int loops = 1; + int varx[6] = {0, 0, 0, 0, 0, 0}; + int vary[6] = {0, 0, 0, 0, 0, 0}; + uint32_t varcol[6] = { mColor, mColor, mColor, mColor, mColor, mColor }; + + int fxOff = 1; + if (mRadius > 1) + fxOff = 2; + + switch (mEffect) { + case tfxShadow: + loops = 1; + for (int fxi = 0; fxi < fxOff; fxi++) { + varx[fxi] = fxi + 1; vary[fxi] = fxi + 1; + varcol[loops-1] = mEffectColor; + loops++; + } + varcol[loops-1] = cColor::Transparent; + loops++; + break; + case tfxOutline: + loops = 6; + varx[0] = -fxOff; vary[0] = 0; + varx[1] = fxOff; vary[1] = 0; + varx[2] = 0; vary[2] = -fxOff; + varx[3] = 0; vary[3] = fxOff; + varcol[0] = varcol[1] = varcol[2] = varcol[3] = mEffectColor; + varcol[4] = cColor::Transparent; + break; + case tfxNone: // no-one gets forgotten here, so make g++ happy + default: + loops = 1; + } + if (skinFont) { + + cBitmap* pane = new cBitmap(Size().w, Size().h, cColor::Transparent); + pane->SetProcessAlpha(false); + const cFont * font = skinFont->Font(); std::string text = ""; @@ -484,6 +796,7 @@ mCurrText = text; mScrollLoopReached = false; mLastChange = timestamp; + mMultilineScrollPosition = 0; } if (mMultiline) @@ -492,7 +805,24 @@ mScrollLoopReached = true; // avoid check in NeedsUpdate() std::vector lines; - font->WrapText(Size().w, Size().h, text, lines); + font->WrapText(Size().w, 0/*Size().h*/, text, lines); + + size_t amount_lines = Size().h / font->LineHeight(); + + if (amount_lines < lines.size()) { + int multilineRelScroll = mMultilineRelScroll.Evaluate(); + if (multilineRelScroll != 0) { + if (multilineRelScroll < 0) { + mMultilineScrollPosition += multilineRelScroll; + if (mMultilineScrollPosition < 0) + mMultilineScrollPosition = 0; + } else if (multilineRelScroll > 0) { + mMultilineScrollPosition += multilineRelScroll; + if (mMultilineScrollPosition > (int)((lines.size() - amount_lines)) ) + mMultilineScrollPosition = lines.size() - amount_lines; + } + } + } // vertical alignment, calculate y offset int yoff = 0; @@ -507,10 +837,14 @@ default: yoff = 0; } - for (size_t i = 0; i < lines.size(); i++) + int end_line = amount_lines; + if (amount_lines > lines.size() ) + end_line = lines.size(); + + for (size_t i = 0; i < (size_t)end_line; i++) { - int w = font->Width(lines[i]); - int x = Pos().x; + int w = font->Width(lines[i + mMultilineScrollPosition]); + int x = 0; if (w < Size().w) { if (mAlign == taRight) @@ -522,7 +856,12 @@ x += (Size().w - w) / 2; } } - screen->DrawText(x, yoff + Pos().y + i * font->LineHeight(), x + Size().w - 1, lines[i], font, mColor); + for (loop = 0; loop < loops; loop++) { + pane->DrawText( + varx[loop] + x, vary[loop] + yoff + i * font->LineHeight(), + x + Size().w - 1, lines[i + mMultilineScrollPosition], font, varcol[loop], mBackgroundColor + ); + } } } else @@ -549,7 +888,7 @@ std::string::size_type pos1; std::string::size_type pos2; std::string str; - int x = Pos().x; + int x = 0; int w = Size().w; int tab = 0; int tabWidth; @@ -560,7 +899,9 @@ { str = text.substr(pos1, pos2 - pos1); tabWidth = mSkin->Config().GetTabPosition(tab, Size().w, *font); - screen->DrawText(x, yoff + Pos().y, x + tabWidth - 1, str, font, mColor); + for (loop = 0; loop < loops; loop++) { + pane->DrawText( varx[loop] + x, vary[loop] + yoff, x + tabWidth - 1, str, font, varcol[loop], mBackgroundColor ); + } pos1 = pos2 + 1; pos2 = text.find('\t', pos1); tabWidth += font->Width(' '); @@ -569,12 +910,14 @@ tab++; } str = text.substr(pos1); - screen->DrawText(x, yoff + Pos().y, x + w - 1, str, font, mColor); + for (loop = 0; loop < loops; loop++) { + pane->DrawText( varx[loop] + x, vary[loop] + yoff, x + w - 1, str, font, varcol[loop], mBackgroundColor ); + } } else { int w = font->Width(text); - int x = Pos().x; + int x = 0; bool updateScroll = false; if (w < Size().w) @@ -601,7 +944,7 @@ currScrollTime = mScrollTime; if (currScrollLoopMode > 0 && (!mScrollLoopReached || mScrollOffset) && - ((int)(timestamp-mLastChange) >= currScrollTime) + ((uint32_t)(timestamp-mLastChange) >= (uint32_t)currScrollTime) ) { if (mScrollLoopReached) @@ -615,22 +958,31 @@ if (mScrollOffset) { int corr_scrolloffset = mScrollOffset; /* object update before scrolltime? use previous offset to avoid 'stumbling' scrolling */ - if ((int)(timestamp-mLastChange) < currScrollTime) { + if ((uint32_t)(timestamp-mLastChange) < (uint32_t)currScrollTime) { corr_scrolloffset -= currScrollSpeed; if (corr_scrolloffset < 0) corr_scrolloffset = 0; } w += font->Width(" "); std::string textdoubled = text + " " + text; - screen->DrawText(x, yoff + Pos().y, x + Size().w - 1, textdoubled, font, mColor, true, corr_scrolloffset); + for (loop = 0; loop < loops; loop++) { + pane->DrawText( + varx[loop] + x, vary[loop] + yoff, x + Size().w - 1, textdoubled, font, + varcol[loop], mBackgroundColor, true, corr_scrolloffset + ); + } } else { - screen->DrawText(x, yoff + Pos().y, x + Size().w - 1, text, font, mColor, true, mScrollOffset); + for (loop = 0; loop < loops; loop++) { + pane->DrawText( + varx[loop] + x, vary[loop] + yoff, x + Size().w - 1, text, font, + varcol[loop], mBackgroundColor, true, mScrollOffset + ); + } } if (updateScroll) { - mScrollOffset += currScrollSpeed; - - if ( x + Size().w + mScrollOffset >= (w+Size().w - font->Width(" "))) { + mScrollOffset += currScrollSpeed; + if ( mScrollOffset >= w ) { if (currScrollLoopMode == 1) // reset mScrollOffset in next step (else: string not redrawn when scroll done) mScrollLoopReached = true; @@ -642,6 +994,8 @@ } } } + screen->DrawBitmap(Pos().x, Pos().y, *pane, cColor::White, cColor::Transparent); + delete pane; } break; } @@ -651,6 +1005,44 @@ // Object->Align()); // break; + case cSkinObject::button: + { + cSkinFont * skinFont = mSkin->GetFont(mFont.Evaluate()); + + if (mBackgroundColor == mColor || mBackgroundColor == cColor::Transparent) + mBackgroundColor.SetColor( (cColor(mColor).Invert()) ); + + if (mRadius == 0) + screen->DrawRectangle(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mBackgroundColor, true); + else + screen->DrawRoundRectangle(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mBackgroundColor, true, mRadius); + + if (skinFont) + { + const cFont * font = skinFont->Font(); + std::string text = ""; + + text = (std::string) mText.Evaluate(); + + if (! (text == mCurrText) ) { + mCurrText = text; + } + std::vector lines; + font->WrapText(Size().w, Size().h, text, lines); + + // always use middle vertical alignment for buttons + int diff = Size().h - lines.size() * font->LineHeight(); + int yoff = (diff > 0) ? diff >> 1 : 0; + + int w = font->Width(text); + int x = Pos().x; + if (w < Size().w) // always center alignment for buttons + x += (Size().w - w) / 2; + screen->DrawText(x, yoff + Pos().y, x + Size().w - 1, text, font, mColor, mBackgroundColor); + } + break; + } + case cSkinObject::scrollbar: //DrawScrollbar(Object->Pos(), Object->Size(), Object->Bg(), Object->Fg()); break; @@ -673,14 +1065,22 @@ { for (int j = 1; j < (int) NumObjects(); j++) { + int px, py, ph,pw; + char buf[10]; const cSkinObject * o = GetObject(j); cSkinObject obj(*o); obj.SetListIndex(maxitems, i); if (obj.Condition() != NULL && !obj.Condition()->Evaluate()) continue; - obj.mPos1.x += mPos1.x; - obj.mPos1.y += mPos1.y + yoffset; - obj.mPos2.y += mPos1.y + yoffset; + px = obj.Pos().x + Pos().x; // obj.mPos1.x += mPos1.x; + py = obj.Pos().y + Pos().y + yoffset; // obj.mPos1.y += mPos1.y + yoffset; + ph = o->Size().h; // obj.mPos2.y += mPos1.y + yoffset; + pw = o->Size().w; + snprintf(buf, 9, "%d", px); obj.mX1.Parse((const char*)buf); + snprintf(buf, 9, "%d", py); obj.mY1.Parse((const char*)buf); + if (ph > 0) + snprintf(buf, 9, "%d", ph); obj.mHeight.Parse((const char*)buf); + snprintf(buf, 9, "%d", pw); obj.mWidth.Parse((const char*)buf); obj.Render(screen); } yoffset += itemheight; @@ -710,7 +1110,7 @@ currScrollLoopMode = mScrollLoopMode; if ( mChangeDelay > 0 && currScrollLoopMode > 0 && !mScrollLoopReached && - ( (int)(CurrentTime-mLastChange) >= mChangeDelay) + ( (uint32_t)(CurrentTime-mLastChange) >= (uint32_t)mChangeDelay) ) { return true; @@ -720,6 +1120,7 @@ } case cSkinObject::text: case cSkinObject::scrolltext: + //case cSkinObject::button: { int currScrollLoopMode = 1; // default values if no setup default values available int currScrollTime = 500; @@ -759,7 +1160,7 @@ if ( (text != mCurrText) || ( (currScrollLoopMode > 0) && (!mScrollLoopReached || mScrollOffset) && - ((int)(CurrentTime-mLastChange) >= currScrollTime) + ((uint32_t)(CurrentTime-mLastChange) >= (uint32_t)currScrollTime) ) ) { @@ -788,6 +1189,71 @@ } +std::string cSkinObject::CheckAction(cGLCDEvent * ev) +{ + if (mCondition != NULL && !mCondition->Evaluate()) + return ""; + + switch (Type()) + { + case cSkinObject::image: + case cSkinObject::text: + case cSkinObject::scrolltext: + case cSkinObject::progress: + case cSkinObject::rectangle: + case cSkinObject::ellipse: + case cSkinObject::slope: + case cSkinObject::button: + case cSkinObject::item: + { + if (mAction == "") + return ""; + + if (ev && (typeid(*ev) == typeid(cSimpleTouchEvent))) { + cSimpleTouchEvent * stev = (cSimpleTouchEvent*)ev; + // check if touch event is in bounding box of object + // uses > and < -1 instead of >= and < -0 for better results + if ( (stev->x > Pos().x) && (stev->x < (Pos().x+Size().w -1)) && + (stev->y > Pos().y) && (stev->y < (Pos().y+Size().h -1)) + ) + { + return mAction; + } + } + return ""; + break; + } + case cSkinObject::block: + { + std::string rv = ""; + for (uint32_t i = 0; i < NumObjects(); i++) { + if ( (rv = GetObject(i)->CheckAction(ev)) != "" ) { + return rv; + } + } + return ""; + break; + } + default: + return ""; + } + return ""; +} + + + +uint32_t cSkinColor::GetColor(void) { + if (mVarId != "") { + cSkinVariable * variable = mObject->Skin()->GetVariable(mVarId); + if (variable) { + return cColor::ParseColor(variable->Value().String()); + } + return cColor::ERRCOL; + } + return (uint32_t) mColor; +} + + cSkinObjects::cSkinObjects(void) { } diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/object.h graphlcd-base-0.1.9+git20120310/glcdskin/object.h --- graphlcd-base-0.2.0+git20101020/glcdskin/object.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/object.h 2012-03-10 09:18:56.000000000 +0000 @@ -24,6 +24,8 @@ #include "type.h" #include "string.h" +#include + namespace GLCD { @@ -58,6 +60,54 @@ tvaBottom }; +enum eEffect +{ + tfxNone, + tfxShadow, + tfxOutline +}; + +enum eScale +{ + tscNone, + tscAuto, + tscAutoX, + tscAutoY, + tscFill +}; + +enum eGradient +{ + tgrdNone, + tgrdTotal, + tgrdCurrent, + tgrdVertical +}; + + + +class cSkinColor +{ +private: + cSkinObject * mObject; + uint32_t mColor; + std::string mVarId; +public: + cSkinColor(cSkinObject *Parent, uint32_t color):mVarId("") { mObject = Parent; mColor = color; } + cSkinColor(cSkinObject *Parent, cColor color):mVarId("") { mObject = Parent; mColor = (uint32_t)color; } + cSkinColor(cSkinObject *Parent, const std::string varId) { mObject = Parent; mVarId = varId; } + ~cSkinColor() {}; + + void SetColor(uint32_t color) { mVarId = ""; mColor = color; } + void SetColor(cColor color) { mVarId = ""; mColor = (uint32_t)color; } + void SetVarId(const std::string varId) { mVarId = varId; } + + uint32_t GetColor(void); + + operator uint32_t(void) { return GetColor(); } +}; + + class cSkinObject { friend bool StartElem(const std::string & name, std::map & attrs); @@ -77,6 +127,7 @@ text, scrolltext, scrollbar, + button, block, list, item, @@ -87,9 +138,16 @@ cSkinDisplay * mDisplay; // parent display cSkin * mSkin; eType mType; // type of object, one of enum eType - tPoint mPos1; - tPoint mPos2; - eColor mColor; + //tPoint mPos1; + //tPoint mPos2; + cSkinString mX1; // either mX1 and mWidth or mX1 and mX2 are defined. not all three + cSkinString mY1; + cSkinString mX2; + cSkinString mY2; + cSkinString mWidth; + cSkinString mHeight; + cSkinColor mColor; + cSkinColor mBackgroundColor; bool mFilled; int mRadius; int mArc; @@ -98,11 +156,16 @@ eTextVerticalAlignment mVerticalAlign; bool mMultiline; cSkinString mPath; - cSkinString mCurrent; - cSkinString mTotal; + cSkinString mCurrent; // progress bar: current value + cSkinString mTotal; // progress bar: maximum valid value + cSkinString mPeak; // progress bar: peak value (<= 0: disabled) cSkinString mFont; cSkinString mText; cSkinFunction * mCondition; + eEffect mEffect; // effect: none, shadow, or outline + cSkinColor mEffectColor; // effect colour (= shadow colour or colour of outline) + cSkinColor mPeakGradientColor; // colour of peak marker or gradient color (mutual exclusive) + eGradient mGradient; // use gradient effect for progress bar (overrules peak!) uint64_t mLastChange; // timestamp: last change in dynamic object (scroll, frame change, ...) int mChangeDelay; // delay between two changes (frame change, scrolling, ...) @@ -111,6 +174,8 @@ std::string mStoredImagePath; // stored image path int mImageFrameId; // frame ID of image + int mOpacity; // opacity of an image ([0, 255], default 255) + eScale mScale; // image scaling (['none', 'autox', 'autoy', 'fill'], default: none) int mScrollLoopMode; // scroll (text) or loop (image) mode: -1: default, 0: never, 1: once, 2: always bool mScrollLoopReached; // if scroll/loop == once: already looped once? @@ -121,6 +186,10 @@ std::string mAltText; // alternative text source for text-objects cSkinFunction * mAltCondition; // condition when alternative sources are used + std::string mAction; // action attached to this object + + int mMultilineScrollPosition; // current scolling position of mMultiline + cSkinString mMultilineRelScroll;// relative scrolling amount of mMultiline (default: 0) cSkinObjects * mObjects; // used for block objects such as @@ -130,14 +199,17 @@ ~cSkinObject(); bool ParseType(const std::string &Text); - bool ParseColor(const std::string &Text); + bool ParseColor(const std::string &Text, cSkinColor & ParamColor); bool ParseCondition(const std::string &Text); bool ParseAlignment(const std::string &Text); bool ParseVerticalAlignment(const std::string &Text); + bool ParseEffect(const std::string &Text); + bool ParseScale(const std::string &Text); + bool ParseGradient(const std::string &Text); bool ParseFontFace(const std::string &Text); bool ParseIntParam(const std::string &Text, int & Param); - bool ParseWidth(const std::string &Text); - bool ParseHeight(const std::string &Text); + //bool ParseWidth(const std::string &Text); + //bool ParseHeight(const std::string &Text); bool ParseScrollLoopMode(const std::string & Text); // parse scroll mode ([never|once|always]) bool ParseScrollSpeed(const std::string & Text); // parse scroll speed @@ -164,6 +236,8 @@ // check if update is required for dynamic objects (image, text, progress, pane) // false: no update required, true: update required bool NeedsUpdate(uint64_t CurrentTime); + + std::string CheckAction(cGLCDEvent * ev); }; class cSkinObjects: public std::vector diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/parser.c graphlcd-base-0.1.9+git20120310/glcdskin/parser.c --- graphlcd-base-0.2.0+git20101020/glcdskin/parser.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/parser.c 2012-03-10 09:18:56.000000000 +0000 @@ -16,28 +16,33 @@ #include #include +#include + #include "parser.h" #include "xml.h" #include "skin.h" +/* workaround for thread-safe parsing */ +#include + namespace GLCD { #define TAG_ERR_REMAIN(_context) do { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Unexpected tag %s within %s", \ - name.c_str(), _context); \ + errorDetail = "Unexpected tag "+name+" within "+ _context; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } while (0) #define TAG_ERR_CHILD(_context) do { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: No child tag %s expected within %s", \ - name.c_str(), _context); \ + errorDetail = "No child tag "+name+" expected within "+ _context; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } while (0) #define TAG_ERR_END(_context) do { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Unexpected closing tag for %s within %s", \ - name.c_str(), _context); \ + errorDetail = "Unexpected closing tag for "+name+" within "+ _context; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } while (0) @@ -49,8 +54,8 @@ #define ATTRIB_MAN_STRING(_attr,_target) \ ATTRIB_OPT_STRING(_attr,_target) \ else { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+ name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } @@ -59,8 +64,8 @@ char *_e; const char *_t = attrs[_attr].c_str(); \ long _l = strtol(_t, &_e, 10); \ if (_e ==_t || *_e != '\0') { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Invalid numeric value \"%s\" in attribute %s", \ - _t, _attr); \ + errorDetail = "Invalid numeric value \""+ (std::string)_t +"\" in attribute "+ (std::string)_attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } else \ _target = _l; \ @@ -69,8 +74,8 @@ #define ATTRIB_MAN_NUMBER(_attr,_target) \ ATTRIB_OPT_NUMBER(_attr,_target) \ else { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } @@ -81,8 +86,8 @@ else if (attrs[_attr] == "no") \ _target = false; \ else { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Invalid boolean value \"%s\" in attribute %s", \ - attrs[_attr].c_str(), _attr); \ + errorDetail = "Invalid boolean value \""+ attrs[_attr] +"\" in attribute "+ _attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } \ } @@ -90,16 +95,16 @@ #define ATTRIB_MAN_BOOL(_attr,_target) \ ATTRIB_OPT_BOOL(_attr,_target) \ else { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } #define ATTRIB_OPT_FUNC(_attr,_func) \ if (attrs.find(_attr) != attrs.end()) { \ if (!_func(attrs[_attr])) { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Unexpected value %s for attribute %s", \ - attrs[_attr].c_str(), _attr); \ + errorDetail = "Unexpected value \""+ attrs[_attr] +"\" for attribute "+ (std::string)_attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } \ } @@ -107,16 +112,16 @@ #define ATTRIB_MAN_FUNC(_attr,_func) \ ATTRIB_OPT_FUNC(_attr,_func) \ else { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } #define ATTRIB_OPT_FUNC_PARAM(_attr,_func,_param) \ if (attrs.find(_attr) != attrs.end()) { \ if (!_func(attrs[_attr],_param)) { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Unexpected value %s for attribute %s", \ - attrs[_attr].c_str(), _attr); \ + errorDetail = "Unexpected value "+ attrs[_attr] +" for attribute "+ (std::string)_attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } \ } @@ -124,8 +129,8 @@ #define ATTRIB_MAN_FUNC_PARAM(_attr,_func,_param) \ ATTRIB_OPT_FUNC_PARAM(_attr,_func,_param) \ else { \ - syslog(LOG_ERR, "ERROR: graphlcd/skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } @@ -133,31 +138,140 @@ static cSkin * skin = NULL; static cSkinFont * font = NULL; static cSkinVariable * variable = NULL; +static cSkinVariable * variable_default = NULL; static cSkinDisplay * display = NULL; static std::vector parents; static cSkinObject * object = NULL; static uint32_t oindex = 0; +static std::string errorDetail = ""; +static std::string condblock_cond = ""; + +// support for including files (templates, ...) in the skin definition +// max. depth supported for file inclusion (-> detect recursive inclusions) +#define MAX_INCLUDEDEPTH 5 +static int includeDepth = 0; +static std::string subErrorDetail = ""; + +bool StartElem(const std::string & name, std::map & attrs); +bool CharData(const std::string & text); +bool EndElem(const std::string & name); + + + +static bool CheckSkinVersion(const std::string & version) { + float currv; + char* ecptr = NULL; + const char* verscstr = version.c_str(); + // only accept floating point numbers with '.' as separator, no ',' + char* curr_locale = setlocale(LC_NUMERIC, "C"); + + currv = strtof(verscstr, &ecptr); + setlocale(LC_NUMERIC, curr_locale); + + if ( (*ecptr != '\0') || (ecptr == NULL) /*|| (ecptr != verscstr)*/ || + ((int)(GLCDSKIN_SKIN_VERSION * 100.0) < (int)(currv * 100.0)) + ) + { + return false; + } + return true; +} + + bool StartElem(const std::string & name, std::map & attrs) { //printf("start element: %s\n", name.c_str()); - +// if (context.size() > 0) fprintf(stderr, "context: %s\n", context[context.size() - 1].c_str()); if (context.size() == 0) { if (name == "skin") { ATTRIB_MAN_STRING("version", skin->version); ATTRIB_MAN_STRING("name", skin->title); + ATTRIB_OPT_FUNC("enable", skin->ParseEnable); + + if (! CheckSkinVersion(skin->version) ) { + errorDetail = "skin version '"+ skin->version +"' not supported."; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } } else TAG_ERR_REMAIN("document"); } + else if (name == "include") + { + if (includeDepth + 1 < MAX_INCLUDEDEPTH) { + cSkinObject* tmpobj = new cSkinObject(new cSkinDisplay(skin)); + cSkinString* path = new cSkinString(tmpobj, false); + ATTRIB_MAN_FUNC("path", path->Parse); + std::string strpath = path->Evaluate(); + // is path relative? -> prepend skinpath + if (strpath[0] != '/') { + strpath = skin->Config().SkinPath() + "/" + strpath; + } + path = NULL; + tmpobj = NULL; + + includeDepth++; + cXML incxml(strpath, skin->Config().CharSet()); + incxml.SetNodeStartCB(StartElem); + incxml.SetNodeEndCB(EndElem); + incxml.SetCDataCB(CharData); + if (incxml.Parse() != 0) { + errorDetail = "error when parsing included xml file '"+strpath+"'"+ ( (subErrorDetail == "") ? "" : " ("+subErrorDetail+")"); + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } + includeDepth--; + } else { + subErrorDetail = "max. include depth reached"; + return false; + } + } + else if (name == "condblock") + { + int i = context.size() - 1; + while (i >= 0) { + if (context[i] == "condblock") { + errorDetail = "'condblock' must not be nested in another 'condblock'."; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } + i--; + } + ATTRIB_MAN_STRING("condition", condblock_cond); + } else if (name == "variable") { variable = new cSkinVariable(skin); ATTRIB_MAN_STRING("id", variable->mId); + ATTRIB_OPT_FUNC("evaluate", variable->ParseEvalMode); ATTRIB_MAN_FUNC("value", variable->ParseValue); - ATTRIB_OPT_FUNC("condition", variable->ParseCondition); + if (context[context.size() - 1] == "condblock") { + if (attrs.find("condition") != attrs.end()) { + errorDetail = "variable \""+variable->mId+"\" must not contain a condition when context = 'condblock'."; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } else { + if (! variable->ParseCondition(condblock_cond)) { + errorDetail = "Unexpected value \""+ attrs["condition"] +"\" for attribute "+ (std::string)"condition"; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } + } + } else { + ATTRIB_OPT_FUNC("condition", variable->ParseCondition); + } + // if a 'default' value is set, create a second variable w/o condition: will be used if condition is not true + // as variables all have global scope (no matter where defined) and will always be sought from the start of the array, + // the default variable will be inserted _after_ the variable containing the condition. + if (attrs.find("default") != attrs.end()) { + variable_default = new cSkinVariable(skin); + ATTRIB_MAN_STRING("id", variable_default->mId); + ATTRIB_MAN_FUNC("default", variable_default->ParseValue); + } } else if (context[context.size() - 1] == "skin") { @@ -187,83 +301,98 @@ } object = new cSkinObject(display); + + /* default settings */ + object->ParseColor("transparent", object->mBackgroundColor); + if (object->ParseType(name)) { - ATTRIB_OPT_FUNC_PARAM("x1", object->ParseIntParam, object->mPos1.x); - ATTRIB_OPT_FUNC_PARAM("y1", object->ParseIntParam, object->mPos1.y); - ATTRIB_OPT_FUNC_PARAM("x2", object->ParseIntParam, object->mPos2.x); - ATTRIB_OPT_FUNC_PARAM("y2", object->ParseIntParam, object->mPos2.y); - ATTRIB_OPT_FUNC("width", object->ParseWidth); - ATTRIB_OPT_FUNC("height", object->ParseHeight); + object->mX1.Parse("0"); + object->mY1.Parse("0"); + object->mX2.Parse("-1"); + object->mY2.Parse("-1"); + object->mWidth.Parse("0"); + object->mHeight.Parse("0"); + ATTRIB_OPT_FUNC("x", object->mX1.Parse); + ATTRIB_OPT_FUNC("y", object->mY1.Parse); + ATTRIB_OPT_FUNC("x1", object->mX1.Parse); + ATTRIB_OPT_FUNC("y1", object->mY1.Parse); + ATTRIB_OPT_FUNC("x2", object->mX2.Parse); + ATTRIB_OPT_FUNC("y2", object->mY2.Parse); + ATTRIB_OPT_FUNC("width", object->mWidth.Parse); + ATTRIB_OPT_FUNC("height", object->mHeight.Parse); ATTRIB_OPT_FUNC("condition", object->ParseCondition); + ATTRIB_OPT_STRING("action", object->mAction); if (name == "image") { - ATTRIB_OPT_FUNC_PARAM("x", object->ParseIntParam, object->mPos1.x); - ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos1.y); - ATTRIB_OPT_FUNC_PARAM("x", object->ParseIntParam, object->mPos2.x); - ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos2.y); - ATTRIB_OPT_FUNC("color", object->ParseColor); + //ATTRIB_OPT_FUNC_PARAM("x", object->ParseIntParam, object->mPos2.x); + //ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos2.y); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); + ATTRIB_OPT_FUNC_PARAM("bgcolor", object->ParseColor, object->mBackgroundColor); ATTRIB_MAN_FUNC("path", object->mPath.Parse); ATTRIB_OPT_FUNC("loop", object->ParseScrollLoopMode); + ATTRIB_OPT_FUNC_PARAM("opacity", object->ParseIntParam, object->mOpacity); + ATTRIB_OPT_FUNC("scale", object->ParseScale); } else if (name == "text" || name == "scrolltext") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); + ATTRIB_OPT_FUNC_PARAM("bgcolor", object->ParseColor, object->mBackgroundColor); ATTRIB_OPT_FUNC("align", object->ParseAlignment); ATTRIB_OPT_FUNC("valign", object->ParseVerticalAlignment); - ATTRIB_OPT_FUNC("font", object->ParseFontFace); + ATTRIB_MAN_FUNC("font", object->ParseFontFace); ATTRIB_OPT_BOOL("multiline", object->mMultiline); + ATTRIB_OPT_FUNC("mlrelscroll", object->mMultilineRelScroll.Parse); ATTRIB_OPT_FUNC("scrollmode", object->ParseScrollLoopMode); ATTRIB_OPT_FUNC("scrollspeed", object->ParseScrollSpeed); ATTRIB_OPT_FUNC("scrolltime", object->ParseScrollTime); ATTRIB_OPT_STRING("alttext", object->mAltText); ATTRIB_OPT_FUNC("altcondition", object->ParseAltCondition); -#if 0 - if (name == "blink") - { - ATTRIB_OPT_NUMBER("delay", object->mDelay); - - if (object->mDelay == 0) - object->mDelay = 1000; - } - else if (name == "marquee") - { - ATTRIB_OPT_NUMBER("delay", object->mDelay); - - if (object->mDelay == 0) - object->mDelay = 500; - } -#endif + ATTRIB_OPT_FUNC_PARAM("effectcolor", object->ParseColor, object->mEffectColor); + ATTRIB_OPT_FUNC("effect", object->ParseEffect); + ATTRIB_OPT_NUMBER("radius", object->mRadius); + } + else if (name == "button") + { + ATTRIB_OPT_FUNC_PARAM("labelcolor", object->ParseColor, object->mColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mBackgroundColor); + ATTRIB_MAN_FUNC("font", object->ParseFontFace); + ATTRIB_OPT_NUMBER("radius", object->mRadius); } else if (name == "pixel") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); } else if (name == "line") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); } else if (name == "rectangle") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); ATTRIB_OPT_BOOL("filled", object->mFilled); ATTRIB_OPT_NUMBER("radius", object->mRadius); } else if (name == "ellipse" || name == "slope") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); ATTRIB_OPT_BOOL("filled", object->mFilled); ATTRIB_OPT_NUMBER("arc", object->mArc); } else if (name == "progress" || name == "scrollbar") { - ATTRIB_OPT_FUNC("color", object->ParseColor); - ATTRIB_OPT_NUMBER("direction", object->mDirection); - ATTRIB_OPT_FUNC("current", object->mCurrent.Parse); - ATTRIB_OPT_FUNC("total", object->mTotal.Parse); + ATTRIB_OPT_FUNC_PARAM( "color", object->ParseColor, object->mColor); + ATTRIB_OPT_NUMBER( "direction", object->mDirection); + ATTRIB_OPT_FUNC( "current", object->mCurrent.Parse); + ATTRIB_OPT_FUNC( "total", object->mTotal.Parse); + ATTRIB_OPT_FUNC( "peak", object->mPeak.Parse); + ATTRIB_OPT_FUNC_PARAM( "peakcolor", object->ParseColor, object->mPeakGradientColor); + ATTRIB_OPT_FUNC( "gradient", object->ParseGradient); + ATTRIB_OPT_FUNC_PARAM( "gradientcolor", object->ParseColor, object->mPeakGradientColor); + ATTRIB_OPT_NUMBER( "radius", object->mRadius); } #if 0 else if (name == "item") { @@ -271,6 +400,12 @@ --object->mPos2.y; } #endif + // range checks + if (object->mOpacity < 0) + object->mOpacity = 0; + else if (object->mOpacity > 255) + object->mOpacity = 255; + } else TAG_ERR_REMAIN(context[context.size() - 1].c_str()); @@ -291,13 +426,14 @@ //printf("context: %s\n", context[context.size() - 1].c_str()); if (context[context.size() - 1] == "text" - || context[context.size() - 1] == "scrolltext") + || context[context.size() - 1] == "scrolltext" + || context[context.size() - 1] == "button") { if (!object->mText.Parse(text)) return false; } else - syslog(LOG_ERR, "ERROR: Bad character data"); + syslog(LOG_ERR, "ERROR: graphlcd/skin: Bad character data"); return true; } @@ -314,7 +450,13 @@ else if (name == "variable") { skin->mVariables.push_back(variable); +//fprintf(stderr, " variable '%s', value: %s\n", variable->mId.c_str(), ((std::string)variable->Value()).c_str()); variable = NULL; + if (variable_default != NULL) { + skin->mVariables.push_back(variable_default); +//fprintf(stderr, " variable default '%s', value: %s\n", variable_default->mId.c_str(), ((std::string)variable_default->Value()).c_str()); + variable_default = NULL; + } } else if (name == "display") { @@ -367,29 +509,57 @@ return true; } -cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::string & fileName) +static pthread_mutex_t parse_mutex; // temp. workaround of thread-safe parsing problem + +cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::string & fileName, std::string & errorString) { + pthread_mutex_lock(&parse_mutex); // temp. workaround + //fprintf(stderr, ">>>>> XmlParse, Config: %s, Name: %s\n", Config.GetDriver()->ConfigName().c_str(), Name.c_str()); skin = new cSkin(Config, Name); context.clear(); - cXML xml(fileName); + { // temp. workaround for thread-safe parsing + font = NULL; + variable = NULL; + variable_default = NULL; + display = NULL; + parents.clear(); + object = NULL; + oindex = 0; + errorDetail = ""; + condblock_cond = ""; + includeDepth = 0; + subErrorDetail = ""; + } + cXML xml(fileName, skin->Config().CharSet()); xml.SetNodeStartCB(StartElem); xml.SetNodeEndCB(EndElem); xml.SetCDataCB(CharData); if (xml.Parse() != 0) { + char buff[8]; + snprintf(buff, 7, "%d", xml.LineNr()); syslog(LOG_ERR, "ERROR: graphlcd/skin: Parse error in %s, line %d", fileName.c_str(), xml.LineNr()); + // shorter version outgoing errorString (eg. displaying errorString on the display) + errorString = "Parse error in skin "+Name+", line "+buff; + if (errorDetail != "") + errorString += ":\n"+errorDetail; delete skin; skin = NULL; delete display; display = NULL; delete object; object = NULL; + //fprintf(stderr, "<<<<< XmlParse ERROR, Config: %s, Name: %s\n", Config.GetDriver()->ConfigName().c_str(), Name.c_str()); + pthread_mutex_unlock(&parse_mutex); return NULL; } cSkin * result = skin; skin = NULL; + errorString = ""; + //fprintf(stderr, "<<<<< XmlParse, Config: %s, Name: %s\n", Config.GetDriver()->ConfigName().c_str(), Name.c_str()); + pthread_mutex_unlock(&parse_mutex); return result; } diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/parser.h graphlcd-base-0.1.9+git20120310/glcdskin/parser.h --- graphlcd-base-0.2.0+git20101020/glcdskin/parser.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/parser.h 2012-03-10 09:18:56.000000000 +0000 @@ -16,13 +16,23 @@ #include +// max. version of skin definitions supported by the parser +#define GLCDSKIN_SKIN_VERSION 1.2 + + namespace GLCD { class cSkin; class cSkinConfig; -cSkin * XmlParse(cSkinConfig & Config, const std::string & name, const std::string & fileName); +cSkin * XmlParse(cSkinConfig & Config, const std::string & name, const std::string & fileName, std::string & errorString); + +// provide old function for compatibility +cSkin * XmlParse(cSkinConfig & Config, const std::string & name, const std::string & fileName) +{ std::string errorString = ""; + return XmlParse(Config, name, fileName, errorString); +} } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/skin.c graphlcd-base-0.1.9+git20120310/glcdskin/skin.c --- graphlcd-base-0.2.0+git20101020/glcdskin/skin.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/skin.c 2012-03-10 09:18:56.000000000 +0000 @@ -21,6 +21,8 @@ name(Name) { mImageCache = new cImageCache(this, 100); + tsEvalTick = 0; + tsEvalSwitch = 0; } cSkin::~cSkin(void) @@ -79,4 +81,16 @@ } +bool cSkin::ParseEnable(const std::string & Text) +{ + cDriver * driver = config.GetDriver(); + + if (!driver) + return false; + + driver->SetFeature(Text, 1); + return true; // always return true else loading the skin would fail if touchscreen is not available +} + + } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/skin.h graphlcd-base-0.1.9+git20120310/glcdskin/skin.h --- graphlcd-base-0.2.0+git20101020/glcdskin/skin.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/skin.h 2012-03-10 09:18:56.000000000 +0000 @@ -43,6 +43,8 @@ cSkinDisplays displays; cSkinVariables mVariables; cImageCache * mImageCache; + uint64_t tsEvalTick; + uint64_t tsEvalSwitch; public: cSkin(cSkinConfig & Config, const std::string & Name); @@ -61,6 +63,16 @@ const tSize & BaseSize(void) const { return baseSize; } cImageCache * ImageCache(void) { return mImageCache; } + + bool ParseEnable(const std::string &Text); + + cColor GetBackgroundColor(void) { return config.GetDriver()->GetBackgroundColor(); } + cColor GetForegroundColor(void) { return config.GetDriver()->GetForegroundColor(); } + + void SetTSEvalTick(uint64_t ts) { tsEvalTick = ts; } + void SetTSEvalSwitch(uint64_t ts) { tsEvalSwitch = ts; } + const uint64_t GetTSEvalTick(void) { return tsEvalTick; } + const uint64_t GetTSEvalSwitch(void) { return tsEvalSwitch; } }; } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/string.c graphlcd-base-0.1.9+git20120310/glcdskin/string.c --- graphlcd-base-0.2.0+git20101020/glcdskin/string.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/string.c 2012-03-10 09:18:56.000000000 +0000 @@ -55,18 +55,23 @@ return result; } +#if 0 cSkinString::tStringList cSkinString::mStrings; +#endif cSkinString::cSkinString(cSkinObject *Parent, bool Translate) : mObject(Parent), mSkin(Parent->Skin()), mTranslate(Translate) { +#if 0 mStrings.push_back(this); +#endif } cSkinString::~cSkinString() { +#if 0 tStringList::iterator it = mStrings.begin(); for (; it != mStrings.end(); ++it) { if ((*it) == this) { @@ -74,8 +79,10 @@ break; } } +#endif } +#if 0 void cSkinString::Reparse(void) { tStringList::iterator it = mStrings.begin(); @@ -84,6 +91,14 @@ (*it)->Parse((*it)->mOriginal, true); } } +#endif + + +// copied from xml.c (should be valid for parsing variable names too ...) +static bool IsTokenChar(bool start, int c) { + return isalpha(c) || c == '_' || (!start && isdigit(c)); +} + bool cSkinString::Parse(const std::string & Text, bool Translate) { @@ -93,16 +108,6 @@ bool inAttrib = false; int offset = 0; - if (trans[0] == '#') - { - cSkinVariable * variable = mSkin->GetVariable(trans.substr(1)); - if (variable) - { - trans = (std::string) variable->Value(); - syslog(LOG_ERR, "string variable %s", trans.c_str()); - } - } - //Dprintf("parsing: %s\n", Text.c_str()); mOriginal = Text; mText = ""; @@ -113,16 +118,39 @@ for (; *ptr; ++ptr) { if (inToken && *ptr == '\\') { if (*(ptr + 1) == '\0') { - syslog(LOG_ERR, "ERROR: Stray \\ in token attribute\n"); + syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Stray \\ in token attribute\n"); return false; } ++ptr; continue; } + else if (*ptr == '#') { + if (inToken) { + syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected '#' in token"); + return false; + } + + mText.append(last, ptr - last); + + bool isStartChar = true; + const char * varNameStart = ptr; + ptr++; + while (*ptr && IsTokenChar(isStartChar, *ptr)) { + isStartChar = false; + ptr++; + offset++; + } + // add #VARNAME# + mText.append(varNameStart, (ptr - varNameStart)); + mText.append("#"); + offset +=2; // adds two '#' -> fix offset + ptr--; // we'd be at the correct position now but the for-loop does a ++ptr -> fix it by stepping back one char + last = ptr + 1; + } else if (*ptr == '{') { if (inToken) { - syslog(LOG_ERR, "ERROR: Unexpected '{' in token"); + syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected '{' in token"); return false; } @@ -132,13 +160,13 @@ } else if (*ptr == '}' || (inToken && *ptr == ':')) { if (!inToken) { - syslog(LOG_ERR, "ERROR: Unexpected '}' outside of token"); + syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected '}' outside of token"); return false; } if (inAttrib) { if (*ptr == ':') { - syslog(LOG_ERR, "ERROR: Unexpected ':' inside of token attribute"); + syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected ':' inside of token attribute"); return false; } @@ -179,12 +207,14 @@ { std::string tmp; tmp.assign(last, ptr - last); - tSkinToken token(mSkin->Config().GetTokenId(tmp), tmp, offset, ""); - mTokens.push_back(token); + if (tmp != "") { // ignore empty token + tSkinToken token(mSkin->Config().GetTokenId(tmp), tmp, offset, ""); + mTokens.push_back(token); + } } else { - syslog(LOG_ERR, "ERROR: Unexpected token {%.*s}", (int)(ptr - last), last); + syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected token {%.*s}", (int)(ptr - last), last); return false; } @@ -201,7 +231,7 @@ } if (inToken) { - syslog(LOG_ERR, "ERROR: Expecting '}' in token"); + syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Expecting '}' in token"); return false; } @@ -214,19 +244,56 @@ cType cSkinString::Evaluate(void) const { - std::string result; - int offset = 0; - if (mText.length() == 0 && mTokens.size() == 1) return mSkin->Config().GetToken(mTokens[0]); - for (uint32_t i = 0; i < mTokens.size(); ++i) { - result.append(mText.c_str() + offset, mTokens[i].Offset - offset); - result.append(mSkin->Config().GetToken(mTokens[i])); + std::string result_raw = ""; + int offset = 0; + for (uint32_t i = 0; i < mTokens.size(); i++) { + result_raw.append(mText.substr(offset, mTokens[i].Offset - offset) ); + result_raw.append(mSkin->Config().GetToken(mTokens[i])); offset = mTokens[i].Offset; } - result.append(mText.c_str() + offset); - return result; + result_raw.append(mText.c_str() + offset); + + // replace variable placeholders (#VARNAME#) with corresponding values + std::string result_trans = ""; + size_t idxstart = 0, idxend = 0; + size_t pos = 0; + while ( (idxstart=result_raw.find("#", idxstart)) != std::string::npos ) { + result_trans.append(result_raw.substr(pos, idxstart-pos)); + idxend = result_raw.find("#", idxstart+1); + cSkinVariable * variable = mSkin->GetVariable(result_raw.substr(idxstart+1, idxend-idxstart-1)); + if (variable) { + std::string val = (std::string) variable->Value(); + + // if value of variable contains token definions: reparse value + if (val.find("{") != std::string::npos) { + cSkinString *result = new cSkinString(Object(), false); + if (result->Parse(val)) { + val = (std::string) result->Evaluate(); + } + delete result; + } + result_trans.append (val); + // syslog(LOG_ERR, "string variable %s", trans.c_str()); + } + idxstart = idxend+1; + pos = idxstart; + } + result_trans.append(result_raw.substr(pos)); + + // re-evaluate resulting string + if ((mText.size() > 0) && mText[0] != '#' && mObject != NULL ) { + cSkinFunction *result = new cSkinFunction(mObject); + if (result->Parse(result_trans, true)) { + std::string result_rescan = (std::string)result->Evaluate(); + if (result_rescan != "") + result_trans = result_rescan; + } + delete result; + } + return result_trans; } } // end of namespace diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/string.h graphlcd-base-0.1.9+git20120310/glcdskin/string.h --- graphlcd-base-0.2.0+git20101020/glcdskin/string.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/string.h 2012-03-10 09:18:56.000000000 +0000 @@ -86,8 +86,10 @@ class cSkinString { private: +#if 0 typedef std::vector tStringList; static tStringList mStrings; +#endif cSkinObject * mObject; cSkin * mSkin; @@ -97,7 +99,9 @@ bool mTranslate; public: +#if 0 static void Reparse(void); +#endif cSkinString(cSkinObject *Parent, bool Translate); ~cSkinString(); diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/type.h graphlcd-base-0.1.9+git20120310/glcdskin/type.h --- graphlcd-base-0.2.0+git20101020/glcdskin/type.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/type.h 2012-03-10 09:18:56.000000000 +0000 @@ -54,6 +54,10 @@ void SetUpdate(uint32_t UpdateIn) { mUpdateIn = UpdateIn; } uint32_t UpdateIn(void) const { return mUpdateIn; } + bool IsString(void) const { return (mType == string); } + bool IsNumber(void) const { return (mType == number); } + bool IsBoolean(void) const { return (mType == boolean); } + operator std::string () const { return String(); } operator int () const { return Number(); } operator bool () const; diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/variable.c graphlcd-base-0.1.9+git20120310/glcdskin/variable.c --- graphlcd-base-0.2.0+git20101020/glcdskin/variable.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/variable.c 2012-03-10 09:18:56.000000000 +0000 @@ -11,23 +11,63 @@ : mSkin(Parent), mValue(0), mCondition(NULL), + mFunction(NULL), mDummyDisplay(mSkin), - mDummyObject(&mDummyDisplay) + mDummyObject(&mDummyDisplay), + mEvalMode(tevmTick), + mEvalInterval(0), + mTimestamp(0) { } +bool cSkinVariable::ParseEvalMode(const std::string & Text) +{ + + if (Text == "always") { + mEvalMode = tevmAlways; + } else if (Text == "tick") { + mEvalMode = tevmTick; + } else if (Text == "switch") { + mEvalMode = tevmSwitch; + } else if (Text == "once") { + mEvalMode = tevmOnce; + } else if (Text.length() > 9 && Text.substr(0,9) == "interval:") { + char * e; + const char * t = Text.substr(9).c_str(); + long l = strtol(t, &e, 10); + if ( ! (e == t || *e != '\0') && (l >= 100)) + { + mEvalInterval = (int) l; + mEvalMode = tevmInterval; + return true; + } + return false; + } else { + return false; + } + return true; +} + + bool cSkinVariable::ParseValue(const std::string & Text) { - if (isalpha(Text[0]) || Text[0] == '#') + if (isalpha(Text[0]) || Text[0] == '#' || Text[0] == '{') { - cSkinFunction * func = new cSkinFunction(&mDummyObject); - if (func->Parse(Text)) + //delete mFunction; + mFunction = new cSkinFunction(&mDummyObject); + if (mFunction->Parse(Text)) { - mValue = func->Evaluate(); - delete func; + if (mEvalMode == tevmOnce) { + mValue = mFunction->Evaluate(); + delete mFunction; + mFunction = NULL; + } + //mValue = func->Evaluate(); + //delete func; return true; } - delete func; + delete mFunction; + mFunction = NULL; } else if (Text[0] == '\'') { @@ -57,6 +97,34 @@ return false; } + +const cType & cSkinVariable::Value(void) +{ + if ( mTimestamp > 0 && + ( ( mEvalMode == tevmTick && mTimestamp >= mSkin->GetTSEvalTick() ) || + ( mEvalMode == tevmSwitch && mTimestamp >= mSkin->GetTSEvalSwitch() ) || + ( mEvalMode == tevmInterval && (mTimestamp + (uint64_t)mEvalInterval) > mSkin->Config().Now()) + ) + ) + { + return mValue; + } + + if (mFunction != NULL) { + mValue = mFunction->Evaluate(); + // should've been solved in ParseValue already, just to be sure ... + if (mEvalMode == tevmOnce) { + delete mFunction; + mFunction = NULL; + } + } + if (mEvalMode == tevmTick || mEvalMode == tevmSwitch || mEvalMode == tevmInterval) { + mTimestamp = mSkin->Config().Now(); + } + return mValue; +} + + cSkinVariables::cSkinVariables(void) { } diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/variable.h graphlcd-base-0.1.9+git20120310/glcdskin/variable.h --- graphlcd-base-0.2.0+git20101020/glcdskin/variable.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/variable.h 2012-03-10 09:18:56.000000000 +0000 @@ -18,10 +18,21 @@ #include "display.h" #include "object.h" +#include "function.h" namespace GLCD { +enum eEvalMode +{ + tevmAlways, + tevmTick, + tevmSwitch, + tevmOnce, + tevmInterval +}; + + class cSkin; class cSkinVariable @@ -34,18 +45,24 @@ std::string mId; cType mValue; cSkinFunction * mCondition; + cSkinFunction * mFunction; cSkinDisplay mDummyDisplay; cSkinObject mDummyObject; + eEvalMode mEvalMode; + int mEvalInterval; + uint64_t mTimestamp; public: cSkinVariable(cSkin * Parent); + bool ParseEvalMode(const std::string & Text); bool ParseValue(const std::string & Text); bool ParseCondition(const std::string & Text); cSkin * Skin(void) const { return mSkin; } const std::string & Id(void) const { return mId; } - const cType & Value(void) const { return mValue; } +// const cType & Value(void) const { return mValue; } + const cType & Value(void); cSkinFunction * Condition(void) const { return mCondition; } }; diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/xml.c graphlcd-base-0.1.9+git20120310/glcdskin/xml.c --- graphlcd-base-0.2.0+git20101020/glcdskin/xml.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/xml.c 2012-03-10 09:18:56.000000000 +0000 @@ -15,32 +15,15 @@ #include #include +#include +#include + #include "xml.h" +#include "../glcdgraphics/common.h" namespace GLCD { -std::string trim(const std::string & s) -{ - std::string::size_type start, end; - - start = 0; - while (start < s.length()) - { - if (!isspace(s[start])) - break; - start++; - } - end = s.length() - 1; - while (end >= 0) - { - if (!isspace(s[end])) - break; - end--; - } - return s.substr(start, end - start + 1); -} - enum { LOOK4START, // looking for first element start LOOK4TAG, // looking for element tag @@ -57,7 +40,7 @@ INCLOSETAG, // reading closing tag }; -cXML::cXML(const std::string & file) +cXML::cXML(const std::string & file, const std::string sysCharset) : nodestartcb(NULL), nodeendcb(NULL), cdatacb(NULL), @@ -66,6 +49,18 @@ { char * buffer; long size; + sysEncoding = sysCharset; + sysIsUTF8 = (sysEncoding == "UTF-8"); + if (!sysIsUTF8) { + // convert from utf-8 to system encoding + iconv_cd = iconv_open(sysEncoding.c_str(), "UTF-8"); + if (iconv_cd == (iconv_t) -1) { + syslog(LOG_ERR, "ERROR: system encoding %s is not supported\n", sysEncoding.c_str()); + iconv_cd = NULL; + } + } else { + iconv_cd = NULL; + } #if (__GNUC__ < 3) std::ifstream f(file.c_str(), std::ios::in | std::ios::binary | std::ios::ate); @@ -75,20 +70,24 @@ if (!f.is_open()) { syslog(LOG_ERR, "ERROR: skin file %s not found\n", file.c_str()); - } - size = f.tellg(); + validFile = false; + } else { + validFile = true; + size = f.tellg(); #if (__GNUC__ < 3) - f.seekg(0, std::ios::beg); + f.seekg(0, std::ios::beg); #else - f.seekg(0, std::ios_base::beg); + f.seekg(0, std::ios_base::beg); #endif - buffer = new char[size]; - f.read(buffer, size); - f.close(); - data.assign(buffer, size); - delete[] buffer; + buffer = new char[size]; + f.read(buffer, size); + f.close(); + data.assign(buffer, size); + delete[] buffer; + } } +#if 0 cXML::cXML(const char * mem, unsigned int len) : nodestartcb(NULL), nodeendcb(NULL), @@ -98,6 +97,13 @@ { data.assign(mem, len); } +#endif + +cXML::~cXML() +{ + if (iconv_cd != NULL) + iconv_close(iconv_cd); +} void cXML::SetNodeStartCB(XML_NODE_START_CB(cb)) { @@ -129,14 +135,29 @@ int percent = 0; int last = 0; std::string::size_type len; + uint32_t c, c_tmp; + unsigned int i_old; + int l, char_size; + + if (!validFile) + return -1; state = LOOK4START; linenr = 1; skipping = false; len = data.length(); - for (std::string::size_type i = 0; i < len; i++) + + unsigned int i = 0; + while (i < (unsigned int)len) { - if (ReadChar(data[i]) != 0) + i_old = i; + encodedCharAdjustCounter(true, data, c_tmp, i); + char_size = (i - i_old) + 1; + c = 0; + for (l = 0 ; l < char_size; l++) + c += ( (0xFF & data[i_old + l]) << ( l << 3) ); + + if (ReadChar(c /*data[i]*/, char_size) != 0) return -1; if (progresscb) { @@ -147,6 +168,7 @@ last = percent; } } + i++; } return 0; } @@ -156,8 +178,15 @@ return isalpha(c) || c == '_' || (!start && isdigit(c)); } -int cXML::ReadChar(int c) +int cXML::ReadChar(unsigned int c, int char_size) { + // buffer for conversions (when conversion from utf8 to system encoding is required) + char convbufin[5]; + char convbufout[5]; + char* convbufinp = convbufin; + char* convbufoutp = convbufout; + size_t bufin_size, bufout_size, bufconverted; + // new line? if (c == '\n') linenr++; @@ -179,6 +208,46 @@ cdata.replace(pos, 4, ">"); else if (cdata.substr(pos, 5) == "&") cdata.replace(pos, 5, "&"); + else if (cdata.substr(pos, 2) == "&#") { + bool ishex = ((cdata.substr(pos+2, 1) == "x") || (cdata.substr(pos+2, 1) == "X") ); + size_t startpos = pos+2+((ishex)?1:0); + size_t endpos = cdata.find(';', startpos ); + if (endpos != std::string::npos) { + char* tempptr; + std::string charid = cdata.substr(startpos, endpos-startpos); + long val = strtol(charid.c_str(), &tempptr, (ishex) ? 16 : 10); + + if (tempptr != charid.c_str() && *tempptr == '\0') { + char encbuf[5]; size_t enclen = 0; + + if ( val <= 0x1F ) { + enclen = 0; // ignore control chars + } else if ( val <= 0x007F ) { + enclen = 1; + encbuf[0] = (char)(val & 0x7F); + } else if ( val <= 0x07FF ) { + enclen = 2; + encbuf[1] = (char)(( val & 0x003F) | 0x80); + encbuf[0] = (char)(( (val & 0x07C0) >> 6) | 0xC0); + } else if ( val <= 0xFFFF ) { + enclen = 3; + encbuf[2] = (char)(( val & 0x003F) | 0x80); + encbuf[1] = (char)(( (val & 0x0FC0) >> 6) | 0x80); + encbuf[0] = (char)(( (val & 0xF000) >> 12) | 0xE0); + } else if ( val <= 0x10FFFF ) { + enclen = 4; + encbuf[3] = (char)(( val & 0x003F) | 0x80); + encbuf[2] = (char)(( (val & 0x0FC0) >> 6) | 0x80); + encbuf[1] = (char)(( (val & 0x03F000 ) >> 12) | 0x80); + encbuf[0] = (char)(( (val & 0x1C0000 ) >> 18) | 0xF0); + } + encbuf[enclen] = '\0'; + if (enclen > 0) { + cdata.replace(pos, endpos-pos+1, encbuf); + } + } + } + } pos++; } if (!cdatacb(trim(cdata))) @@ -190,7 +259,29 @@ state = LOOK4TAG; } else - cdata += c; + { + int i; + //cdata += c; + // convert text-data on the fly if system encoding != UTF-8 + if (iconv_cd != NULL && char_size > 1 /* ((c & 0x80) == 0x80)*/) { + for (i = 0; i < char_size; i++) + convbufin[i] = ( (char)((c >> ( i << 3) ) & 0xFF) ); + convbufin[char_size] = '\0'; + bufin_size = strlen(convbufin); + bufout_size = bufin_size; + bufconverted = iconv(iconv_cd, &convbufinp, &bufin_size, &convbufoutp, &bufout_size); + + if (bufconverted != (size_t)-1 && strlen(convbufout) != 0) { + for (i = 0; i < (int)strlen(convbufout); i++) + cdata += convbufout[i]; + } else { + cdata += "?"; + } + } else { + for (i = 0; i < char_size; i++) + cdata += ( (unsigned char)((c >> ( i << 3) ) & 0xFF) ); + } + } // silently ignore until resync break; diff -Nru graphlcd-base-0.2.0+git20101020/glcdskin/xml.h graphlcd-base-0.1.9+git20120310/glcdskin/xml.h --- graphlcd-base-0.2.0+git20101020/glcdskin/xml.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/glcdskin/xml.h 2012-03-10 09:18:56.000000000 +0000 @@ -15,6 +15,7 @@ #include #include +#include namespace GLCD { @@ -33,10 +34,14 @@ class cXML { private: + bool validFile; bool skipping; int state; int linenr; - int delim; + unsigned int delim; + std::string sysEncoding; + bool sysIsUTF8; + iconv_t iconv_cd; std::string data, cdata, tag, attrn, attrv; std::map attr; @@ -49,11 +54,12 @@ protected: bool IsTokenChar(bool start, int c); - int ReadChar(int c); + int ReadChar(unsigned int c, int char_size); public: - cXML(const std::string & file); - cXML(const char * mem, unsigned int len); + cXML(const std::string & file, const std::string sysCharset = "UTF-8"); + //cXML(const char * mem, unsigned int len); + ~cXML(); void SetNodeStartCB(XML_NODE_START_CB(cb)); void SetNodeEndCB(XML_NODE_END_CB(cb)); diff -Nru graphlcd-base-0.2.0+git20101020/graphlcd.conf graphlcd-base-0.1.9+git20120310/graphlcd.conf --- graphlcd-base-0.2.0+git20101020/graphlcd.conf 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/graphlcd.conf 2012-03-10 09:18:56.000000000 +0000 @@ -76,7 +76,7 @@ # Brightness # Sets the brightness of your display's backlight if supported by its # driver. -# Supported by: gu140x32f, gu256x64-372, gu256x64-3900, gu126x64D-K610A4 +# Supported by: gu140x32f, gu256x64-372, gu256x64-3900, gu126x64D-K610A4, ax206dpf # Possible values: 0 <= x <= 100) # Default value: 100 # @@ -120,17 +120,32 @@ [framebuffer] # framebuffer driver # Output goes to a framebuffer device -# Default size: 320 x 240 Driver=framebuffer -#Width=320 -#Height=240 #UpsideDown=no #Invert=no +# Device +# Framebuffer device +# Default value: /dev/fb0 +#Device=/dev/fb0 + +# Damage | ReportDamage +# Damage reporting for framebuffer devices with update problems +# Possible values: none, auto, udlfb, ugly +# none: no damage reporting +# auto: automatic determination if damage reporting is needed +# udlfb: damage reporting for udlfb-devices (displaylink) +# ugly: dirty damagereporting (a '\n' is written to the framebuffer file handle) +# Default value: none +#Damage=none + # Zoom # Determines if pixels should be drawn double sized. +# If zoom is set, the actual resolution will be halved (both width and height) +# e.g.: framebuffer has resolution 800x600: this driver will report a drawing area of 400x300 # Possible values: 0, 1 +# Default value: 1 Zoom=1 ######################################################################## @@ -429,8 +444,6 @@ #Controller=nokia7110 #Controller=sed1335 Controller=optrex323 -#Controller=l4m132c -#Controller=l4m320t # Options # Pass display specific options @@ -467,9 +480,6 @@ Device=/dev/parport0 #Port=0x378 -#Device=HID:/dev/usb/hiddev0 -#Device=HID:/dev/hiddev0 -#Device=USB:USB:4243/ee20 # Linux4Media 320T TouchLCD #UpsideDown=no #Invert=no Contrast=5 @@ -565,18 +575,75 @@ # USB ID activy 5xx: #Vendor=0x1509 #Product=0x925d - ######################################################################## -[futabaMDM166A] -# futabaMDM166A driver -# This is an driver module for Futaba MDM166A VFD displays. -# The VFD is built-in in Targa HTPC cases and connected to USB port. -# Default size: 96 x 16 -Driver=futabaMDM166A -#Width=96 -#Height=16 +[ax206dpf] +# THIS IS AN EXPERIMENTAL DRIVER! +# You have to uncomment the variable HAVE_AX206DPF_EXPERIMENTAL +# in Make.config to use this driver. +# READ the READDME.ax206dpf before use! +# +# ax206dpf driver +# This is a driver module for an AX 206 based hacked photoframe. +# +# Default size: 320 x 240 or 240 x 320 (see "Portrait") +Driver=ax206dpf +#Width=320 +#Height=240 +# +# UpsideDown +# Rotates the display output by 180 degrees. This might be useful, if +# the LCD is mounted upside-down. +# Possible values: 'yes', 'no' +# Default value: 'no' #UpsideDown=no -#Invert=no -#Brightness=50 -#RefreshDisplay=1000 +# +# Brightness +# Sets the brightness of the display's backlight +# Possible values: 0 <= x <= 100) +# Default value: 100 +#Brightness=100 +# +# Device +# Selects a specific display +# 'dpf0' = first detected display, 'dpf1' = second detected display, ... +# Default value: 'dpf0' +#Device=dpf0 +# +# Portrait +# Select portrait or landscape mode +# Rotate display output by 90 degrees if necessary +# Possible values: 'yes' -> default size = 240 x 320 +# 'no' -> default size = 320 x 240 +# Default value: 'no' +#Portrait=no +# +# Zoom +# Determines if pixels should be magnified. +# Possible values: 1, 2, 3, 4 +# Default value: 1 +#Zoom=1 +# +# The following parameters are for multi-display setups only! +# +# Horizontal +# Sets the number of displays in horizontal direction. +# Possible values if Vertical=1: 1, 2, 3, 4 +# if Vertical=2: 1, 2 +# Default value: 1 +#Horizontal=1 +# +# Vertical +# Sets the number of displays in vertical direction. +# Possible values if Horizontal=1: 1, 2, 3, 4 +# if Horizontal=2: 1, 2 +# Default value: 1 +#Vertical=1 +# +# Flip +# Rotates a single displays output by 180 degrees. This might be useful, if +# some LCDs are mounted upside-down. +# Possible values for every display : 'y', 'n' +# Default value: 'nnnn' +#Flip=nnnn +# diff -Nru graphlcd-base-0.2.0+git20101020/HISTORY graphlcd-base-0.1.9+git20120310/HISTORY --- graphlcd-base-0.2.0+git20101020/HISTORY 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/HISTORY 2012-03-10 09:18:56.000000000 +0000 @@ -1,6 +1,57 @@ GraphLCD base package Revision History -------------------------------------- +2011-05-01: branch touchcol, first commit +- glcddrivers changes / enhancements: + - support for colour bitmap data + - support for colours either by using pre-defined colour names or 0xRRGGBB / 0xAARRGGBB (though no alpha channel is supported yet) + - adapted/added methods SetScreen(), SetPixel()-methods in base-class and driver-classes for new colour enabled bitmap data + - added support for events (supported for now: simple touch events) + - added support for requesting and setting driver features + - added GetBackgroundColor(), GetForegroundColor() -> gets default back/foreground colour + - fixed compiler warnings (missing parameters in printf(), ...) + - dm140glnk: bugfix: changed type for vendor and product to 'signed' + - serdisp: + - added support for touch events + - cut support for serdisplib version < 1.95 (-> simplifies code) + - added basic support for GPIs (eg. enable/disable touchpad) + - rotate only when graphlcd-setup says so + - UTF8 should work fine but is not tested very well yet + - vdr 1.3.x should be supported as well but support for it is deprecated and will be removed (-> cleaner code) +- glcdskin changes / enhancements: + - improved update policies (update only display regions that require update) - w/o this displays like l4m320t would be unusable w/ graphlcd. + - new objects / attributes / features for skins: + - increased skin version to 1.1, version info is now verified before loading a skin + - objects can now trigger actions (eg. when touching an object it may trigger a VDR 'Key'-event) + - 'scrolltext' is deprecated and is now an aliases for 'text' + - new object 'button' + - new attribute 'valign': vertical alignment + - attribute 'bgcolor': sets background colour for object (whereas 'color' sets foreground colour) + - new attributes 'alttext' and 'altcondition' for object 'text' (if 'altcondition' is true, 'alttext' is evaluated and used) + - scrolling/looping attributes for 'text': 'loop', 'scrollmode', 'scrollspeed', 'scrolltime' + - new attribute 'default' for variables: + shortcut for : + + this will actually be stored in two variable entries (exactly as in the first version) + - new entity 'condblock': combines variables that use the same condition + + + + + can now be simplified to + + + + + attention: variable-definitions in a condblock must not contain condition-attributes. + - XML parser: + - parser method XmlParse() optionally may pass an error string + - text-objects may now contain combinations of tokens, constants, and variables + - evaluation of variables in text-objects is now delayed from parsing time to runtime + - attention: 'condblock' and attributes 'alttext', 'altcondition' are case studies for now and may be removed +- all changes/modifications/improvements that i've missed in this list + + 2010-04-23: version 0.1.6_1 - added additional wiring for GU256x64-372 driver (thanks to mentox, http://www.vdr-portal.de/board/thread.php?postid=895721#post895721) diff -Nru graphlcd-base-0.2.0+git20101020/Make.config graphlcd-base-0.1.9+git20120310/Make.config --- graphlcd-base-0.2.0+git20101020/Make.config 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/Make.config 2012-03-29 21:49:37.000000000 +0000 @@ -34,3 +34,10 @@ # comment this variable out if you don't want to use FreeType2 font rendering HAVE_FREETYPE2=1 +# uncomment one of the following two lines if you want either GraphicsMagick/ImageMagick support +HAVE_IMAGEMAGICK=1 +#HAVE_GRAPHICSMAGICK=1 + +# uncomment this variable if you want to enable the experimental AX 206 based digital photo frame driver +# Read DRIVER.ax206dpf before use! +#HAVE_AX206DPF_EXPERIMENTAL=1 diff -Nru graphlcd-base-0.2.0+git20101020/Makefile graphlcd-base-0.1.9+git20120310/Makefile --- graphlcd-base-0.2.0+git20101020/Makefile 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/Makefile 2012-03-10 09:18:56.000000000 +0000 @@ -3,46 +3,40 @@ # PROJECT = graphlcd-base -VERSION = 0.1.6 +VERSION = 0.3.0 ARCHIVE = $(PROJECT)-$(VERSION) PACKAGE = $(ARCHIVE) TMPDIR = /tmp -INCLUDE_SKINS=1 +UDEVRULESDIR = /etc/udev/rules.d/ +UDEVRULE = "99-graphlcd-base.rules" ### Targets: all: @$(MAKE) -C glcdgraphics all @$(MAKE) -C glcddrivers all -ifdef INCLUDE_SKINS @$(MAKE) -C glcdskin all -endif @$(MAKE) -C tools all install: @$(MAKE) -C glcdgraphics install @$(MAKE) -C glcddrivers install -ifdef INCLUDE_SKINS @$(MAKE) -C glcdskin install -endif @$(MAKE) -C tools install + test -d "${UDEVRULESDIR}" || install -m 644 -o root -g root $(UDEVRULE) $(UDEVRULESDIR) uninstall: @$(MAKE) -C glcdgraphics uninstall @$(MAKE) -C glcddrivers uninstall -ifdef INCLUDE_SKINS @$(MAKE) -C glcdskin uninstall -endif @$(MAKE) -C tools uninstall clean: @-rm -f *.tgz @$(MAKE) -C glcdgraphics clean @$(MAKE) -C glcddrivers clean -ifdef INCLUDE_SKINS @$(MAKE) -C glcdskin clean -endif @$(MAKE) -C tools clean dist: clean diff -Nru graphlcd-base-0.2.0+git20101020/README graphlcd-base-0.1.9+git20120310/README --- graphlcd-base-0.2.0+git20101020/README 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/README 2012-03-10 09:18:56.000000000 +0000 @@ -11,7 +11,7 @@ from 0.0.8 on maintained by Andreas Regel (andreas.regel AT powarman.de) from 0.1.5 on maintained by Wolfgang Astleitner (mrwastl AT users.sourceforge.net) & Andreas 'randy' Weinberger (vdr AT smue.org) - gu140x32f driver by Andreas Brachold (vdr07 AT deltab.de) + gu140x32f driver by Andreas Brachold (vdr04 AT deltab.de) gu256x64-372 driver by Andreas Weinberger (vdr AT smue.org) gu256x64-3xx0 driver by Ralf Mueller (ralf AT bj-ig.de) gu126x64D-K610A4 driver by Alexander Rieger (Alexander.Rieger AT inka.de) @@ -25,7 +25,6 @@ t6963c driver by Andreas Regel (andreas.regel AT powarman.de) noritake800 driver by Lucian Muresan (lucianm AT users.sourceforge.net) futaba dm140 driver by Stephan Skrodzki (skrodzki AT stevekist.de) - futama md166 driver by Andreas Brachold Project's homepage: http://graphlcd.berlios.de/ GIT repo: http://projects.vdr-developer.org/projects/show/graphlcd diff -Nru graphlcd-base-0.2.0+git20101020/TODO graphlcd-base-0.1.9+git20120310/TODO --- graphlcd-base-0.2.0+git20101020/TODO 1970-01-01 00:00:00.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/TODO 2012-03-10 09:18:56.000000000 +0000 @@ -0,0 +1,18 @@ +TODO: +- add missing objects like textbox, scrollbar +- add special objects for external data so that other plugins can draw text and bitmaps on an area of the display that will be defined in the skin. This could be used p.e. for a spectrum analyzer or displaying id3 tags. +- add service interface for external data objects +- DOCUMENTATION, DOCUMENTATION, DOCUMENTATION +- fix all the small bugs that were introduced +- all the stuff I forgot :-) + +- all tools (convpic, ...) are probably not functional yet +- support for loading colour BMPs and other formats + + +DONE/SOLVED/PARTIALLY SOLVED: +- add dynamic behaviour to objects like scrolling and blinking (done, but w/o blinking) +- make skin variables more dynamic, p.e. evaluate positions while displaying, not only during skin loading. This should make it easier to support several display sizes with one skin (done for text-objects, but not for attributes) + + +this TODO is initially based on the plans of andreas regel. diff -Nru graphlcd-base-0.2.0+git20101020/tools/convpic/bmp.c graphlcd-base-0.1.9+git20120310/tools/convpic/bmp.c --- graphlcd-base-0.2.0+git20101020/tools/convpic/bmp.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/tools/convpic/bmp.c 2012-03-10 09:18:56.000000000 +0000 @@ -89,7 +89,8 @@ long iSize; uint32_t x, y; uint16_t iRead; - uint8_t * bitmap = NULL; +// uint8_t * bitmap = NULL; + uint32_t *bitmap = NULL; bool bInvert = false; if (fileName.length() > 0) @@ -163,7 +164,8 @@ image.SetWidth(bmpHeader.bmpWidth); image.SetHeight(bmpHeader.bmpHeight); image.SetDelay(100); - bitmap = new unsigned char[bmpHeader.bmpHeight * ((bmpHeader.bmpWidth + 7) / 8)]; +// bitmap = new unsigned char[bmpHeader.bmpHeight * ((bmpHeader.bmpWidth + 7) / 8)]; + bitmap = new uint32_t [bmpHeader.bmpHeight * bmpHeader.bmpWidth]; if (!bitmap) { fprintf(stderr, "ERROR: cannot allocate memory\n"); @@ -260,7 +262,8 @@ char Dummy = 0x00; uint32_t x, y; uint16_t iWrote; - const uint8_t * bmpdata = bitmap->Data(); +// const uint8_t * bmpdata = bitmap->Data(); + const uint32_t * bmpdata = bitmap->Data(); if (bitmap && bitmap->Width() > 0 diff -Nru graphlcd-base-0.2.0+git20101020/tools/convpic/tiff.c graphlcd-base-0.1.9+git20120310/tools/convpic/tiff.c --- graphlcd-base-0.2.0+git20101020/tools/convpic/tiff.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/tools/convpic/tiff.c 2012-03-10 09:18:56.000000000 +0000 @@ -71,7 +71,8 @@ unsigned char fLittleEndian=0; int j; int t; - unsigned char *bitmap = NULL; +// unsigned char *bitmap = NULL; + uint32_t *bitmap = NULL; bool bInvert = false; if (fileName.length() > 0) @@ -152,7 +153,8 @@ image.SetWidth(width); image.SetHeight(height); image.SetDelay(100); - bitmap = new unsigned char[height * ((width + 7) / 8)]; +// bitmap = new unsigned char[height * ((width + 7) / 8)]; + bitmap = new uint32_t[height * width]; if (bitmap) { if (fread(bitmap, height*((width+7)/8), 1, fIN)!=1) diff -Nru graphlcd-base-0.2.0+git20101020/tools/convpic/tuxbox.c graphlcd-base-0.1.9+git20120310/tools/convpic/tuxbox.c --- graphlcd-base-0.2.0+git20101020/tools/convpic/tuxbox.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/tools/convpic/tuxbox.c 2012-03-10 09:18:56.000000000 +0000 @@ -118,15 +118,19 @@ for (unsigned int n=0;n [ oooooooo ] {o}[o][o][o][o][o][o][o] => [ oooooooo ] {o}[o][o][o][o][o][o][o] => [ oooooooo ]*/ -void cTuxBoxFile::vert2horz(const unsigned char* source, unsigned char* dest, int width, int height) { +//void cTuxBoxFile::vert2horz(const unsigned char* source, unsigned char* dest, int width, int height) { +void cTuxBoxFile::vert2horz(const uint32_t *source, uint32_t *dest, int width, int height) { int x, y, off; memset(dest,0,height*((width+7)/8)); @@ -261,7 +267,8 @@ [ oooooooo ] => {o}[o][o][o][o][o][o][o] [ oooooooo ] => {o}[o][o][o][o][o][o][o] [ oooooooo ] => {o}[o][o][o][o][o][o][o]*/ -void cTuxBoxFile::horz2vert(const unsigned char* source, unsigned char* dest, int width, int height) { +//void cTuxBoxFile::horz2vert(const unsigned char* source, unsigned char* dest, int width, int height) { +void cTuxBoxFile::horz2vert(const uint32_t *source, uint32_t *dest, int width, int height) { int x, y, off; memset(dest,0,width*((height+7)/8)); diff -Nru graphlcd-base-0.2.0+git20101020/tools/convpic/tuxbox.h graphlcd-base-0.1.9+git20120310/tools/convpic/tuxbox.h --- graphlcd-base-0.2.0+git20101020/tools/convpic/tuxbox.h 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/tools/convpic/tuxbox.h 2012-03-10 09:18:56.000000000 +0000 @@ -32,8 +32,10 @@ class cTuxBoxFile : public GLCD::cImageFile { private: - void vert2horz(const unsigned char* source, unsigned char* dest, int width, int height); - void horz2vert(const unsigned char* source, unsigned char* dest, int width, int height); +// void vert2horz(const unsigned char* source, unsigned char* dest, int width, int height); +// void horz2vert(const unsigned char* source, unsigned char* dest, int width, int height); + void vert2horz(const uint32_t *source, uint32_t *dest, int width, int height); + void horz2vert(const uint32_t *source, uint32_t *dest, int width, int height); public: cTuxBoxFile(); virtual ~cTuxBoxFile(); diff -Nru graphlcd-base-0.2.0+git20101020/tools/crtfont/crtfont.c graphlcd-base-0.1.9+git20120310/tools/crtfont/crtfont.c --- graphlcd-base-0.2.0+git20101020/tools/crtfont/crtfont.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/tools/crtfont/crtfont.c 2012-03-10 09:18:56.000000000 +0000 @@ -10,7 +10,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #include @@ -20,6 +22,8 @@ #include #include #include +#include +#include static const char *prgname = "crtfont"; static const char *version = "0.1.6"; @@ -151,15 +155,25 @@ // Load Picture switch (picFormat) { - case PBM: - bitmap = new GLCD::cBitmap(0, 0); - bitmap->LoadPBM(picName); - if (!bitmap) - { + case PBM: { + GLCD::cPBMFile pbm; + GLCD::cImage* image = new GLCD::cImage(); + + if (!image) + return 3; + + if (pbm.Load(*image, picName) == false) { fprintf(stderr, "Cannot open file: %s\n",picName); + delete image; return 2; } - break; + + const GLCD::cBitmap * pbmbm = image->GetBitmap(); + bitmap = new GLCD::cBitmap(*pbmbm); + delete image; + pbmbm = NULL; + } + break; default: return 2; @@ -296,7 +310,7 @@ fprintf(stdout, " graphlcd plugin for VDR.\n\n"); fprintf(stdout, " Usage: %s -f -b bmpfile -d descfile -o outfile\n\n", prgname); fprintf(stdout, " -f --format specifies the format of the bitmap. Possible values are:\n"); - fprintf(stdout, " PBM : file is an binary PBM file\n" ); + fprintf(stdout, " PBM : file is a binary PBM file\n" ); fprintf(stdout, " -b --bmpfile specifies the name of the bitmap file (*.pbm)\n"); fprintf(stdout, " -d --descfile specifies the name of the description file (*.desc)\n"); fprintf(stdout, " -o --outfile specifies the name of the output file (*.fnt)\n"); diff -Nru graphlcd-base-0.2.0+git20101020/tools/genfont/genfont.c graphlcd-base-0.1.9+git20120310/tools/genfont/genfont.c --- graphlcd-base-0.2.0+git20101020/tools/genfont/genfont.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/tools/genfont/genfont.c 2012-03-10 09:18:56.000000000 +0000 @@ -7,7 +7,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #include @@ -17,6 +19,8 @@ #include #include +#include +#include static const char *prgname = "genfont"; static const char *version = "0.0.2"; @@ -136,13 +140,14 @@ fprintf(descFile, "spacebetween:%d\n", 0); fprintf(descFile, "spacewidth:%d\n", 0); - for (unsigned int i = 0; i < 256; i++) + for (uint32_t i = 0; i < 256; i++) { - const GLCD::cBitmap * charBitmap = font.GetCharacter((char) i); + const GLCD::cBitmap * charBitmap = font.GetCharacter(i); + if (charBitmap == NULL) continue; - bitmap->DrawBitmap(posX, posY, *charBitmap, GLCD::clrBlack); + bitmap->DrawBitmap(posX, posY, *charBitmap); fprintf(descFile, "%d %d ", posX, i); posX += charBitmap->Width(); if ((i % 32) == 31) @@ -156,9 +161,23 @@ if (posX > 0) // write last end marker fprintf(descFile, "%d\n", posX); fileName = outputName + ".pbm"; - bitmap->SavePBM(fileName); - delete bitmap; + + GLCD::cPBMFile pbm; + GLCD::cImage* image = new GLCD::cImage(); + + if (!image) + return 3; + + image->AddBitmap(bitmap); + + if (pbm.Save(*image, fileName) == false) { + fprintf(stderr, "Cannot save file: %s\n",fileName.c_str()); + delete image; + return 2; + } + fclose(descFile); + delete image; } fprintf(stdout, "Font successfully generated.\n"); diff -Nru graphlcd-base-0.2.0+git20101020/tools/lcdtestpattern/Makefile graphlcd-base-0.1.9+git20120310/tools/lcdtestpattern/Makefile --- graphlcd-base-0.2.0+git20101020/tools/lcdtestpattern/Makefile 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/tools/lcdtestpattern/Makefile 2012-03-10 09:18:56.000000000 +0000 @@ -32,7 +32,7 @@ # The main program: $(PRGNAME): $(OBJS) - $(CXX) $(CXXFLAGS) $(LDFLAGS) -rdynamic $(OBJS) $(LIBS) $(LIBDIRS) -lglcdgraphics -lglcddrivers -lstdc++ -o $(PRGNAME) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -rdynamic $(OBJS) $(LIBS) $(LIBDIRS) -lglcddrivers -lglcdgraphics -lstdc++ -o $(PRGNAME) install: $(PRGNAME) install -d $(BINDIR) diff -Nru graphlcd-base-0.2.0+git20101020/tools/showpic/showpic.c graphlcd-base-0.1.9+git20120310/tools/showpic/showpic.c --- graphlcd-base-0.2.0+git20101020/tools/showpic/showpic.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/tools/showpic/showpic.c 2012-03-10 09:18:56.000000000 +0000 @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #include @@ -29,6 +31,7 @@ #include #include #include +#include static const char *prgname = "showpic"; static const char *version = "0.1.2"; @@ -53,7 +56,7 @@ { fprintf(stdout, "\n"); fprintf(stdout, "%s v%s\n", prgname, version); - fprintf(stdout, "%s is a tool to show an image on a LCD.\n", prgname); + fprintf(stdout, "%s is a tool to show an image on an LCD.\n", prgname); fprintf(stdout, "The image must be in a special format (*.glcd).\n"); fprintf(stdout, "You can create such images with the convpic tool.\n\n"); fprintf(stdout, " Usage: %s [-c CONFIGFILE] [-d DISPLAY] [-s SLEEP] [-uie] file [more files]\n\n", prgname); @@ -64,7 +67,7 @@ fprintf(stdout, " -i --invert inverts the output (default: no)\n"); fprintf(stdout, " -e --endless show all images in endless loop (default: no)\n"); fprintf(stdout, " -s --sleep set sleeptime between two images [ms] (default: %d ms)\n", kDefaultSleepMs); - fprintf(stdout, " -b --brightness set brightness for display if driver support it [%%]\n"); + fprintf(stdout, " -b --brightness set brightness for display (if supported by the driver) [%%]\n"); fprintf(stdout, " (default: config file value)\n"); fprintf(stdout, "\n" ); fprintf(stdout, " examples: %s -c /etc/graphlcd.conf vdr-logo.glcd\n", prgname); @@ -199,7 +202,7 @@ delete lcd; return 7; } - lcd->SetBrightness(GLCD::Config.driverConfigs[displayNumber].brightness); + lcd->SetBrightness(GLCD::Config.driverConfigs[displayNumber].brightness); signal(SIGINT, sighandler); signal(SIGQUIT, sighandler); @@ -209,6 +212,8 @@ const GLCD::cBitmap * bitmap; GLCD::cImage image; GLCD::cGLCDFile glcd; + GLCD::cExtFormatFile extformat; + int optFile; std::string picFile; @@ -216,19 +221,22 @@ while (optFile < argc && !stopProgramm) { picFile = argv[optFile++]; - if (glcd.Load(image, picFile) == false) - { - fprintf(stderr, "ERROR: Failed loading file %s\n", picFile.c_str()); - return 8; + if (glcd.Load(image, picFile) == false) { + if (extformat.Load(image, picFile) == false) { + fprintf(stderr, "ERROR: Failed loading file %s\n", picFile.c_str()); + return 8; + } } if (delay) image.SetDelay(sleepMs); + lcd->Refresh(true); while ((bitmap = image.GetBitmap()) != NULL && !stopProgramm) { - lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height(), bitmap->LineSize()); - lcd->Refresh(true); +// lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height(), bitmap->LineSize()); + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(false); if (image.Next(0)) // Select next image { diff -Nru graphlcd-base-0.2.0+git20101020/tools/showtext/showtext.c graphlcd-base-0.1.9+git20120310/tools/showtext/showtext.c --- graphlcd-base-0.2.0+git20101020/tools/showtext/showtext.c 2010-10-05 19:11:05.000000000 +0000 +++ graphlcd-base-0.1.9+git20120310/tools/showtext/showtext.c 2012-03-10 09:18:56.000000000 +0000 @@ -6,7 +6,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel + * (c) 2004-2010 Andreas Regel + * (c) 2010-2011 Wolfgang Astleitner + * Andreas 'randy' Weinberger */ #include @@ -35,7 +37,7 @@ { fprintf(stdout, "\n"); fprintf(stdout, "%s v%s\n", prgname, version); - fprintf(stdout, "%s is a tool to show a text on a LCD.\n", prgname); + fprintf(stdout, "%s is a tool to show a text on an LCD.\n", prgname); fprintf(stdout, "\n"); fprintf(stdout, " Usage: %s [-c CONFIGFILE] [-d DISPLAY] [-f FONT] [-x XPOS] [-y YPOS] [-uib] text [more text]\n\n", prgname); fprintf(stdout, " -c --config specifies the location of the config file\n"); @@ -269,7 +271,8 @@ bitmap->DrawText(x, y, bitmap->Width() - 1, text, &font); y += font.LineHeight(); } - lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height(), bitmap->LineSize()); +// lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height(), bitmap->LineSize()); + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); lcd->Refresh(true); lcd->DeInit();