summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--99-graphlcd-base.rules8
-rw-r--r--HISTORY52
-rw-r--r--Make.config58
-rw-r--r--Makefile14
-rw-r--r--README6
-rw-r--r--TODO18
-rw-r--r--docs/DRIVER.ax206dpf160
-rw-r--r--docs/DRIVER.futabaMDM166A4
-rw-r--r--glcddrivers/Makefile49
-rw-r--r--glcddrivers/avrctl.c30
-rw-r--r--glcddrivers/avrctl.h8
-rw-r--r--glcddrivers/ax206dpf.c992
-rw-r--r--glcddrivers/ax206dpf.h300
-rw-r--r--glcddrivers/common.c5
-rw-r--r--glcddrivers/config.c9
-rw-r--r--glcddrivers/config.h3
-rw-r--r--glcddrivers/dm140gink.c24
-rw-r--r--glcddrivers/dm140gink.h15
-rw-r--r--glcddrivers/driver.c61
-rw-r--r--glcddrivers/driver.h99
-rw-r--r--glcddrivers/drivers.c50
-rw-r--r--glcddrivers/drivers.h17
-rw-r--r--glcddrivers/framebuffer.c313
-rw-r--r--glcddrivers/framebuffer.h20
-rw-r--r--glcddrivers/futabaMDM166A.c27
-rw-r--r--glcddrivers/futabaMDM166A.h12
-rw-r--r--glcddrivers/g15daemon.c22
-rw-r--r--glcddrivers/g15daemon.h12
-rw-r--r--glcddrivers/gu126x64D-K610A4.c29
-rw-r--r--glcddrivers/gu126x64D-K610A4.h11
-rw-r--r--glcddrivers/gu140x32f.c20
-rw-r--r--glcddrivers/gu140x32f.h11
-rw-r--r--glcddrivers/gu256x64-372.c32
-rw-r--r--glcddrivers/gu256x64-372.h10
-rw-r--r--glcddrivers/gu256x64-3900.c26
-rw-r--r--glcddrivers/gu256x64-3900.h12
-rw-r--r--glcddrivers/hd61830.c31
-rw-r--r--glcddrivers/hd61830.h7
-rw-r--r--glcddrivers/ili9341.c395
-rw-r--r--glcddrivers/ili9341.h53
-rw-r--r--glcddrivers/image.c40
-rw-r--r--glcddrivers/image.h13
-rw-r--r--glcddrivers/ks0108.c32
-rw-r--r--glcddrivers/ks0108.h12
-rw-r--r--glcddrivers/network.c35
-rw-r--r--glcddrivers/network.h9
-rw-r--r--glcddrivers/noritake800.c155
-rw-r--r--glcddrivers/noritake800.h12
-rw-r--r--glcddrivers/picoLCD_256x64.c553
-rw-r--r--glcddrivers/picoLCD_256x64.h106
-rw-r--r--glcddrivers/port.c53
-rw-r--r--glcddrivers/port.h4
-rw-r--r--glcddrivers/sed1330.c33
-rw-r--r--glcddrivers/sed1330.h9
-rw-r--r--glcddrivers/sed1520.c32
-rw-r--r--glcddrivers/sed1520.h8
-rw-r--r--glcddrivers/serdisp.c409
-rw-r--r--glcddrivers/serdisp.h98
-rw-r--r--glcddrivers/simlcd.c114
-rw-r--r--glcddrivers/simlcd.h12
-rw-r--r--glcddrivers/ssd1306.c340
-rw-r--r--glcddrivers/ssd1306.h53
-rw-r--r--glcddrivers/t6963c.c55
-rw-r--r--glcddrivers/t6963c.h8
-rw-r--r--glcddrivers/vncserver.c211
-rw-r--r--glcddrivers/vncserver.h50
-rw-r--r--glcdgraphics/Makefile41
-rw-r--r--glcdgraphics/bitmap.c570
-rw-r--r--glcdgraphics/bitmap.h114
-rw-r--r--glcdgraphics/common.c68
-rw-r--r--glcdgraphics/common.h8
-rw-r--r--glcdgraphics/extformats.c184
-rw-r--r--glcdgraphics/extformats.h37
-rw-r--r--glcdgraphics/font.c262
-rw-r--r--glcdgraphics/font.h26
-rw-r--r--glcdgraphics/glcd.c57
-rw-r--r--glcdgraphics/image.c189
-rw-r--r--glcdgraphics/image.h10
-rw-r--r--glcdgraphics/imagefile.c21
-rw-r--r--glcdgraphics/imagefile.h7
-rw-r--r--glcdgraphics/pbm.c93
-rw-r--r--glcdskin/Makefile20
-rw-r--r--glcdskin/cache.c70
-rw-r--r--glcdskin/cache.h16
-rw-r--r--glcdskin/config.h4
-rw-r--r--glcdskin/display.c15
-rw-r--r--glcdskin/display.h2
-rw-r--r--glcdskin/font.c101
-rw-r--r--glcdskin/font.h3
-rw-r--r--glcdskin/function.c87
-rw-r--r--glcdskin/function.h7
-rw-r--r--glcdskin/object.c594
-rw-r--r--glcdskin/object.h90
-rw-r--r--glcdskin/parser.c304
-rw-r--r--glcdskin/parser.h12
-rw-r--r--glcdskin/skin.c14
-rw-r--r--glcdskin/skin.h12
-rw-r--r--glcdskin/string.c155
-rw-r--r--glcdskin/string.h4
-rw-r--r--glcdskin/type.h4
-rw-r--r--glcdskin/variable.c82
-rw-r--r--glcdskin/variable.h19
-rw-r--r--glcdskin/xml.c161
-rw-r--r--glcdskin/xml.h14
-rw-r--r--graphlcd.conf134
-rw-r--r--tools/Makefile4
-rw-r--r--tools/convpic/Makefile11
-rw-r--r--tools/convpic/bmp.c375
-rw-r--r--tools/convpic/bmp.h45
-rw-r--r--tools/convpic/convpic.c219
-rw-r--r--tools/convpic/tiff.c201
-rw-r--r--tools/convpic/tiff.h42
-rw-r--r--tools/convpic/tuxbox.c280
-rw-r--r--tools/convpic/tuxbox.h44
-rw-r--r--tools/crtfont/Makefile9
-rw-r--r--tools/crtfont/crtfont.c30
-rw-r--r--tools/genfont/Makefile9
-rw-r--r--tools/genfont/genfont.c31
-rw-r--r--tools/lcdtestpattern/Makefile11
-rw-r--r--tools/showpic/Makefile9
-rw-r--r--tools/showpic/showpic.c466
-rw-r--r--tools/showtext/Makefile9
-rw-r--r--tools/showtext/showtext.c9
-rw-r--r--tools/skintest/DejaVuSans.ttfbin0 -> 720012 bytes
-rw-r--r--tools/skintest/Makefile42
-rw-r--r--tools/skintest/skintest.c190
-rw-r--r--tools/skintest/test.skin50
128 files changed, 8524 insertions, 2657 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2d1bf8b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.d
+*.o
+*.so*
diff --git a/99-graphlcd-base.rules b/99-graphlcd-base.rules
new file mode 100644
index 0000000..1f5cd6b
--- /dev/null
+++ b/99-graphlcd-base.rules
@@ -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 --git a/HISTORY b/HISTORY
index c22c8a9..1055121 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,56 @@
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 <variable id="name" value="value1" condition="somecondition"/> <variable id="name" value="value2"/>:
+ <variable id="name" value="value1" condition="somecondition" default="value2"/>
+ 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
+ <variable id="id1" condition="condition1" value="val1"/>
+ <variable id="id1" value="valdefault1"/>
+ <variable id="id2" condition="condition1" value="val2"/>
+ <variable id="id2" value="valdefault2"/>
+ can now be simplified to
+ <condblock condition="condition1">
+ <variable id="id1" value="val1" default="valdefault1"/>
+ <variable id="id2" value="val2" default="valdefault2"/>
+ </condblock>
+ 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
+
2011-02-13: version 0.1.9
- fixed compile error. http://www.vdrportal.de/board/thread.php?postid=959952#post959952
- changed graphlcd.conf back to original: http://projects.vdr-developer.org/issues/524
@@ -9,7 +59,7 @@ GraphLCD base package Revision History
2010-11-02: version 0.1.7
- added futuba MDM166A driver from andreas brachold: http://projects.vdr-developer.org/issues/351
- fixed compiler warnings: http://projects.vdr-developer.org/issues/352
-- added new attribute 'valign' (vertical alignment) for text objects.
+- added new attribute 'valign' (vertical alignment) for text objects.
- text-object: fix to avoid stumbling scrolling
- text-object: added support for alternative text / alternative condition
- glcdskin: bugfixing and improvements
diff --git a/Make.config b/Make.config
index 017f2b6..3ddedd2 100644
--- a/Make.config
+++ b/Make.config
@@ -6,17 +6,33 @@
CC = gcc
CFLAGS = -O2
-CXX = g++
+#CXX = g++
+
CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual
#CXXFLAGS = -g -ggdb -O0 -Wall -Woverloaded-virtual
+CXXFLAGS += -MMD -MP
+
+# no CXX given at all: force g++
+ifeq (x$(CXX)x,xx)
+ CXX=g++
+endif
+
+# CXX set to clang++: force clang
+ifeq ($(CXX),clang++)
+ CXX = clang
+endif
+
+# set CXXEXTRA according to compiler that is used
+ifeq ($(CXX),clang)
+ CXXEXTRA = -x c++ -Qunused-arguments
+else
+ CXXEXTRA =
+endif
#LDFLAGS = -g -ggdb -O0
LDCONFIG = ldconfig
-### strip binaries when installing by default, but allow easyly supressing it
-STRIP ?= -s
-
### The directory environment:
ifndef $(DESTDIR)
@@ -33,7 +49,41 @@ MANDIR = $(DESTDIR)/man
#INCLUDES += -I
DEFINES += -D_GNU_SOURCE
+# define HAVE_DEBUG when invoking "make" if you want to use debugging
+ifdef HAVE_DEBUG
+DEFINES += -DHAVE_DEBUG
+endif
+
+
+#
+#
+# Build & install configuration
# comment this variable out if you don't want to use FreeType2 font rendering
HAVE_FREETYPE2=1
+# comment this variable out if you don't want to use fontconfig font names
+HAVE_FONTCONFIG=1
+
+# comment this variable out if you want binaries to be stripped when installing (for production-level binaries or packages)
+#HAVE_STRIP = -s
+
+# uncomment one of the following two lines if you want either GraphicsMagick/ImageMagick support
+#HAVE_IMAGEMAGICK=1
+#HAVE_GRAPHICSMAGICK=1
+
+# comment this variable or set to 0 if you do not want to build the vncserver driver, even if requirements (libvncserver) are fullfilled on the system
+HAVE_DRIVER_VNCSERVER=1
+
+### Experimental drivers
+
+# uncomment this variable if you want to enable the experimental AX 206 based digital photo frame driver
+# Read DRIVER.ax206dpf before use!
+#HAVE_DRIVER_AX206DPF=1
+
+# uncomment this variable if you want to enable the experimental support for picoLCD 256x64
+#HAVE_DRIVER_picoLCD_256x64=1
+
+#HAVE_DRIVER_SSD1306=1
+
+#HAVE_DRIVER_ILI9341=1
diff --git a/Makefile b/Makefile
index d5ffe7b..82f06b4 100644
--- a/Makefile
+++ b/Makefile
@@ -3,46 +3,40 @@
#
PROJECT = graphlcd-base
-VERSION = 0.1.9
+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 --git a/README b/README
index e717dbb..37d8b88 100644
--- a/README
+++ b/README
@@ -25,7 +25,7 @@ based on the graphlcd plugin for the Video Disc Recorder
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 <vdr07 AT deltab de>
+ futaba md166 driver by Andreas Brachold <vdr07 AT deltab de>
Project's homepage: http://graphlcd.berlios.de/
GIT repo: http://projects.vdr-developer.org/projects/show/graphlcd
@@ -67,8 +67,8 @@ Installation and Configuration:
tar xzf graphlcd-base-0.1.8.tgz
-2. Configure if you want FreeType2 support by commenting/uncommenting
- HAVE_FREETYPE2 in Make.config.
+2. Configure the package to your needs, by following the comments in the
+ "Build & install configuration" section in Make.config.
3. Compile the libraries and tools.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..f516608
--- /dev/null
+++ b/TODO
@@ -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 --git a/docs/DRIVER.ax206dpf b/docs/DRIVER.ax206dpf
new file mode 100644
index 0000000..7c11d97
--- /dev/null
+++ b/docs/DRIVER.ax206dpf
@@ -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_DRIVER_AX206DPF 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="<user_group>", MODE="0660"
+Replace <user_group> 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 --git a/docs/DRIVER.futabaMDM166A b/docs/DRIVER.futabaMDM166A
index 94e6179..088498f 100644
--- a/docs/DRIVER.futabaMDM166A
+++ b/docs/DRIVER.futabaMDM166A
@@ -12,7 +12,7 @@ The VFD is connected to a PC's USB port.
Installation Notes
------------------
-You need installed library libhid to use the futabaMDM166A driver.
+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/
@@ -62,7 +62,7 @@ RefreshDisplay
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.
+ A value of 0 completely disables complete refreshs.
Possible values: 0 <= x <= 50
Default value: 50
diff --git a/glcddrivers/Makefile b/glcddrivers/Makefile
index acb1577..8c2b3d6 100644
--- a/glcddrivers/Makefile
+++ b/glcddrivers/Makefile
@@ -6,8 +6,8 @@
CXXFLAGS += -fPIC
-VERMAJOR = 1
-VERMINOR = 0
+VERMAJOR = 2
+VERMINOR = 1
VERMICRO = 0
BASENAME = libglcddrivers.so
@@ -25,17 +25,52 @@ LIBS += $(shell pkg-config --libs libhid)
DEFINES += -DHAVE_LIBHID
endif
+
+ifeq ($(shell pkg-config --exists libusb && echo 1), 1)
+ DEFINES += -DHAVE_LIBUSB
+ ifdef HAVE_DRIVER_AX206DPF
+ OBJS += ax206dpf.o
+ INCLUDES += $(shell pkg-config --cflags libusb)
+ LIBS += $(shell pkg-config --libs libusb)
+ DEFINES += -DHAVE_DRIVER_AX206DPF
+ endif
+ ifdef HAVE_DRIVER_picoLCD_256x64
+ OBJS += picoLCD_256x64.o
+ INCLUDES += $(shell pkg-config --cflags libusb)
+ LIBS += $(shell pkg-config --libs libusb)
+ DEFINES += -DHAVE_DRIVER_picoLCD_256x64
+ endif
+endif
+
+ifeq ($(HAVE_DRIVER_VNCSERVER), 1)
+ifeq ($(shell libvncserver-config --version >/dev/null && echo 1), 1)
+ DEFINES += -DHAVE_DRIVER_VNCSERVER
+ OBJS += vncserver.o
+ INCLUDES += $(shell libvncserver-config --cflags)
+ LIBS += $(shell libvncserver-config --libs)
+endif
+endif
+
+ifeq ($(HAVE_DRIVER_SSD1306), 1)
+ DEFINES += -DHAVE_DRIVER_SSD1306
+ OBJS += ssd1306.o
+ LIBS += -lwiringPi
+endif
+
+ifeq ($(HAVE_DRIVER_ILI9341), 1)
+ DEFINES += -DHAVE_DRIVER_ILI9341
+ OBJS += ili9341.o
+ LIBS += -lwiringPi
+endif
+
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
-MAKEDEP = g++ -MM -MG
-DEPFILE = .dependencies
-$(DEPFILE): Makefile
- @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+DEPFILE = $(OBJS:%.o=%.d)
-include $(DEPFILE)
diff --git a/glcddrivers/avrctl.c b/glcddrivers/avrctl.c
index b0e09b9..2261d95 100644
--- a/glcddrivers/avrctl.c
+++ b/glcddrivers/avrctl.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <stdint.h>
@@ -50,10 +51,8 @@ const int kBufferHeight = 128;
cDriverAvrCtl::cDriverAvrCtl(cDriverConfig * config)
-: config(config)
+: cDriver(config)
{
- oldConfig = new cDriverConfig(*config);
-
port = new cSerialPort();
//width = config->width;
@@ -64,7 +63,6 @@ cDriverAvrCtl::cDriverAvrCtl(cDriverConfig * config)
cDriverAvrCtl::~cDriverAvrCtl()
{
delete port;
- delete oldConfig;
}
int cDriverAvrCtl::Init()
@@ -176,6 +174,27 @@ void cDriverAvrCtl::Clear()
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 @@ void cDriverAvrCtl::Set8Pixels(int x, int y, unsigned char data)
}
}
}
+#endif
void cDriverAvrCtl::Refresh(bool refreshAll)
{
diff --git a/glcddrivers/avrctl.h b/glcddrivers/avrctl.h
index 557b7d2..a7ecb42 100644
--- a/glcddrivers/avrctl.h
+++ b/glcddrivers/avrctl.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_AVRCTL_H_
@@ -26,8 +27,6 @@ private:
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 @@ public:
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 --git a/glcddrivers/ax206dpf.c b/glcddrivers/ax206dpf.c
new file mode 100644
index 0000000..acae61d
--- /dev/null
+++ b/glcddrivers/ax206dpf.c
@@ -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.siebholz AT t-online.de>
+ * (c) 2011 Dirk Heiser
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
+ *
+ * includes code from:
+ * http://sourceforge.net/projects/dpf-ax/
+ *
+ * Original copyright:
+ *
+ * Copyright (C) 2008 Jeroen Domburg <picframe@spritesmods.com>
+ * Modified from sample code by:
+ * Copyright (C) 2005 Michael Reinelt <michael@reinelt.co.at>
+ * Copyright (C) 2005, 2006, 2007 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
+ * Mods by <hackfin@section5.ch>
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2011 Lutz Neumann <superelchi AT wolke7.net>
+ *
+ * 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 <stdio.h>
+#include <syslog.h>
+#include <cstring>
+#include <algorithm>
+#include <pthread.h>
+#include <time.h>
+#include <usb.h>
+
+#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 <hackfin@section5.ch>
+ *
+ * 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 <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <sys/ioctl.h>
+
+/** 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 <hackfin@section5.ch>
+ *
+ * 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 HAVE_DEBUG
+ printf("%04x %04x\n",
+ d->descriptor.idVendor,
+ d->descriptor.idProduct);
+#endif
+ d = d->next;
+ }
+ b = b->next;
+ }
+ return NULL;
+}
+
+unsigned 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, (char*)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 --git a/glcddrivers/ax206dpf.h b/glcddrivers/ax206dpf.h
new file mode 100644
index 0000000..d683ccf
--- /dev/null
+++ b/glcddrivers/ax206dpf.h
@@ -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.siebholz AT t-online.de>
+ * (c) 2011 Dirk Heiser
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
+ *
+ * includes code from:
+ * http://sourceforge.net/projects/dpf-ax/
+ *
+ * Original copyright:
+ *
+ * Copyright (C) 2008 Jeroen Domburg <picframe@spritesmods.com>
+ * Modified from sample code by:
+ * Copyright (C) 2005 Michael Reinelt <michael@reinelt.co.at>
+ * Copyright (C) 2005, 2006, 2007 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
+ * Mods by <hackfin@section5.ch>
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2011 Lutz Neumann <superelchi AT wolke7.net>
+ *
+ */
+
+#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 <hackfin@section5.ch>
+ *
+ */
+
+// -------------------------------------------------------------------
+// START SELECTIVE COPY & PASTE "usbuser.h"
+// -------------------------------------------------------------------
+
+#include <usb.h>
+
+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, <n>: 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 --git a/glcddrivers/common.c b/glcddrivers/common.c
index 0d0fad9..40a3048 100644
--- a/glcddrivers/common.c
+++ b/glcddrivers/common.c
@@ -9,7 +9,8 @@
* This file is released under the GNU General Public License. Refer
* to the COPYING file distributed with this package.
*
- * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2012 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#include <ctype.h>
@@ -219,7 +220,7 @@ std::string trim(const std::string & s)
start++;
}
end = s.length() - 1;
- while (end >= 0)
+ while (end > start)
{
if (!isspace(s[end]))
break;
diff --git a/glcddrivers/config.c b/glcddrivers/config.c
index ef88279..15338b6 100644
--- a/glcddrivers/config.c
+++ b/glcddrivers/config.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#include <syslog.h>
@@ -214,6 +215,12 @@ bool cConfig::Load(const std::string & filename)
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 --git a/glcddrivers/config.h b/glcddrivers/config.h
index 8caa77e..1c744e8 100644
--- a/glcddrivers/config.h
+++ b/glcddrivers/config.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#ifndef _GLCDDRIVERS_CONFIG_H_
diff --git a/glcddrivers/dm140gink.c b/glcddrivers/dm140gink.c
index c7efdba..4f73c42 100644
--- a/glcddrivers/dm140gink.c
+++ b/glcddrivers/dm140gink.c
@@ -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-2013 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <fcntl.h>
@@ -30,16 +31,10 @@ namespace GLCD
{
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 @@ int cDriverDM140GINK::SendReport(const char *cbuf, size_t size)
//**************************************************************
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?
@@ -254,7 +249,7 @@ int cDriverDM140GINK::CheckSetup()
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 @@ void cDriverDM140GINK::SetPixel(int x, int y)
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 @@ void cDriverDM140GINK::Clear()
memset(framebuff, 0, screensize);
}
+#if 0
void cDriverDM140GINK::Set8Pixels(int x, int y, unsigned char data)
{
x &= 0xFFF8;
@@ -282,9 +281,10 @@ void cDriverDM140GINK::Set8Pixels(int x, int y, unsigned char data)
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 --git a/glcddrivers/dm140gink.h b/glcddrivers/dm140gink.h
index 526263a..10bfea6 100644
--- a/glcddrivers/dm140gink.h
+++ b/glcddrivers/dm140gink.h
@@ -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-2013 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_DM140GINK_H_
@@ -24,13 +25,10 @@ class cDriverConfig;
class cDriverDM140GINK : public cDriver
{
private:
- cDriverConfig * config;
- cDriverConfig * oldConfig;
-
int fd;
- int vendor;
- int product;
+ signed short vendor;
+ signed short product;
char *framebuff;
@@ -38,17 +36,16 @@ private:
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 --git a/glcddrivers/driver.c b/glcddrivers/driver.c
index b1b6286..ea13eaf 100644
--- a/glcddrivers/driver.c
+++ b/glcddrivers/driver.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#include "common.h"
#include "driver.h"
-
+#include "config.h"
namespace GLCD
{
-cDriver::cDriver()
+cTouchEvent::cTouchEvent() : 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);
+}
+
+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 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 @@ void cDriver::SetScreen(const unsigned char * data, int wid, int hgt, int lineSi
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 @@ void cDriver::SetScreen(const unsigned char * data, int wid, int hgt, int lineSi
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 --git a/glcddrivers/driver.h b/glcddrivers/driver.h
index 1d82eaa..3e28a3f 100644
--- a/glcddrivers/driver.h
+++ b/glcddrivers/driver.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#ifndef _GLCDDRIVERS_DRIVER_H_
#define _GLCDDRIVERS_DRIVER_H_
#include <stdint.h>
+#include "../glcdgraphics/bitmap.h"
+
+// for strcasecmp
+#include <strings.h>
namespace GLCD
{
+class cGLCDEvent {
+public:
+ virtual ~cGLCDEvent() {}
+};
+
+class cTouchEvent : public cGLCDEvent {
+public:
+ int x;
+ int y;
+ int touch;
+ cTouchEvent();
+};
+
+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 --git a/glcddrivers/drivers.c b/glcddrivers/drivers.c
index 946ab39..4c7e67a 100644
--- a/glcddrivers/drivers.c
+++ b/glcddrivers/drivers.c
@@ -33,6 +33,21 @@
#ifdef HAVE_LIBHID
#include "futabaMDM166A.h"
#endif
+#ifdef HAVE_DRIVER_AX206DPF
+#include "ax206dpf.h"
+#endif
+#ifdef HAVE_DRIVER_picoLCD_256x64
+#include "picoLCD_256x64.h"
+#endif
+#ifdef HAVE_DRIVER_VNCSERVER
+#include "vncserver.h"
+#endif
+#ifdef HAVE_DRIVER_SSD1306
+#include "ssd1306.h"
+#endif
+#ifdef HAVE_DRIVER_ILI9341
+#include "ili9341.h"
+#endif
namespace GLCD
{
@@ -60,6 +75,21 @@ tDriver drivers[] =
#endif
{"serdisp", kDriverSerDisp},
{"g15daemon", kDriverG15daemon},
+#ifdef HAVE_DRIVER_AX206DPF
+ {"ax206dpf", kDriverAX206DPF},
+#endif
+#ifdef HAVE_DRIVER_picoLCD_256x64
+ {"picolcd256x64", kDriverPicoLCD_256x64},
+#endif
+#ifdef HAVE_DRIVER_VNCSERVER
+ {"vncserver", kDriverVncServer},
+#endif
+#ifdef HAVE_DRIVER_SSD1306
+ {"ssd1306", kDriverSSD1306},
+#endif
+#ifdef HAVE_DRIVER_ILI9341
+ {"ili9341", kDriverILI9341},
+#endif
{"", kDriverUnknown}
};
@@ -122,6 +152,26 @@ cDriver * CreateDriver(int driverID, cDriverConfig * config)
return new cDriverSerDisp(config);
case kDriverG15daemon:
return new cDriverG15daemon(config);
+#ifdef HAVE_DRIVER_AX206DPF
+ case kDriverAX206DPF:
+ return new cDriverAX206DPF(config);
+#endif
+#ifdef HAVE_DRIVER_picoLCD_256x64
+ case kDriverPicoLCD_256x64:
+ return new cDriverPicoLCD_256x64(config);
+#endif
+#ifdef HAVE_DRIVER_VNCSERVER
+ case kDriverVncServer:
+ return new cDriverVncServer(config);
+#endif
+#ifdef HAVE_DRIVER_SSD1306
+ case kDriverSSD1306:
+ return new cDriverSSD1306(config);
+#endif
+#ifdef HAVE_DRIVER_ILI9341
+ case kDriverILI9341:
+ return new cDriverILI9341(config);
+#endif
case kDriverUnknown:
default:
return NULL;
diff --git a/glcddrivers/drivers.h b/glcddrivers/drivers.h
index b088713..970b01e 100644
--- a/glcddrivers/drivers.h
+++ b/glcddrivers/drivers.h
@@ -40,7 +40,22 @@ enum eDriver
kDriverNetwork = 14,
kDriverGU126X64D_K610A4 = 15,
kDriverDM140GINK = 16,
- kDriverFutabaMDM166A = 17,
+ kDriverFutabaMDM166A = 17,
+#ifdef HAVE_DRIVER_AX206DPF
+ kDriverAX206DPF = 18,
+#endif
+#ifdef HAVE_DRIVER_picoLCD_256x64
+ kDriverPicoLCD_256x64 = 19,
+#endif
+#ifdef HAVE_DRIVER_VNCSERVER
+ kDriverVncServer = 20,
+#endif
+#ifdef HAVE_DRIVER_SSD1306
+ kDriverSSD1306 = 21,
+#endif
+#ifdef HAVE_DRIVER_ILI9341
+ kDriverILI9341 = 22,
+#endif
kDriverSerDisp = 100,
kDriverG15daemon = 200
};
diff --git a/glcddrivers/framebuffer.c b/glcddrivers/framebuffer.c
index ef96cde..254f487 100644
--- a/glcddrivers/framebuffer.c
+++ b/glcddrivers/framebuffer.c
@@ -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 <mrwastl AT users.sourceforge.net>
*/
#include <fcntl.h>
@@ -28,20 +29,15 @@ namespace GLCD
{
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 @@ int cDriverFramebuffer::Init()
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 @@ int cDriverFramebuffer::Init()
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 @@ int cDriverFramebuffer::Init()
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 @@ int cDriverFramebuffer::CheckSetup()
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 @@ void cDriverFramebuffer::SetPixel(int x, int y)
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 @@ void cDriverFramebuffer::Set8Pixels(int x, int y, unsigned char data)
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 --git a/glcddrivers/framebuffer.h b/glcddrivers/framebuffer.h
index 79d1d77..7949ad3 100644
--- a/glcddrivers/framebuffer.h
+++ b/glcddrivers/framebuffer.h
@@ -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-2013 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_FRAMEBUFFER_H_
@@ -25,9 +26,6 @@ class cDriverConfig;
class cDriverFramebuffer : public cDriver
{
private:
- unsigned char ** LCD;
- cDriverConfig * config;
- cDriverConfig * oldConfig;
char *offbuff;
int fbfd;
struct fb_var_screeninfo vinfo;
@@ -35,19 +33,25 @@ private:
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 --git a/glcddrivers/futabaMDM166A.c b/glcddrivers/futabaMDM166A.c
index 2fc8d67..dfa74b2 100644
--- a/glcddrivers/futabaMDM166A.c
+++ b/glcddrivers/futabaMDM166A.c
@@ -1,12 +1,15 @@
/*
* GraphLCD driver library
*
- * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
-
+ * 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 <vdr07 AT deltab de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <stdlib.h>
@@ -215,26 +218,22 @@ const char *cHIDQueue::hiderror(hid_return ret) const
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 @@ void cDriverFutabaMDM166A::Clear()
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 @@ void cDriverFutabaMDM166A::SetPixel(int x, int y)
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 @@ void cDriverFutabaMDM166A::Set8Pixels(int x, int y, byte data)
SetPixel(x + n, y);
}
}
+#endif
void cDriverFutabaMDM166A::Refresh(bool refreshAll)
{
diff --git a/glcddrivers/futabaMDM166A.h b/glcddrivers/futabaMDM166A.h
index ca1783d..65323be 100644
--- a/glcddrivers/futabaMDM166A.h
+++ b/glcddrivers/futabaMDM166A.h
@@ -1,12 +1,15 @@
/*
* GraphLCD driver library
*
- * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ * 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 <vdr07 AT deltab de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_FutabaMDM166A_H_
@@ -40,8 +43,6 @@ namespace GLCD
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 @@ namespace GLCD
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 --git a/glcddrivers/g15daemon.c b/glcddrivers/g15daemon.c
index e275b38..daa0b9b 100644
--- a/glcddrivers/g15daemon.c
+++ b/glcddrivers/g15daemon.c
@@ -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 <andreas.regel AT powarman.de>
+* (c) 2011-2012 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <fcntl.h>
@@ -105,16 +107,10 @@ namespace GLCD
{
cDriverG15daemon::cDriverG15daemon(cDriverConfig * config)
-: config(config),
+: cDriver(config),
offbuff(0),
sockfd(-1)
{
- oldConfig = new cDriverConfig(*config);
-}
-
-cDriverG15daemon::~cDriverG15daemon()
-{
- delete oldConfig;
}
int cDriverG15daemon::Init()
@@ -150,8 +146,8 @@ int cDriverG15daemon::Init()
int cDriverG15daemon::DeInit()
{
- if (offbuff);
- delete[] offbuff;
+ if (offbuff)
+ delete[] offbuff;
if (-1 != sockfd)
close(sockfd);
@@ -180,7 +176,7 @@ int cDriverG15daemon::CheckSetup()
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 @@ void cDriverG15daemon::SetPixel(int x, int y)
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 @@ void cDriverG15daemon::Clear()
memset(offbuff, 0, screensize);
}
+#if 0
void cDriverG15daemon::Set8Pixels(int x, int y, unsigned char data)
{
int n;
@@ -208,9 +205,10 @@ void cDriverG15daemon::Set8Pixels(int x, int y, unsigned char data)
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 --git a/glcddrivers/g15daemon.h b/glcddrivers/g15daemon.h
index c91ef17..c7c216a 100644
--- a/glcddrivers/g15daemon.h
+++ b/glcddrivers/g15daemon.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2011-2013 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_G15DAEMON_H_
@@ -20,27 +22,21 @@ class cDriverConfig;
class cDriverG15daemon : public cDriver
{
private:
- unsigned char ** LCD;
- cDriverConfig * config;
- cDriverConfig * oldConfig;
char *offbuff;
int sockfd;
long int screensize;
- char *fbp;
- 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 --git a/glcddrivers/gu126x64D-K610A4.c b/glcddrivers/gu126x64D-K610A4.c
index 711e672..6770467 100644
--- a/glcddrivers/gu126x64D-K610A4.c
+++ b/glcddrivers/gu126x64D-K610A4.c
@@ -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 <mrwastl AT users.sourceforge.net>
*/
#include <errno.h>
@@ -90,9 +91,8 @@ static const long ADJUST_FACTOR = 100; // used to adjust timing
//-----------------------------------------------------------------------------
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 @@ cDriverGU126X64D_K610A4::cDriverGU126X64D_K610A4(cDriverConfig * config)
, 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 @@ int cDriverGU126X64D_K610A4::write(unsigned char data)
} // 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 @@ void cDriverGU126X64D_K610A4::setPixel(int x, int y)
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 @@ void cDriverGU126X64D_K610A4::Set8Pixels(int x, int y, unsigned char data)
{
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 @@ int cDriverGU126X64D_K610A4::cmdWriteText(const char *theText)
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 --git a/glcddrivers/gu126x64D-K610A4.h b/glcddrivers/gu126x64D-K610A4.h
index 3d6c29c..422705f 100644
--- a/glcddrivers/gu126x64D-K610A4.h
+++ b/glcddrivers/gu126x64D-K610A4.h
@@ -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 <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_GU126X64D_K610A4_H_
@@ -45,7 +46,6 @@ public:
// constructor/destructor
//---------------------------------------------------------------------------
cDriverGU126X64D_K610A4(cDriverConfig * config);
- virtual ~cDriverGU126X64D_K610A4();
//---------------------------------------------------------------------------
// from cDriver
@@ -54,7 +54,8 @@ public:
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 @@ public:
, FONT_FIX_BIG
};
- void setPixel (int x, int y);
int cmdReset ();
int cmdPower (bool fOn);
@@ -108,9 +108,6 @@ private:
//---------------------------------------------------------------------------
cParallelPort *port;
- cDriverConfig *config;
- cDriverConfig *oldConfig;
-
int myNumRows;
unsigned char **myDrawMem;
unsigned char **myVFDMem;
diff --git a/glcddrivers/gu140x32f.c b/glcddrivers/gu140x32f.c
index c3990a3..3cf568e 100644
--- a/glcddrivers/gu140x32f.c
+++ b/glcddrivers/gu140x32f.c
@@ -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 <vdr04 AT deltab.de>
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <errno.h>
@@ -96,12 +98,10 @@ static const std::string kWiringWindows = "Windows";
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(cDriverConfig * config)
cDriverGU140X32F::~cDriverGU140X32F()
{
delete port;
- delete oldConfig;
}
int cDriverGU140X32F::Init()
@@ -326,7 +325,7 @@ void cDriverGU140X32F::Write(unsigned char nFlags, unsigned char bData, unsigned
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 @@ void cDriverGU140X32F::SetPixel(int x, int y)
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 @@ void cDriverGU140X32F::Set8Pixels(int x, int y, unsigned char data)
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 --git a/glcddrivers/gu140x32f.h b/glcddrivers/gu140x32f.h
index c0b87f2..2a94f03 100644
--- a/glcddrivers/gu140x32f.h
+++ b/glcddrivers/gu140x32f.h
@@ -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 <vdr04 AT deltab.de>
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_GU140X32F_H_
@@ -37,9 +39,6 @@ class cDriverGU140X32F : public cDriver
cParallelPort * port;
- cDriverConfig * config;
- cDriverConfig * oldConfig;
-
int m_iSizeYb;
int m_nRefreshCounter;
unsigned char *m_pDrawMem; // the draw "memory"
@@ -51,7 +50,6 @@ class cDriverGU140X32F : public cDriver
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 @@ public:
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 --git a/glcddrivers/gu256x64-372.c b/glcddrivers/gu256x64-372.c
index 049253e..1709568 100644
--- a/glcddrivers/gu256x64-372.c
+++ b/glcddrivers/gu256x64-372.c
@@ -4,6 +4,7 @@
* gu256x64-372.c - 8-bit driver module for Noritake GU256x64-372
* VFD displays. The VFD is operating in its 8-bit
* mode connected to a single PC parallel port.
+ * Should also work for GU256x64-355 and -352.
*
* based on:
* gu256x32f driver module for graphlcd
@@ -16,7 +17,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-2012 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <errno.h>
@@ -83,10 +85,8 @@ const unsigned char kWindowsCDLO = 0x08; //
cDriverGU256X64_372::cDriverGU256X64_372(cDriverConfig * config)
-: config(config)
+: cDriver(config)
{
- oldConfig = new cDriverConfig(*config);
-
port = new cParallelPort();
m_nRefreshCounter = 0;
@@ -94,7 +94,6 @@ cDriverGU256X64_372::cDriverGU256X64_372(cDriverConfig * config)
cDriverGU256X64_372::~cDriverGU256X64_372()
{
- delete oldConfig;
delete port;
}
@@ -322,12 +321,12 @@ void cDriverGU256X64_372::GU256X64Cmd(unsigned char data)
if (m_bSleepIsInit)
nSleepInit();
- port->WriteControl(CDHI | WRHI | RDLO);
+ port->WriteControl(CDHI | WRHI);
port->WriteData(data);
nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
- port->WriteControl(CDHI | WRLO | RDLO);
+ port->WriteControl(CDHI | WRLO);
nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
- port->WriteControl(CDHI | WRHI | RDLO);
+ port->WriteControl(CDHI | WRHI);
nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
}
@@ -336,16 +335,16 @@ void cDriverGU256X64_372::GU256X64Data(unsigned char data)
if (m_bSleepIsInit)
nSleepInit();
- port->WriteControl(CDLO | WRHI | RDLO);
+ port->WriteControl(CDLO | WRHI);
port->WriteData(data);
nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
- port->WriteControl(CDLO | WRLO | RDLO);
+ port->WriteControl(CDLO | WRLO);
nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
- port->WriteControl(CDLO | WRHI | RDLO);
+ port->WriteControl(CDLO | WRHI);
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 +364,13 @@ void cDriverGU256X64_372::SetPixel(int x, int y)
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 +381,10 @@ void cDriverGU256X64_372::Set8Pixels(int x, int y, unsigned char data)
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 --git a/glcddrivers/gu256x64-372.h b/glcddrivers/gu256x64-372.h
index 7d92561..a0d511f 100644
--- a/glcddrivers/gu256x64-372.h
+++ b/glcddrivers/gu256x64-372.h
@@ -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 <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_GU256X64_372_H_
@@ -34,9 +35,6 @@ class cDriverGU256X64_372 : public cDriver
{
cParallelPort * port;
- cDriverConfig * config;
- cDriverConfig * oldConfig;
-
int m_iSizeYb;
int m_nRefreshCounter;
@@ -57,7 +55,6 @@ class cDriverGU256X64_372 : public cDriver
protected:
void ClearVFDMem();
- void SetPixel(int x, int y);
void GU256X64Cmd(unsigned char data);
void GU256X64Data(unsigned char data);
@@ -69,7 +66,8 @@ public:
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 --git a/glcddrivers/gu256x64-3900.c b/glcddrivers/gu256x64-3900.c
index d9279dc..8a2dafc 100644
--- a/glcddrivers/gu256x64-3900.c
+++ b/glcddrivers/gu256x64-3900.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2011-2012 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <errno.h>
@@ -102,19 +104,12 @@ static const int kInterfaceSerial = 1; // serial mode
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;
@@ -262,7 +257,7 @@ int cDriverGU256X64_3900::DeInit()
if (portFd >= 0)
{
close(portFd);
- portFd =- 1;
+ portFd = -1;
}
}
if (port)
@@ -503,7 +498,7 @@ void cDriverGU256X64_3900::Write(unsigned char data)
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 @@ void cDriverGU256X64_3900::SetPixel(int x, int y)
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 @@ void cDriverGU256X64_3900::Set8Pixels(int x, int y, unsigned char data)
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 --git a/glcddrivers/gu256x64-3900.h b/glcddrivers/gu256x64-3900.h
index 2201417..9703a04 100644
--- a/glcddrivers/gu256x64-3900.h
+++ b/glcddrivers/gu256x64-3900.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_GU256X64_3900_H_
@@ -39,9 +41,6 @@ class cDriverGU256X64_3900 : public cDriver
cParallelPort * port;
int portFd;
- cDriverConfig * config;
- cDriverConfig * oldConfig;
-
int m_iSizeYb;
int m_nRefreshCounter;
int interface;
@@ -59,7 +58,6 @@ class cDriverGU256X64_3900 : public cDriver
protected:
void ClearVFDMem();
- void SetPixel(int x, int y);
int InitSerialPort();
int InitParallelPort();
void InitNormalDisplay();
@@ -70,13 +68,13 @@ protected:
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 --git a/glcddrivers/hd61830.c b/glcddrivers/hd61830.c
index 7f0bd53..25f39ff 100644
--- a/glcddrivers/hd61830.c
+++ b/glcddrivers/hd61830.c
@@ -7,6 +7,8 @@
* to the COPYING file distributed with this package.
*
* (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <syslog.h>
@@ -55,10 +57,8 @@ namespace GLCD
cDriverHD61830::cDriverHD61830(cDriverConfig * config)
-: config(config)
+: cDriver(config)
{
- oldConfig = new cDriverConfig(*config);
-
port = new cParallelPort();
useSleepInit = false;
@@ -70,7 +70,6 @@ cDriverHD61830::cDriverHD61830(cDriverConfig * config)
cDriverHD61830::~cDriverHD61830()
{
delete port;
- delete oldConfig;
}
int cDriverHD61830::Init()
@@ -301,6 +300,29 @@ void cDriverHD61830::Clear()
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 @@ void cDriverHD61830::Set8Pixels(int x, int y, unsigned char data)
newLCD[x / 8][y] = newLCD[x / 8][y] | data;
}
}
+#endif
void cDriverHD61830::Refresh(bool refreshAll)
{
diff --git a/glcddrivers/hd61830.h b/glcddrivers/hd61830.h
index 50f3b26..4d70446 100644
--- a/glcddrivers/hd61830.h
+++ b/glcddrivers/hd61830.h
@@ -7,6 +7,8 @@
* to the COPYING file distributed with this package.
*
* (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_HD61830_H_
@@ -27,8 +29,6 @@ private:
unsigned char ** newLCD; // wanted state
unsigned char ** oldLCD; // current state
- cDriverConfig * config;
- cDriverConfig * oldConfig;
int refreshCounter;
long timeForPortCmdInNs;
bool useSleepInit;
@@ -45,7 +45,8 @@ public:
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 --git a/glcddrivers/ili9341.c b/glcddrivers/ili9341.c
new file mode 100644
index 0000000..54627d4
--- /dev/null
+++ b/glcddrivers/ili9341.c
@@ -0,0 +1,395 @@
+/*
+ * GraphLCD driver library
+ *
+ * ili9341.c - ILI9341 TFT driver class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2015 Andreas Regel <andreas.regel AT powarman.de>
+ */
+
+#include <stdint.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <cstring>
+
+#include <wiringPi.h>
+#include <wiringPiSPI.h>
+
+#include "common.h"
+#include "config.h"
+#include "ili9341.h"
+
+
+namespace GLCD
+{
+
+const int kLcdWidth = 320;
+const int kLcdHeight = 240;
+
+const int kSpiBus = 0;
+
+const int kGpioPwm = 13;
+const int kGpioReset = 23;
+const int kGpioDC = 24;
+
+const uint8_t kCmdNop = 0x00;
+const uint8_t kCmdSleepOut = 0x11;
+const uint8_t kCmdGammaSet = 0x26;
+const uint8_t kCmdDisplayOn = 0x29;
+const uint8_t kCmdColumnAddressSet = 0x2A;
+const uint8_t kCmdPageAddressSet = 0x2B;
+const uint8_t kCmdMemoryWrite = 0x2C;
+const uint8_t kCmdMemoryAccessControl = 0x36;
+const uint8_t kCmdPixelFormatSet = 0x3A;
+const uint8_t kCmdFrameRateControl = 0xB1;
+const uint8_t kCmdDisplayFunctionControl = 0xB6;
+
+const uint8_t kCmdPowerControl1 = 0xC0;
+const uint8_t kCmdPowerControl2 = 0xC1;
+const uint8_t kCmdVcomControl1 = 0xC5;
+const uint8_t kCmdVcomControl2 = 0xC7;
+const uint8_t kCmdPositiveGammaControl = 0xE0;
+const uint8_t kCmdNegativeGammaControl = 0xE1;
+
+const uint8_t kCmdPowerControlA = 0xCB;
+const uint8_t kCmdPowerControlB = 0xCF;
+const uint8_t kCmdDriverTimingControlA = 0xE8;
+const uint8_t kCmdDriverTimingControlB = 0xEA;
+const uint8_t kCmdPowerOnSequenceControl = 0xED;
+const uint8_t kCmdUnknownEF = 0xEF;
+const uint8_t kCmdEnable3G = 0xF2;
+const uint8_t kCmdPumpRatioControl = 0xF7;
+
+
+cDriverILI9341::cDriverILI9341(cDriverConfig * config)
+: cDriver(config)
+{
+ refreshCounter = 0;
+
+ wiringPiSetupGpio();
+}
+
+cDriverILI9341::~cDriverILI9341()
+{
+}
+
+int cDriverILI9341::Init()
+{
+ width = config->width;
+ if (width <= 0)
+ width = kLcdWidth;
+ height = config->height;
+ if (height <= 0)
+ height = kLcdHeight;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "")
+ {
+ }
+ }
+
+ // setup lcd array (wanted state)
+ newLCD = new uint32_t[width * height];
+ if (newLCD)
+ {
+ memset(newLCD, 0, width * height * sizeof(uint32_t));
+ }
+ // setup lcd array (current state)
+ oldLCD = new uint32_t[width * height];
+ if (oldLCD)
+ {
+ memset(oldLCD, 0, width * height * sizeof(uint32_t));
+ }
+
+ if (config->device == "")
+ {
+ return -1;
+ }
+
+ pinMode(kGpioReset, OUTPUT);
+ pinMode(kGpioDC, OUTPUT);
+
+ pinMode(kGpioPwm, PWM_OUTPUT);
+ SetBrightness(config->brightness);
+
+ digitalWrite(kGpioReset, HIGH);
+ digitalWrite(kGpioDC, LOW);
+
+ wiringPiSPISetup(kSpiBus, 64000000);
+
+ /* reset display */
+ Reset();
+
+ WriteCommand(kCmdUnknownEF);
+ WriteData(0x03);
+ WriteData(0x80);
+ WriteData(0x02);
+ WriteCommand(kCmdPowerControlB);
+ WriteData(0x00);
+ WriteData(0xC1);
+ WriteData(0x30);
+ WriteCommand(kCmdPowerOnSequenceControl);
+ WriteData(0x64);
+ WriteData(0x03);
+ WriteData(0x12);
+ WriteData(0x81);
+ WriteCommand(kCmdDriverTimingControlA);
+ WriteData(0x85);
+ WriteData(0x00);
+ WriteData(0x78);
+ WriteCommand(kCmdPowerControlA);
+ WriteData(0x39);
+ WriteData(0x2C);
+ WriteData(0x00);
+ WriteData(0x34);
+ WriteData(0x02);
+ WriteCommand(kCmdPumpRatioControl);
+ WriteData(0x20);
+ WriteCommand(kCmdDriverTimingControlB);
+ WriteData(0x00);
+ WriteData(0x00);
+
+ WriteCommand(kCmdPowerControl1);
+ WriteData(0x23);
+ WriteCommand(kCmdPowerControl2);
+ WriteData(0x10);
+ WriteCommand(kCmdVcomControl1);
+ WriteData(0x3e);
+ WriteData(0x28);
+ WriteCommand(kCmdVcomControl2);
+ WriteData(0x86);
+ WriteCommand(kCmdMemoryAccessControl);
+ WriteData(0x48);
+ WriteCommand(kCmdPixelFormatSet);
+ WriteData(0x55);
+ WriteCommand(kCmdFrameRateControl);
+ WriteData(0x00);
+ WriteData(0x18);
+ WriteCommand(kCmdDisplayFunctionControl);
+ WriteData(0x08);
+ WriteData(0x82);
+ WriteData(0x27);
+ WriteCommand(kCmdEnable3G);
+ WriteData(0x00);
+ WriteCommand(kCmdGammaSet);
+ WriteData(0x01);
+ WriteCommand(kCmdPositiveGammaControl);
+ WriteData(0x0F);
+ WriteData(0x31);
+ WriteData(0x2B);
+ WriteData(0x0C);
+ WriteData(0x0E);
+ WriteData(0x08);
+ WriteData(0x4E);
+ WriteData(0xF1);
+ WriteData(0x37);
+ WriteData(0x07);
+ WriteData(0x10);
+ WriteData(0x03);
+ WriteData(0x0E);
+ WriteData(0x09);
+ WriteData(0x00);
+ WriteCommand(kCmdNegativeGammaControl);
+ WriteData(0x00);
+ WriteData(0x0E);
+ WriteData(0x14);
+ WriteData(0x03);
+ WriteData(0x11);
+ WriteData(0x07);
+ WriteData(0x31);
+ WriteData(0xC1);
+ WriteData(0x48);
+ WriteData(0x08);
+ WriteData(0x0F);
+ WriteData(0x0C);
+ WriteData(0x31);
+ WriteData(0x36);
+ WriteData(0x0F);
+ WriteCommand(kCmdSleepOut);
+ usleep(120000);
+ WriteCommand(kCmdDisplayOn);
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ syslog(LOG_INFO, "%s: ILI9341 initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverILI9341::DeInit()
+{
+ // free lcd array (wanted state)
+ if (newLCD)
+ {
+ delete[] newLCD;
+ }
+ // free lcd array (current state)
+ if (oldLCD)
+ {
+ delete[] oldLCD;
+ }
+
+ return 0;
+}
+
+int cDriverILI9341::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->width != oldConfig->width ||
+ config->height != oldConfig->height)
+ {
+ DeInit();
+ Init();
+ return 0;
+ }
+
+ if (config->upsideDown != oldConfig->upsideDown)
+ {
+ oldConfig->upsideDown = config->upsideDown;
+ return 1;
+ }
+ return 0;
+}
+
+void cDriverILI9341::Clear()
+{
+ memset(newLCD, 0, width * height * sizeof(uint32_t));
+}
+
+
+void cDriverILI9341::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;
+ }
+
+ newLCD[y * width + x] = data;
+}
+
+
+void cDriverILI9341::Refresh(bool refreshAll)
+{
+ int y;
+
+ if (CheckSetup() == 1)
+ refreshAll = true;
+
+ if (config->refreshDisplay > 0)
+ {
+ refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !refreshCounter)
+ refreshAll = true;
+ }
+
+ refreshAll = true;
+ if (refreshAll)
+ {
+ SetWindow(0, 0, height - 1, width - 1);
+ WriteCommand(kCmdMemoryWrite);
+ for (y = 0; y < width; y++)
+ {
+ uint8_t line[height * 2];
+ uint32_t * pixel = &newLCD[width - 1 - y];
+
+ for (int x = 0; x < (height * 2); x += 2)
+ {
+ line[x] = ((*pixel & 0x00F80000) >> 16)
+ | ((*pixel & 0x0000E000) >> 13);
+ line[x + 1] = ((*pixel & 0x00001C00) >> 5)
+ | ((*pixel & 0x000000F8) >> 3);
+ pixel += width;
+ }
+ WriteData((uint8_t *) line, height * 2);
+ }
+ memcpy(oldLCD, newLCD, width * height * sizeof(uint32_t));
+ // and reset RefreshCounter
+ refreshCounter = 0;
+ }
+ else
+ {
+ // draw only the changed bytes
+ }
+}
+
+void cDriverILI9341::SetBrightness(unsigned int percent)
+{
+ uint32_t value;
+
+ if (percent == 0)
+ value = 0;
+ else if (percent <= 10)
+ value = 4;
+ else if (percent <= 20)
+ value = 8;
+ else if (percent <= 30)
+ value = 16;
+ else if (percent <= 40)
+ value = 32;
+ else if (percent <= 50)
+ value = 64;
+ else if (percent <= 60)
+ value = 128;
+ else if (percent <= 70)
+ value = 192;
+ else if (percent <= 80)
+ value = 320;
+ else if (percent <= 90)
+ value = 512;
+ else
+ value = 1023;
+
+ pwmWrite(kGpioPwm, value);
+}
+
+void cDriverILI9341::Reset()
+{
+ digitalWrite(kGpioReset, HIGH);
+ usleep(10000);
+ digitalWrite(kGpioReset, LOW);
+ usleep(20000);
+ digitalWrite(kGpioReset, HIGH);
+ usleep(150000);
+}
+
+void cDriverILI9341::SetWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
+{
+ WriteCommand(kCmdColumnAddressSet);
+ WriteData(x0 >> 8);
+ WriteData(x0);
+ WriteData(x1 >> 8);
+ WriteData(x1);
+ WriteCommand(kCmdPageAddressSet);
+ WriteData(y0 >> 8);
+ WriteData(y0);
+ WriteData(y1 >> 8);
+ WriteData(y1);
+}
+
+void cDriverILI9341::WriteCommand(uint8_t command)
+{
+ digitalWrite(kGpioDC, LOW);
+ wiringPiSPIDataRW(kSpiBus, &command, 1);
+ digitalWrite(kGpioDC, HIGH);
+}
+
+void cDriverILI9341::WriteData(uint8_t data)
+{
+ wiringPiSPIDataRW(kSpiBus, &data, 1);
+}
+
+void cDriverILI9341::WriteData(uint8_t * buffer, uint32_t length)
+{
+ wiringPiSPIDataRW(kSpiBus, buffer, length);
+}
+
+} // end of namespace
diff --git a/glcddrivers/ili9341.h b/glcddrivers/ili9341.h
new file mode 100644
index 0000000..d729971
--- /dev/null
+++ b/glcddrivers/ili9341.h
@@ -0,0 +1,53 @@
+/*
+ * GraphLCD driver library
+ *
+ * ili9341.h - ILI9341 OLED driver class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2015 Andreas Regel <andreas.regel AT powarman.de>
+ */
+
+#ifndef _GLCDDRIVERS_ILI9341_H_
+#define _GLCDDRIVERS_ILI9341_H_
+
+#include "driver.h"
+
+namespace GLCD
+{
+
+class cDriverConfig;
+
+class cDriverILI9341 : public cDriver
+{
+private:
+ uint32_t * newLCD; // wanted state
+ uint32_t * oldLCD; // current state
+ int refreshCounter;
+
+ int CheckSetup();
+
+ void Reset();
+ void SetWindow(uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1);
+ void WriteCommand(uint8_t command);
+ void WriteData(uint8_t data);
+ void WriteData(uint8_t * buffer, uint32_t length);
+
+public:
+ cDriverILI9341(cDriverConfig * config);
+ virtual ~cDriverILI9341();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ 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);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/image.c b/glcddrivers/image.c
index a07ce54..a3d123f 100644
--- a/glcddrivers/image.c
+++ b/glcddrivers/image.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ Andreas 'randy' Weinberger
*/
#include <stdio.h>
@@ -23,15 +25,13 @@ namespace GLCD
{
cDriverImage::cDriverImage(cDriverConfig * config)
-: config(config)
+: cDriver(config)
{
- oldConfig = new cDriverConfig(*config);
}
cDriverImage::~cDriverImage()
{
DeInit();
- delete oldConfig;
}
int cDriverImage::Init()
@@ -51,12 +51,13 @@ int cDriverImage::Init()
}
}
- 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;
@@ -109,6 +110,7 @@ void cDriverImage::Clear()
memset(newLCD, 0, lineSize * height);
}
+#if 0
void cDriverImage::Set8Pixels(int x, int y, unsigned char data)
{
if (x >= width || y >= height)
@@ -127,6 +129,28 @@ void cDriverImage::Set8Pixels(int x, int y, unsigned char data)
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 --git a/glcddrivers/image.h b/glcddrivers/image.h
index 3e39e3f..2d3cb71 100644
--- a/glcddrivers/image.h
+++ b/glcddrivers/image.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ Andreas 'randy' Weinberger
*/
#ifndef _GLCDDRIVERS_IMAGE_H_
@@ -24,10 +26,8 @@ class cDriverConfig;
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 @@ public:
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 --git a/glcddrivers/ks0108.c b/glcddrivers/ks0108.c
index de9c505..042f286 100644
--- a/glcddrivers/ks0108.c
+++ b/glcddrivers/ks0108.c
@@ -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 <vdr AT smue.org>
+ * (c) 2003-2011 Andreas 'randy' Weinberger <vdr AT smue.org>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <syslog.h>
@@ -41,10 +42,8 @@ const unsigned char kCS2LO = 0x04;
cDriverKS0108::cDriverKS0108(cDriverConfig * config)
-: config(config)
+: cDriver(config)
{
- oldConfig = new cDriverConfig(*config);
-
port = new cParallelPort();
refreshCounter = 0;
@@ -55,7 +54,6 @@ cDriverKS0108::cDriverKS0108(cDriverConfig * config)
cDriverKS0108::~cDriverKS0108()
{
delete port;
- delete oldConfig;
}
int cDriverKS0108::Init()
@@ -420,6 +418,29 @@ void cDriverKS0108::Clear()
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 @@ void cDriverKS0108::Set8Pixels(int x, int y, unsigned char data)
LCD[x / 8][y] = LCD[x / 8][y] | ReverseBits(data);
}
}
+#endif
void cDriverKS0108::Refresh(bool refreshAll)
{
diff --git a/glcddrivers/ks0108.h b/glcddrivers/ks0108.h
index 66ac425..d9016c0 100644
--- a/glcddrivers/ks0108.h
+++ b/glcddrivers/ks0108.h
@@ -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 <vdr AT smue.org>
+ * (c) 2003-2011 Andreas 'randy' Weinberger <vdr AT smue.org>
+ * (c) 2011-2013 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_KS0108_H_
@@ -30,8 +31,6 @@ private:
int refreshCounter;
long timeForPortCmdInNs;
long timeForLCDInNs;
- cDriverConfig * config;
- cDriverConfig * oldConfig;
bool useSleepInit;
int CheckSetup();
@@ -49,10 +48,6 @@ private:
int CELO;
int CDHI;
int CDLO;
- int CS1HI;
- int CS1LO;
- int CS2HI;
- int CS2LO;
int CS1;
int CS2;
@@ -69,7 +64,8 @@ public:
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 --git a/glcddrivers/network.c b/glcddrivers/network.c
index 485f8ea..5000fda 100644
--- a/glcddrivers/network.c
+++ b/glcddrivers/network.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <stdio.h>
@@ -29,19 +30,13 @@ namespace GLCD
{
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 @@ void cDriverNetwork::Clear()
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 @@ void cDriverNetwork::Set8Pixels(int x, int y, unsigned char data)
newLCD[lineSize * y + x / 8] |= ReverseBits(data);
}
}
+#endif
void cDriverNetwork::Refresh(bool refreshAll)
{
diff --git a/glcddrivers/network.h b/glcddrivers/network.h
index 4664f4c..9251c50 100644
--- a/glcddrivers/network.h
+++ b/glcddrivers/network.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_NETWORK_H_
@@ -28,8 +29,6 @@ class cDriverNetwork : public cDriver
private:
unsigned char * newLCD;
unsigned char * oldLCD;
- cDriverConfig * config;
- cDriverConfig * oldConfig;
int lineSize;
bool running;
pthread_t childTid;
@@ -41,13 +40,13 @@ private:
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 --git a/glcddrivers/noritake800.c b/glcddrivers/noritake800.c
index 89ae898..05eed6e 100644
--- a/glcddrivers/noritake800.c
+++ b/glcddrivers/noritake800.c
@@ -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 - 2011 Lucian Muresan <lucianm AT users.sourceforge.net>
+ * (c) 2004-2011 Lucian Muresan <lucianm AT users.sourceforge.net>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <errno.h>
@@ -89,7 +91,7 @@ static const std::string kWiringMZ = "MZ";
#define SETPOSITION 0xff
-cDriverNoritake800::cDriverNoritake800(cDriverConfig * config)
+cDriverNoritake800::cDriverNoritake800(cDriverConfig * config) : cDriver(config)
{
int x = 0;
m_bGraphScreen0_On = true;
@@ -97,18 +99,15 @@ cDriverNoritake800::cDriverNoritake800(cDriverConfig * config)
// 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 @@ cDriverNoritake800::cDriverNoritake800(cDriverConfig * config)
//
// 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;
}
@@ -182,7 +181,6 @@ cDriverNoritake800::~cDriverNoritake800()
}
delete[] m_pDrawMem;
delete[] m_pWiringMaskCache;
- delete m_oldConfig;
delete m_pport;
}
@@ -211,27 +209,27 @@ int cDriverNoritake800::DeInit()
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,31 @@ int cDriverNoritake800::Init()
int x;
struct timeval tv1, tv2;
- if (m_Config->device == "")
+ if (config->device == "" && m_pport->IsDirectIO())
{
// use DirectIO
- if (m_pport->Open(m_Config->port) != 0)
+ syslog(LOG_INFO, "INFO (cDriverNoritake800::Init): using Direct IO port access\n");
+ if (m_pport->Open(config->port) != 0)
+ {
+ syslog(LOG_ERR, "ERROR (cDriverNoritake800::Init): cannot open configured port %x, Err: %s\n", config->port, strerror(errno));
return -1;
+ }
uSleep(10);
}
else
{
// use ppdev
- if (m_pport->Open(m_Config->device.c_str()) != 0)
+ syslog(LOG_INFO, "INFO (cDriverNoritake800::Init): using PPDEV port access\n");
+ if (m_pport->Open(config->device.c_str()) != 0)
+ {
+ syslog(LOG_ERR, "ERROR (cDriverNoritake800::Init): cannot open configured device %s, Err: %s\n", config->device.c_str(), strerror(errno));
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_INFO, "INFO (cDriverNoritake800::Init): cannot change wait parameters Err: %s\n", strerror(errno));
m_bSleepIsInit = false;
}
else
@@ -266,9 +272,14 @@ int cDriverNoritake800::Init()
m_bSleepIsInit = true;
}
+ // claim port if not already done
+ if (!m_pport->Claim())
+ {
+ syslog(LOG_ERR, "ERROR (cDriverNoritake800::Init): cannot claim port Err: %s\n", strerror(errno));
+ return -1;
+ }
// 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 nBenchIterations = 10000;
for (x = 0; x < nBenchIterations; x++)
@@ -279,7 +290,8 @@ int cDriverNoritake800::Init()
nSleepDeInit();
// 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", m_Config->name.c_str(), m_nTimingAdjustCmd);
+ syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), m_nTimingAdjustCmd);
+
m_pport->Release();
// initialize display
@@ -289,13 +301,13 @@ int cDriverNoritake800::Init()
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
@@ -311,15 +323,15 @@ int cDriverNoritake800::Init()
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, "INFO (cDriverNoritake800::Init): initialization done.\n");
return 0;
}
@@ -333,14 +345,19 @@ void cDriverNoritake800::Refresh(bool refreshAll)
if (!m_pVFDMem || !m_pDrawMem)
return;
- if (m_Config->refreshDisplay > 0)
+ if (config->refreshDisplay > 0)
{
- m_nRefreshCounter = (m_nRefreshCounter + 1) % m_Config->refreshDisplay;
+ m_nRefreshCounter = (m_nRefreshCounter + 1) % config->refreshDisplay;
if (m_nRefreshCounter == 0)
refreshAll = true;
}
- m_pport->Claim();
+ if (!m_pport->Claim())
+ {
+ syslog(LOG_ERR, "ERROR (cDriverNoritake800::Refresh): cannot claim port Err: %s\n", strerror(errno));
+ return;
+ }
+
for (xb = 0; xb < width; ++xb)
{
for (yb = 0; yb < m_iSizeYb; ++yb)
@@ -355,57 +372,74 @@ void cDriverNoritake800::Refresh(bool 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);
}
}
}
+
m_pport->Release();
}
void cDriverNoritake800::N800Cmd(unsigned char data)
{
+ if (!m_pport->Claim())
+ {
+ syslog(LOG_ERR, "ERROR (cDriverNoritake800::N800Cmd): cannot claim port Err: %s\n", strerror(errno));
+ return;
+ }
+
if (m_bSleepIsInit)
nSleepInit();
// set direction to "port_output" & C/D to C
- m_pport->WriteControl(m_pWiringMaskCache[0x00]);
+ m_pport->SetDirection(kForward);
// 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]);
+ m_pport->SetDirection(kReverse);
+
+ m_pport->Release();
}
void cDriverNoritake800::N800Data(unsigned char data)
{
+ if (!m_pport->Claim())
+ {
+ syslog(LOG_ERR, "ERROR (cDriverNoritake800::N800Data): cannot claim port Err: %s\n", strerror(errno));
+ return;
+ }
+
if (m_bSleepIsInit)
nSleepInit();
// set direction to "port_output" & C/D to C
- m_pport->WriteControl(m_pWiringMaskCache[VFDSGN_CD]);
+ m_pport->SetDirection(kForward);
// 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]);
+ m_pport->SetDirection(kReverse);
+
+ m_pport->Release();
}
-void cDriverNoritake800::SetPixel(int x, int y)
+void cDriverNoritake800::SetPixel(int x, int y, uint32_t data)
{
unsigned char c;
@@ -417,7 +451,7 @@ void cDriverNoritake800::SetPixel(int x, int y)
if (y >= height || y < 0)
return;
- if (m_Config->upsideDown)
+ if (config->upsideDown)
{
x = width - 1 - x;
y = height - 1 - y;
@@ -425,9 +459,13 @@ void cDriverNoritake800::SetPixel(int x, int y)
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;
@@ -441,9 +479,16 @@ void cDriverNoritake800::Set8Pixels(int x, int y, unsigned char data)
SetPixel(x + n, y);
}
}
+#endif
void cDriverNoritake800::SetBrightness(unsigned int percent)
{
+ if (!m_pport->Claim())
+ {
+ syslog(LOG_ERR, "ERROR (cDriverNoritake800::SetBrightness): cannot claim port Err: %s\n", strerror(errno));
+ return;
+ }
+
// display can do 16 brightness levels,
// 0 = light
// 15 = dark
@@ -455,8 +500,8 @@ void cDriverNoritake800::SetBrightness(unsigned int percent)
}
unsigned int darkness = 16 - (unsigned int)((double)percent * 16.0 / 100.0);
- m_pport->Claim();
N800Cmd(0x40 + (darkness & 0xf));
+
m_pport->Release();
}
diff --git a/glcddrivers/noritake800.h b/glcddrivers/noritake800.h
index f34c476..5d72974 100644
--- a/glcddrivers/noritake800.h
+++ b/glcddrivers/noritake800.h
@@ -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 - 2011 Lucian Muresan <lucianm AT users.sourceforge.net>
+ * (c) 2004-2011 Lucian Muresan <lucianm AT users.sourceforge.net>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_NORITAKE800_H_
@@ -43,11 +45,9 @@ class cParallelPort;
class cDriverNoritake800 : public cDriver
{
+private:
cParallelPort * m_pport;
- cDriverConfig * m_Config;
- cDriverConfig * m_oldConfig;
-
int m_iSizeYb;
int m_nRefreshCounter;
int m_nWiring;
@@ -80,8 +80,8 @@ public:
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 --git a/glcddrivers/picoLCD_256x64.c b/glcddrivers/picoLCD_256x64.c
new file mode 100644
index 0000000..8cef04d
--- /dev/null
+++ b/glcddrivers/picoLCD_256x64.c
@@ -0,0 +1,553 @@
+/*
+ * GraphLCD driver library
+ *
+ * PicoLCD_256x64.c - picoLCD Graphic 256x64
+ * Output goes to a picoLCD Graphic 256x64 LCD
+ *
+ * Driver is based on lcd4linux driver by Nicu Pavel, Mini-Box.com <npavel@mini-box.com>
+ *
+ * This file is released under the GNU General Public License.
+ *
+ * See the files README and COPYING for details.
+ *
+ * 2012 by Jochen Koch <linuxfan1992 AT web de>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <stdint.h>
+
+
+#include <stdio.h>
+#include <syslog.h>
+#include <cstring>
+
+#include "common.h"
+#include "config.h"
+#include "picoLCD_256x64.h"
+
+namespace GLCD {
+
+cDriverPicoLCD_256x64::cDriverPicoLCD_256x64(cDriverConfig * config)
+: cDriver(config)
+, pLG_framebuffer(0)
+{
+ dirty = 1;
+ inverted = 0;
+ gpo = 0;
+ read_timeout = 0;
+}
+
+int cDriverPicoLCD_256x64::Init()
+{
+ DEBUG("picoLCD Graphic initialization");
+
+ // default values
+ width = config->width;
+ if (width <= 0 || width > SCREEN_W)
+ width = SCREEN_W;
+ height = config->height;
+ if (height <= 0 || height > SCREEN_H)
+ height = SCREEN_H;
+
+ *oldConfig = *config;
+
+ if (drv_pLG_open() < 0) {
+ return -1;
+ }
+
+ /* Init framebuffer buffer */
+ pLG_framebuffer = (unsigned char *)malloc(SCREEN_W * SCREEN_H / 8 * sizeof(unsigned char));
+ if (!pLG_framebuffer)
+ {
+ INFO("picoLCD_256x64: frame buffer could not be allocated: malloc() failed");
+ return -1;
+ }
+
+ /* clear display */
+ Clear();
+ drv_pLG_clear();
+ DEBUG("zeroed");
+
+ // inverted display
+ inverted = (config->invert ? 0xff : 0);
+ // Set Display SetBrightness
+ SetBacklight(config->backlight);
+ // Set Display SetContrast
+ SetContrast(config->contrast);
+
+ return 0;
+}
+
+
+int cDriverPicoLCD_256x64::DeInit()
+{
+
+ DEBUG("picoLCD_256x64: shutting down.");
+
+ /* clear display */
+ Clear();
+ drv_pLG_clear();
+ drv_pLG_close();
+
+ if (pLG_framebuffer) {
+ free(pLG_framebuffer);
+ pLG_framebuffer = NULL;
+ }
+ return 0;
+}
+
+
+int cDriverPicoLCD_256x64::CheckSetup()
+{
+ if (config->width != oldConfig->width ||
+ config->height != oldConfig->height)
+ {
+ DeInit();
+ return Init();
+ }
+
+ if (config->backlight != oldConfig->backlight)
+ {
+ oldConfig->backlight = config->backlight;
+ SetBacklight(config->backlight);
+ }
+
+ if (config->contrast != oldConfig->contrast)
+ {
+ oldConfig->contrast = config->contrast;
+ SetContrast(config->contrast);
+ }
+
+ if (config->upsideDown != oldConfig->upsideDown ||
+ config->invert != oldConfig->invert)
+ {
+ oldConfig->upsideDown = config->upsideDown;
+ oldConfig->invert = config->invert;
+ inverted = (config->invert ? 0xff : 0);
+ return 1;
+ }
+ return 0;
+}
+
+
+void cDriverPicoLCD_256x64::Clear()
+{
+ for (unsigned int n = 0; pLG_framebuffer && n < (SCREEN_W * SCREEN_H / 8); n++)
+ pLG_framebuffer[n] = 0x00;
+}
+
+
+void cDriverPicoLCD_256x64::SetPixel(int x, int y, uint32_t data)
+{
+ unsigned char c;
+ int n;
+
+ if (!pLG_framebuffer)
+ return;
+
+ if (x >= width || x < 0)
+ return;
+ if (y >= height || y < 0)
+ return;
+
+ if (config->upsideDown)
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ }
+
+ n = x + ((y / 8) * SCREEN_W);
+ c = 0x01 << (y % 8);
+
+ if (data == GRAPHLCD_White)
+ pLG_framebuffer[n] |= c;
+ else
+ pLG_framebuffer[n] &= (0xFF ^ c);
+
+ /* display needs to be redrawn from frame buffer */
+ dirty = 1;
+}
+
+
+void cDriverPicoLCD_256x64::Refresh(bool refreshAll)
+{
+ unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA }; /* send command + data */
+ unsigned char cmd4[64] = { OUT_REPORT_DATA }; /* send data only */
+
+ int index, x, s;
+ unsigned char cs, line;
+
+ if (!pLG_framebuffer)
+ return;
+
+ s = CheckSetup();
+ if ((s > 0) || dirty)
+ refreshAll = true;
+
+ /* do not redraw display if frame buffer has not changed */
+ if (!refreshAll) {
+ DEBUG("Skipping");
+ return;
+ }
+ DEBUG("entered");
+
+ for (cs = 0; cs < 4; cs++)
+ {
+ unsigned char chipsel = (cs << 2); //chipselect
+ for (line = 0; line < 8; line++)
+ {
+ //ha64_1.setHIDPkt(OUT_REPORT_CMD_DATA, 8+3+32, 8, chipsel, 0x02, 0x00, 0x00, 0xb8|j, 0x00, 0x00, 0x40);
+ cmd3[0] = OUT_REPORT_CMD_DATA;
+ cmd3[1] = chipsel;
+ cmd3[2] = 0x02;
+ cmd3[3] = 0x00;
+ cmd3[4] = 0x00;
+ cmd3[5] = 0xb8 | line;
+ cmd3[6] = 0x00;
+ cmd3[7] = 0x00;
+ cmd3[8] = 0x40;
+ cmd3[9] = 0x00;
+ cmd3[10] = 0x00;
+ cmd3[11] = 32;
+
+ //ha64_2.setHIDPkt(OUT_REPORT_DATA, 4+32, 4, chipsel | 0x01, 0x00, 0x00, 32);
+ cmd4[0] = OUT_REPORT_DATA;
+ cmd4[1] = chipsel | 0x01;
+ cmd4[2] = 0x00;
+ cmd4[3] = 0x00;
+ cmd4[4] = 32;
+
+ for (index = 0; index < 32; index++)
+ {
+ x=64*cs+index;
+ cmd3[12 + index] = pLG_framebuffer[line * SCREEN_W + x] ^ inverted;
+ }
+ for (index = 32; index < 64; index++)
+ {
+ x=64*cs+index;
+ cmd4[5 + (index - 32)] = pLG_framebuffer[line * SCREEN_W + x] ^ inverted;
+ }
+ drv_pLG_send(cmd3, 44);
+ drv_pLG_send(cmd4, 38);
+ }
+ }
+ /* mark display as up-to-date */
+ dirty = 0;
+}
+
+
+/*
+ * Sets the backlight brightness of the display.
+ *
+ */
+void cDriverPicoLCD_256x64::SetBacklight(unsigned int onoff)
+{
+ unsigned char cmd[2] = { 0x91 }; /* set backlight */
+
+ cmd[1] = (onoff>0 ? 0xff : 0);
+ drv_pLG_send(cmd, 2);
+}
+
+
+void cDriverPicoLCD_256x64::SetContrast(unsigned int val)
+{
+ unsigned char cmd[2] = { 0x92 }; /* set contrast */
+
+ if (val > 10)
+ val = 10;
+
+ cmd[1] = 0x99+val*(0xff-0x99)/10;
+ drv_pLG_send(cmd, 2);
+}
+
+/****************************************/
+/*** hardware dependant functions ***/
+/****************************************/
+
+int cDriverPicoLCD_256x64::drv_pLG_open(void)
+{
+ struct usb_bus *busses, *bus;
+ struct usb_device *dev;
+ char driver[1024];
+ char product[1024];
+ char manufacturer[1024];
+ char serialnumber[1024];
+ int ret;
+
+ lcd = NULL;
+
+ INFO("scanning for picoLCD 256x64...");
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ busses = usb_get_busses();
+
+ for (bus = busses; bus; bus = bus->next) {
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if ((dev->descriptor.idVendor == picoLCD_VENDOR) && (dev->descriptor.idProduct == picoLCD_DEVICE)) {
+
+ DEBUG1("found picoLCD on bus %s device %s", bus->dirname, dev->filename);
+
+ lcd = usb_open(dev);
+
+ ret = usb_get_driver_np(lcd, 0, driver, sizeof(driver));
+
+ if (ret == 0) {
+ DEBUG1("interface 0 already claimed by '%s'", driver);
+ DEBUG(" attempting to detach driver...");
+ if (usb_detach_kernel_driver_np(lcd, 0) < 0) {
+ DEBUG("usb_detach_kernel_driver_np() failed!");
+ return -1;
+ }
+ }
+
+ usb_set_configuration(lcd, 1);
+ usleep(100);
+
+ if (usb_claim_interface(lcd, 0) < 0) {
+ DEBUG("picoLCD_256x64: usb_claim_interface() failed!");
+ return -1;
+ }
+
+ usb_set_altinterface(lcd, 0);
+
+ usb_get_string_simple(lcd, dev->descriptor.iProduct, product, sizeof(product));
+ usb_get_string_simple(lcd, dev->descriptor.iManufacturer, manufacturer, sizeof(manufacturer));
+ usb_get_string_simple(lcd, dev->descriptor.iSerialNumber, serialnumber, sizeof(serialnumber));
+
+ INFO1("Manufacturer='%s' Product='%s' SerialNumber='%s\n'", manufacturer, product, serialnumber);
+
+ return 0;
+ }
+ }
+ }
+ INFO("could not find a picoLCD");
+ return -1;
+}
+
+
+int cDriverPicoLCD_256x64::drv_pLG_read(unsigned char *data, int size)
+{
+ return usb_interrupt_read(lcd, USB_ENDPOINT_IN + 1, (char *) data, size, read_timeout);
+}
+
+
+void cDriverPicoLCD_256x64::drv_pLG_send(unsigned char *data, int size)
+{
+ int __attribute__ ((unused)) ret;
+ ret = usb_interrupt_write(lcd, USB_ENDPOINT_OUT + 1, (char *) data, size, 1000);
+}
+
+
+int cDriverPicoLCD_256x64::drv_pLG_close(void)
+{
+ usb_release_interface(lcd, 0);
+ usb_close(lcd);
+
+ return 0;
+}
+
+
+void cDriverPicoLCD_256x64::drv_pLG_clear(void)
+{
+ unsigned char cmd[3] = { 0x93, 0x01, 0x00 }; /* init display */
+ unsigned char cmd2[9] = { OUT_REPORT_CMD }; /* init display */
+ unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA }; /* clear screen */
+ unsigned char cmd4[64] = { OUT_REPORT_CMD_DATA }; /* clear screen */
+
+ int init, index;
+ unsigned char cs, line;
+
+
+ DEBUG("entering\n");
+ drv_pLG_send(cmd, 3);
+
+ for (init = 0; init < 4; init++) {
+ unsigned char cs = ((init << 2) & 0xFF);
+
+ cmd2[0] = OUT_REPORT_CMD;
+ cmd2[1] = cs;
+ cmd2[2] = 0x02;
+ cmd2[3] = 0x00;
+ cmd2[4] = 0x64;
+ cmd2[5] = 0x3F;
+ cmd2[6] = 0x00;
+ cmd2[7] = 0x64;
+ cmd2[8] = 0xC0;
+
+ drv_pLG_send(cmd2, 9);
+ }
+
+ for (cs = 0; cs < 4; cs++) {
+ unsigned char chipsel = (cs << 2); //chipselect
+ for (line = 0; line < 8; line++) {
+ //ha64_1.setHIDPkt(OUT_REPORT_CMD_DATA, 8+3+32, 8, cs, 0x02, 0x00, 0x00, 0xb8|j, 0x00, 0x00, 0x40);
+ cmd3[0] = OUT_REPORT_CMD_DATA;
+ cmd3[1] = chipsel;
+ cmd3[2] = 0x02;
+ cmd3[3] = 0x00;
+ cmd3[4] = 0x00;
+ cmd3[5] = 0xb8 | line;
+ cmd3[6] = 0x00;
+ cmd3[7] = 0x00;
+ cmd3[8] = 0x40;
+ cmd3[9] = 0x00;
+ cmd3[10] = 0x00;
+ cmd3[11] = 32;
+
+ unsigned char temp = 0;
+
+ for (index = 0; index < 32; index++) {
+ cmd3[12 + index] = temp;
+ }
+
+ drv_pLG_send(cmd3, 64);
+
+ //ha64_2.setHIDPkt(OUT_REPORT_DATA, 4+32, 4, cs | 0x01, 0x00, 0x00, 32);
+
+ cmd4[0] = OUT_REPORT_DATA;
+ cmd4[1] = chipsel | 0x01;
+ cmd4[2] = 0x00;
+ cmd4[3] = 0x00;
+ cmd4[4] = 32;
+
+ for (index = 32; index < 64; index++) {
+ temp = 0x00;
+ cmd4[5 + (index - 32)] = temp;
+ }
+ drv_pLG_send(cmd4, 64);
+ }
+ }
+}
+
+#ifdef ENABLE_GPIO_KEYPAD
+/**************************************\
+* *
+* Routines for GPI, GPO & Keypad *
+* *
+\**************************************/
+
+#define _USBLCD_MAX_DATA_LEN 24
+#define IN_REPORT_KEY_STATE 0x11
+
+typedef enum {
+ WIDGET_KEY_UP = 1,
+ WIDGET_KEY_DOWN = 2,
+ WIDGET_KEY_LEFT = 4,
+ WIDGET_KEY_RIGHT = 8,
+ WIDGET_KEY_CONFIRM = 16,
+ WIDGET_KEY_CANCEL = 32,
+ WIDGET_KEY_PRESSED = 64,
+ WIDGET_KEY_RELEASED = 128
+} KEYPADKEY;
+
+int cDriverPicoLCD_256x64::drv_pLG_gpi( __attribute__ ((unused))
+ int num)
+{
+ int ret;
+ unsigned char read_packet[_USBLCD_MAX_DATA_LEN];
+ ret = drv_pLG_read(read_packet, _USBLCD_MAX_DATA_LEN);
+ if ((ret > 0) && (read_packet[0] == IN_REPORT_KEY_STATE)) {
+// DEBUG("picoLCD: pressed key= 0x%02x\n", read_packet[1]);
+ return read_packet[1];
+ }
+ return 0;
+}
+
+
+int cDriverPicoLCD_256x64::drv_pLG_gpo(int num, int val)
+{
+ unsigned char cmd[2] = { 0x81 }; /* set GPO */
+
+ if (num < 0)
+ num = 0;
+ if (num > 7)
+ num = 7;
+
+ if (val < 0)
+ val = 0;
+ if (val > 1)
+ val = 1;
+
+ /* set led bit to 1 or 0 */
+ if (val)
+ gpo |= 1 << num;
+ else
+ gpo &= ~(1 << num);
+
+ cmd[1] = gpo;
+ drv_pLG_send(cmd, 2);
+
+ return val;
+}
+
+
+void cDriverPicoLCD_256x64::drv_pLG_update_keypad(void)
+{
+ static int pressed_key = 0;
+
+ int ret;
+ unsigned char read_packet[_USBLCD_MAX_DATA_LEN];
+ ret = drv_pLG_read(read_packet, _USBLCD_MAX_DATA_LEN);
+ if ((ret > 0) && (read_packet[0] == IN_REPORT_KEY_STATE)) {
+// DEBUG("picoLCD: pressed key= 0x%02x\n", read_packet[1]);
+ int new_pressed_key = read_packet[1];
+ if (pressed_key != new_pressed_key) {
+ /* negative values mark a key release */
+// drv_generic_keypad_press(-pressed_key);
+// drv_generic_keypad_press(new_pressed_key);
+ pressed_key = new_pressed_key;
+ }
+ }
+}
+
+
+int cDriverPicoLCD_256x64::drv_pLG_keypad(const int num)
+{
+ int val;
+ int new_num = num;
+
+ if (new_num == 0)
+ return 0;
+ else if (new_num > 0)
+ val = WIDGET_KEY_PRESSED;
+ else {
+ /* negative values mark a key release */
+ new_num = -num;
+ val = WIDGET_KEY_RELEASED;
+ }
+
+ switch (new_num) {
+ case 1:
+ val += WIDGET_KEY_CANCEL;
+ break;
+ case 2:
+ val += WIDGET_KEY_LEFT;
+ break;
+ case 3:
+ val += WIDGET_KEY_RIGHT;
+ break;
+ case 5:
+ val += WIDGET_KEY_UP;
+ break;
+ case 6:
+ val += WIDGET_KEY_CONFIRM;
+ break;
+ case 7:
+ val += WIDGET_KEY_DOWN;
+ break;
+ default:
+ fprintf(stderr,"picoLCD_256x64: unknown keypad value %d", num);
+ }
+
+ return val;
+}
+#endif
+
+// /namespace
+}
+
diff --git a/glcddrivers/picoLCD_256x64.h b/glcddrivers/picoLCD_256x64.h
new file mode 100644
index 0000000..4f8ce75
--- /dev/null
+++ b/glcddrivers/picoLCD_256x64.h
@@ -0,0 +1,106 @@
+/*
+ * GraphLCD driver library
+ *
+ * PicoLCD_256x64.h - picoLCD Graphic 256x64
+ * Output goes to a picoLCD Graphic 256x64 LCD
+ *
+ * Driver is based on lcd4linux driver by Nicu Pavel, Mini-Box.com <npavel@mini-box.com>
+ *
+ * This file is released under the GNU General Public License.
+ *
+ * See the files README and COPYING for details.
+ *
+ * 2012 by Jochen Koch <linuxfan1992 AT web de>
+ */
+
+#ifndef _GLCDDRIVERS_PicoLCD_256x64_H_
+#define _GLCDDRIVERS_PicoLCD_256x64_H_
+
+#include "driver.h"
+#include "stdio.h"
+#include <usb.h>
+#include <syslog.h>
+
+#define HAVE_STDBOOL_H
+
+#define picoLCD_VENDOR 0x04d8
+#define picoLCD_DEVICE 0xc002
+
+#define OUT_REPORT_LED_STATE 0x81
+#define OUT_REPORT_LCD_BACKLIGHT 0x91
+#define OUT_REPORT_LCD_CONTRAST 0x92
+
+#define OUT_REPORT_CMD 0x94
+#define OUT_REPORT_DATA 0x95
+#define OUT_REPORT_CMD_DATA 0x96
+
+#define SCREEN_H 64
+#define SCREEN_W 256
+
+#ifdef HAVE_DEBUG
+#define DEBUG(x) fprintf(stderr,"picoLCD_256x64: %s(): " #x "\n", __FUNCTION__);
+#define DEBUG1(x,...) fprintf(stderr,"picoLCD_256x64: %s(): " #x "\n", __FUNCTION__, __VA_ARGS__);
+#else
+#define DEBUG(x)
+#define DEBUG1(x,...)
+#endif
+
+#define INFO(x) syslog(LOG_INFO, "picoLCD_256x64: %s\n", x);
+#define INFO1(x,...) syslog(LOG_INFO, "picoLCD_256x64: " #x "\n", __VA_ARGS__);
+
+namespace GLCD
+{
+ class cDriverConfig;
+
+ class cDriverPicoLCD_256x64 : public cDriver
+ {
+ /* "dirty" marks the display to be redrawn from frame buffer */
+ int dirty;
+
+ /* USB read timeout in ms (the picoLCD 256x64 times out on every read
+ unless a key has been pressed!) */
+ int read_timeout;
+
+ unsigned char *pLG_framebuffer;
+
+ /* used to display white text on black background or inverse */
+ unsigned char inverted;
+
+ unsigned int gpo;
+
+ usb_dev_handle *lcd;
+
+ int CheckSetup();
+ protected:
+ int drv_pLG_open(void);
+ int drv_pLG_read(unsigned char *data, int size);
+ void drv_pLG_send(unsigned char *data, int size);
+ int drv_pLG_close(void);
+ void drv_pLG_clear(void);
+#ifdef ENABLE_GPIO_KEYPAD
+ // GPI, GPO, Keypad
+ int drv_pLG_gpi(int num);
+ int drv_pLG_gpo(int num, int val);
+ void drv_pLG_update_keypad(void);
+ int drv_pLG_keypad(const int num);
+#endif
+
+ public:
+ cDriverPicoLCD_256x64(cDriverConfig * config);
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ 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 SetBacklight(unsigned int percent);
+ virtual void SetContrast(unsigned int percent);
+ };
+};
+#endif
+
+
+
diff --git a/glcddrivers/port.c b/glcddrivers/port.c
index d6e8e34..cfb4156 100644
--- a/glcddrivers/port.c
+++ b/glcddrivers/port.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011-2012 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <errno.h>
@@ -16,6 +17,7 @@
#include <syslog.h>
#include <unistd.h>
#include <termios.h>
+#include <pthread.h>
#include <sys/io.h>
#include <sys/ioctl.h>
#include <linux/ppdev.h>
@@ -25,29 +27,42 @@
#include "port.h"
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
+ #define __HAS_DIRECTIO__ 1
+#endif
+
namespace GLCD
{
+static pthread_mutex_t claimport_mutex;
+
static inline int port_in(int port)
{
+#ifdef __HAS_DIRECTIO__
unsigned char value;
__asm__ volatile ("inb %1,%0"
: "=a" (value)
: "d" ((unsigned short) port));
return value;
+#else
+ return 0;
+#endif
}
static inline void port_out(unsigned short int port, unsigned char val)
{
+#ifdef __HAS_DIRECTIO__
__asm__ volatile ("outb %0,%1\n"
:
: "a" (val), "d" (port));
+#endif
}
cParallelPort::cParallelPort()
: fd(-1),
port(0),
- usePPDev(false)
+ usePPDev(false),
+ portClaimed(false)
{
}
@@ -57,6 +72,7 @@ cParallelPort::~cParallelPort()
int cParallelPort::Open(int portIO)
{
+#ifdef __HAS_DIRECTIO__
usePPDev = false;
port = portIO;
@@ -79,6 +95,10 @@ int cParallelPort::Open(int portIO)
}
}
return 0;
+#else
+ syslog(LOG_ERR, "glcd drivers: ERROR: direct IO/parport is not available on this architecture / operating system\n");
+ return -1;
+#endif
}
int cParallelPort::Open(const char * device)
@@ -93,7 +113,7 @@ int cParallelPort::Open(const char * device)
return -1;
}
- if (ioctl(fd, PPCLAIM, NULL) == -1)
+ if (!Claim())
{
syslog(LOG_ERR, "glcd drivers: ERROR cannot claim %s. Err:%s (cParallelPort::Init)\n",
device, strerror(errno));
@@ -102,7 +122,7 @@ int cParallelPort::Open(const char * device)
}
int mode = PARPORT_MODE_PCSPP;
- if (ioctl(fd, PPSETMODE, &mode) == -1)
+ if (ioctl(fd, PPSETMODE, &mode) != 0)
{
syslog(LOG_ERR, "glcd drivers: ERROR cannot setmode %s. Err:%s (cParallelPort::Init)\n",
device, strerror(errno));
@@ -130,6 +150,7 @@ int cParallelPort::Close()
}
else
{
+#ifdef __HAS_DIRECTIO__
if (port < 0x400)
{
if (ioperm(port, 3, 0) == -1)
@@ -144,20 +165,34 @@ int cParallelPort::Close()
return -1;
}
}
+#else
+ return -1; // should never make it until here ...
+#endif
}
return 0;
}
-void cParallelPort::Claim()
+bool cParallelPort::Claim()
{
- if (usePPDev)
- ioctl(fd, PPCLAIM);
+ if (!IsPortClaimed())
+ {
+ if (usePPDev)
+ portClaimed = (ioctl(fd, PPCLAIM) == 0);
+ else
+ portClaimed = (pthread_mutex_lock(&claimport_mutex) == 0);
+ }
+ return IsPortClaimed();
}
void cParallelPort::Release()
{
- if (usePPDev)
- ioctl(fd, PPRELEASE);
+ if (IsPortClaimed())
+ {
+ if (usePPDev)
+ portClaimed = !(ioctl(fd, PPRELEASE) == 0);
+ else
+ portClaimed = !(pthread_mutex_unlock(&claimport_mutex) == 0);
+ }
}
void cParallelPort::SetDirection(int direction)
diff --git a/glcddrivers/port.h b/glcddrivers/port.h
index 2920461..6fcd635 100644
--- a/glcddrivers/port.h
+++ b/glcddrivers/port.h
@@ -33,6 +33,7 @@ private:
int fd;
int port;
bool usePPDev;
+ bool portClaimed;
public:
cParallelPort();
@@ -45,8 +46,9 @@ public:
bool IsDirectIO() const { return (!usePPDev); }
int GetPortHandle() const { return ((usePPDev) ? fd : port); }
- void Claim();
+ bool Claim();
void Release();
+ bool IsPortClaimed() const { return (portClaimed); }
void SetDirection(int direction);
unsigned char ReadControl();
diff --git a/glcddrivers/sed1330.c b/glcddrivers/sed1330.c
index e993ca0..872cf89 100644
--- a/glcddrivers/sed1330.c
+++ b/glcddrivers/sed1330.c
@@ -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 <praml.roland AT t-online.de>
+ * (c) 2003 Roland Praml <praml.roland AT t-online.de>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <syslog.h>
@@ -129,10 +131,8 @@ const unsigned char kYASEDWCSLO = kSelectLow;
cDriverSED1330::cDriverSED1330(cDriverConfig * config)
-: config(config)
+: cDriver(config)
{
- oldConfig = new cDriverConfig(*config);
-
port = new cParallelPort();
refreshCounter = 0;
@@ -141,7 +141,6 @@ cDriverSED1330::cDriverSED1330(cDriverConfig * config)
cDriverSED1330::~cDriverSED1330()
{
delete port;
- delete oldConfig;
}
int cDriverSED1330::Init()
@@ -539,6 +538,29 @@ void cDriverSED1330::Clear()
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 @@ void cDriverSED1330::Set8Pixels(int x, int y, unsigned char data)
newLCD[x / 8][y] = newLCD[x / 8][y] | ReverseBits(data);
}
}
+#endif
void cDriverSED1330::Refresh(bool refreshAll)
{
diff --git a/glcddrivers/sed1330.h b/glcddrivers/sed1330.h
index 354b853..ad2eef5 100644
--- a/glcddrivers/sed1330.h
+++ b/glcddrivers/sed1330.h
@@ -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 <praml.roland AT t-online.de>
+ * (c) 2003 Roland Praml <praml.roland AT t-online.de>
+ * (c) 2005-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_SED1330_H_
@@ -37,8 +39,6 @@ private:
unsigned char ** oldLCD; // current state
int refreshCounter;
long timeForPortCmdInNs;
- cDriverConfig * config;
- cDriverConfig * oldConfig;
bool useSleepInit;
int oscillatorFrequency;
@@ -69,7 +69,8 @@ public:
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 --git a/glcddrivers/sed1520.c b/glcddrivers/sed1520.c
index c0b1b27..4692c64 100644
--- a/glcddrivers/sed1520.c
+++ b/glcddrivers/sed1520.c
@@ -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 <vdr AT smue.org>
+ * (c) 2003-2011 Andreas 'randy' Weinberger <vdr AT smue.org>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <syslog.h>
@@ -45,10 +46,8 @@ const unsigned char kLEDLO = 0x00;
cDriverSED1520::cDriverSED1520(cDriverConfig * config)
-: config(config)
+: cDriver(config)
{
- oldConfig = new cDriverConfig(*config);
-
port = new cParallelPort();
refreshCounter = 0;
@@ -57,7 +56,6 @@ cDriverSED1520::cDriverSED1520(cDriverConfig * config)
cDriverSED1520::~cDriverSED1520()
{
delete port;
- delete oldConfig;
}
int cDriverSED1520::Init()
@@ -303,6 +301,29 @@ void cDriverSED1520::Clear()
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 @@ void cDriverSED1520::Set8Pixels (int x, int y, unsigned char data)
LCD[x / 8][y] = LCD[x / 8][y] | ReverseBits(data);
}
}
+#endif
void cDriverSED1520::Refresh(bool refreshAll)
{
diff --git a/glcddrivers/sed1520.h b/glcddrivers/sed1520.h
index 931d51b..e72befc 100644
--- a/glcddrivers/sed1520.h
+++ b/glcddrivers/sed1520.h
@@ -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 <vdr AT smue.org>
+ * (c) 2003-2011 Andreas 'randy' Weinberger <vdr AT smue.org>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_SED1520_H_
@@ -29,8 +30,6 @@ private:
unsigned char ** LCD_page; // paged lcd display "memory"
int refreshCounter;
long timeForPortCmdInNs;
- cDriverConfig * config;
- cDriverConfig * oldConfig;
bool useSleepInit;
int SEAD;
@@ -63,7 +62,8 @@ public:
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 --git a/glcddrivers/serdisp.c b/glcddrivers/serdisp.c
index b092659..1fac5ba 100644
--- a/glcddrivers/serdisp.c
+++ b/glcddrivers/serdisp.c
@@ -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 <mrwastl AT users.sourceforge.net>
+ * (c) 2003-2013 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <stdio.h>
@@ -19,6 +19,11 @@
#include "config.h"
#include "serdisp.h"
+// for memcpy
+#include <string.h>
+
+#include <map>
+
#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,26 @@
#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 */
+#define SDGPT_GENERICTOUCH 0x11 /* generic touch screen event, type: SDGP_evpkt_generictouch_t */
+
+#define SDGPT_TOUCHDOWN 0x0
+#define SDGPT_TOUCHUP 0x1
+#define SDGPT_TOUCHMOVE 0x2
namespace GLCD
{
-cDriverSerDisp::cDriverSerDisp(cDriverConfig * config)
-: config(config)
-{
- oldConfig = new cDriverConfig(*config);
+static void wrapEventListener(void* dd, SDGP_event_t* recylce);
+
+static std::map<void* ,tTouchEvent*> touchEvents;
- dd = (void *) NULL;
-}
-cDriverSerDisp::~cDriverSerDisp(void)
+cDriverSerDisp::cDriverSerDisp(cDriverConfig * config)
+: cDriver(config)
{
- delete oldConfig;
+ dd = (void *) NULL;
}
int cDriverSerDisp::Init(void)
@@ -58,10 +66,27 @@ int cDriverSerDisp::Init(void)
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
+
+ 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 --;
+ }
- sdhnd = dlopen("libserdisp.so", RTLD_LAZY);
+ 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 +101,63 @@ int cDriverSerDisp::Init(void)
/* 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 +216,24 @@ int cDriverSerDisp::Init(void)
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 +249,12 @@ int cDriverSerDisp::Init(void)
} 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 +270,13 @@ int cDriverSerDisp::Init(void)
}
- 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 +288,13 @@ int cDriverSerDisp::Init(void)
}
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 +306,7 @@ int cDriverSerDisp::Init(void)
}
}
- 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 +318,9 @@ int cDriverSerDisp::Init(void)
// 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,22 +363,28 @@ int cDriverSerDisp::Init(void)
// clear display
Clear();
+ touchEvent = new tTouchEvent;
+ touchEvent->touchChanged = 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);
- }
- (int) dlclose(sdhnd);
+ 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);
+
+ dlclose(sdhnd);
sdhnd = NULL;
return 0;
@@ -434,6 +436,7 @@ int cDriverSerDisp::CheckSetup()
update = true;
}
+#if 0
/* driver dependend options */
if ( supports_options ) {
for (unsigned int i = 0; i < config->options.size(); i++) {
@@ -448,7 +451,7 @@ int cDriverSerDisp::CheckSetup()
}
}
}
-
+#endif
if (update)
return 1;
@@ -457,16 +460,17 @@ int cDriverSerDisp::CheckSetup()
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 +480,50 @@ void cDriverSerDisp::Set8Pixels(int x, int y, unsigned char data) {
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 +537,114 @@ void cDriverSerDisp::Refresh(bool refreshAll)
}
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->touchChanged == false)
+ return NULL;
+
+ cTouchEvent * ev = new cTouchEvent();
+
+ ev->x = tev->touchX;
+ ev->y = tev->touchY;
+ ev->touch = tev->touchT;
+ tev->touchChanged = 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->touchChanged = true;
+ tev->touchX = simpletouch.norm_x;
+ tev->touchY = simpletouch.norm_y;
+ tev->touchT = simpletouch.norm_touch;
+ }
+ } else if (event->type == SDGPT_GENERICTOUCH) {
+ SDGP_evpkt_generictouch_t generictouch;
+ memcpy(&generictouch, &event->data, sizeof(SDGP_evpkt_generictouch_t));
+
+ /* ignore all but SDGPT_TOUCHDOWN events */
+ if (generictouch.type != SDGPT_TOUCHDOWN)
+ return;
+
+ tTouchEvent* tev = touchEvents[dd];
+ if (tev) {
+ tev->touchChanged = true;
+ tev->touchX = generictouch.norm_x;
+ tev->touchY = generictouch.norm_y;
+ tev->touchT = (int)generictouch.norm_touch;
+ }
+ }
}
} // end of namespace
diff --git a/glcddrivers/serdisp.h b/glcddrivers/serdisp.h
index c84874e..31fcdad 100644
--- a/glcddrivers/serdisp.h
+++ b/glcddrivers/serdisp.h
@@ -7,32 +7,84 @@
* This file is released under the GNU General Public License. Refer
* to the COPYING file distributed with this package.
*
- * (c) 2003-2010 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
+ * (c) 2003-2013 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_SERDISP_H_
#define _GLCDDRIVERS_SERDISP_H_
#include "driver.h"
-
+#include <sys/time.h>
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;
+
+/* event-payload-type for generic touchscreen events (only importat stuff is defined here, rest is ignored (read only!) */
+typedef struct SDGP_evpkt_generictouch_s { /* 16 bytes */
+ uint8_t type; /* event type: 0: up, 1: down, 2: move */
+ uint8_t flags; /* 0000 000x ... 0: binary touch, 1: touch with pressure information */
+ /* xxxx 0000 ... 0000: union not used */
+ /* 0001: raw touch information included in union */
+ /* 0010: reserved */
+ /* 0011: reserved */
+ int16_t norm_x; /* normalised coordinate X (norm_x <= dd->width) */
+ int16_t norm_y; /* normalised coordinate Y (norm_y <= dd->height) */
+ uint16_t norm_touch; /* normalised touch value */
+ /* ignore all union stuff */
+} SDGP_evpkt_generictouch_t;
+
+
+typedef struct {
+ bool touchChanged;
+ int touchX;
+ int touchY;
+ int touchT;
+} 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 +94,57 @@ private:
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 --git a/glcddrivers/simlcd.c b/glcddrivers/simlcd.c
index 6dc1dfe..d1da90f 100644
--- a/glcddrivers/simlcd.c
+++ b/glcddrivers/simlcd.c
@@ -9,6 +9,8 @@
* to the COPYING file distributed with this package.
*
* (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ * (c) 2011 Dirk Heiser
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <stdio.h>
@@ -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 @@ int cDriverSimLCD::Init()
}
// 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 @@ int cDriverSimLCD::Init()
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 @@ int cDriverSimLCD::DeInit()
return 0;
}
-int cDriverSimLCD::CheckSetup()
+int cDriverSimLCD::CheckSetup(void)
{
if (config->width != oldConfig->width ||
config->height != oldConfig->height)
@@ -105,29 +107,29 @@ int cDriverSimLCD::CheckSetup()
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 @@ void cDriverSimLCD::Refresh(bool refreshAll)
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 @@ void cDriverSimLCD::Refresh(bool refreshAll)
fclose(fp);
}
- fp = fopen("/tmp/simlcd.sem", "w");
+ fp = fopen(DISPLAY_REFRESH_FILE, "w");
fclose(fp);
}
else
@@ -181,4 +188,31 @@ void cDriverSimLCD::Refresh(bool refreshAll)
}
}
+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 --git a/glcddrivers/simlcd.h b/glcddrivers/simlcd.h
index 8b2aca8..12f819c 100644
--- a/glcddrivers/simlcd.h
+++ b/glcddrivers/simlcd.h
@@ -9,6 +9,8 @@
* to the COPYING file distributed with this package.
*
* (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ * (c) 2011 Dirk Heiser
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_SIMLCD_H_
@@ -25,22 +27,20 @@ class cDriverConfig;
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 --git a/glcddrivers/ssd1306.c b/glcddrivers/ssd1306.c
new file mode 100644
index 0000000..852ea13
--- /dev/null
+++ b/glcddrivers/ssd1306.c
@@ -0,0 +1,340 @@
+/*
+ * GraphLCD driver library
+ *
+ * ssd1306.c - SSD1306 OLED driver class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2014 Andreas Regel <andreas.regel AT powarman.de>
+ */
+
+#include <stdint.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <cstring>
+
+#include <wiringPi.h>
+#include <wiringPiSPI.h>
+
+#include "common.h"
+#include "config.h"
+#include "ssd1306.h"
+
+
+namespace GLCD
+{
+
+const int kLcdWidth = 128;
+const int kLcdHeight = 64;
+
+const int kSpiBus = 0;
+
+const int kGpioReset = 15;
+const int kGpioDC = 16;
+
+const uint8_t kCmdSetLowerColumn = 0x00;
+const uint8_t kCmdSetHigherColumn = 0x10;
+const uint8_t kCmdSetMemoryAddressingMode = 0x20;
+const uint8_t kCmdSetColumnAddress = 0x21;
+const uint8_t kCmdSetPageAddress = 0x22;
+const uint8_t kCmdSetDisplayStartLine = 0x40;
+const uint8_t kCmdSetContrast = 0x81;
+const uint8_t kCmdSetChargePump = 0x8D;
+const uint8_t kCmdSetSegmentReMap = 0xA0;
+const uint8_t kCmdEntireDisplayOnResume = 0xA4;
+const uint8_t kCmdEntireDisplayOn = 0xA5;
+const uint8_t kCmdSetNormalDisplay = 0xA6;
+const uint8_t kCmdSetInverseDisplay = 0xA7;
+const uint8_t kCmdSetMultiplexRatio = 0xA8;
+const uint8_t kCmdSetDisplayOff = 0xAE;
+const uint8_t kCmdSetDisplayOn = 0xAF;
+const uint8_t kCmdSetPageStart = 0xB0;
+const uint8_t kCmdSetComScanInc = 0xC0;
+const uint8_t kCmdSetComScanDec = 0xC8;
+const uint8_t kCmdSetDisplayOffset = 0xD3;
+const uint8_t kCmdSetDisplayClockDiv = 0xD5;
+const uint8_t kCmdSetPreChargePeriod = 0xD9;
+const uint8_t kCmdSetComPins = 0xDA;
+const uint8_t kCmdSetVComDeselectLevel = 0xDB;
+
+
+cDriverSSD1306::cDriverSSD1306(cDriverConfig * config)
+: cDriver(config)
+{
+ refreshCounter = 0;
+
+ wiringPiSetup();
+}
+
+cDriverSSD1306::~cDriverSSD1306()
+{
+ //delete port;
+}
+
+int cDriverSSD1306::Init()
+{
+ int x;
+
+ width = config->width;
+ if (width <= 0)
+ width = kLcdWidth;
+ height = config->height;
+ if (height <= 0)
+ height = kLcdHeight;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "")
+ {
+ }
+ }
+
+ // setup lcd array (wanted state)
+ newLCD = new unsigned char*[width];
+ if (newLCD)
+ {
+ for (x = 0; x < width; x++)
+ {
+ newLCD[x] = new unsigned char[(height + 7) / 8];
+ memset(newLCD[x], 0, (height + 7) / 8);
+ }
+ }
+ // setup lcd array (current state)
+ oldLCD = new unsigned char*[width];
+ if (oldLCD)
+ {
+ for (x = 0; x < width; x++)
+ {
+ oldLCD[x] = new unsigned char[(height + 7) / 8];
+ memset(oldLCD[x], 0, (height + 7) / 8);
+ }
+ }
+
+ if (config->device == "")
+ {
+ return -1;
+ }
+
+ pinMode(kGpioReset, OUTPUT);
+ pinMode(kGpioDC, OUTPUT);
+
+ digitalWrite(kGpioReset, HIGH);
+ digitalWrite(kGpioDC, LOW);
+
+ wiringPiSPISetup(kSpiBus, 1000000);
+
+ /* reset display */
+ Reset();
+ usleep(1000);
+
+ WriteCommand(kCmdSetDisplayOff);
+
+ if (height == 64)
+ {
+ WriteCommand(kCmdSetMultiplexRatio, 0x3F);
+ WriteCommand(kCmdSetComPins, 0x12);
+ }
+ else if (height == 32)
+ {
+ WriteCommand(kCmdSetMultiplexRatio, 0x1F);
+ WriteCommand(kCmdSetComPins, 0x02);
+ }
+
+ WriteCommand(kCmdSetDisplayOffset, 0x00);
+ WriteCommand(kCmdSetDisplayStartLine | 0x00);
+ WriteCommand(kCmdSetMemoryAddressingMode, 0x01);
+ WriteCommand(kCmdSetSegmentReMap | 0x01);
+ WriteCommand(kCmdSetComScanDec);
+ WriteCommand(kCmdSetContrast, config->brightness * 255 / 100);
+ WriteCommand(kCmdEntireDisplayOnResume);
+ WriteCommand(kCmdSetNormalDisplay);
+ WriteCommand(kCmdSetDisplayClockDiv, 0x80);
+ WriteCommand(kCmdSetChargePump, 0x14);
+ WriteCommand(kCmdSetDisplayOn);
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ syslog(LOG_INFO, "%s: SSD1306 initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverSSD1306::DeInit()
+{
+ int x;
+ // free lcd array (wanted state)
+ if (newLCD)
+ {
+ for (x = 0; x < width; x++)
+ {
+ delete[] newLCD[x];
+ }
+ delete[] newLCD;
+ }
+ // free lcd array (current state)
+ if (oldLCD)
+ {
+ for (x = 0; x < width; x++)
+ {
+ delete[] oldLCD[x];
+ }
+ delete[] oldLCD;
+ }
+
+ return 0;
+}
+
+int cDriverSSD1306::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->width != oldConfig->width ||
+ config->height != oldConfig->height)
+ {
+ DeInit();
+ Init();
+ return 0;
+ }
+
+ if (config->upsideDown != oldConfig->upsideDown ||
+ config->invert != oldConfig->invert)
+ {
+ oldConfig->upsideDown = config->upsideDown;
+ oldConfig->invert = config->invert;
+ return 1;
+ }
+ return 0;
+}
+
+void cDriverSSD1306::Clear()
+{
+ for (int x = 0; x < width; x++)
+ memset(newLCD[x], 0, (height + 7) / 8);
+}
+
+
+void cDriverSSD1306::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 = (y % 8);
+ if (data == GRAPHLCD_White)
+ newLCD[x][y / 8] |= (1 << offset);
+ else
+ newLCD[x][y / 8] &= ( 0xFF ^ (1 << offset) );
+}
+
+
+#if 0
+void cDriverSSD1306::Set8Pixels(int x, int y, unsigned char data)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (!config->upsideDown)
+ {
+ int offset = 7 - (y % 8);
+ for (int i = 0; i < 8; i++)
+ {
+ newLCD[x + i][y / 8] |= ((data >> (7 - i)) << offset) & (1 << offset);
+ }
+ }
+ else
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ int offset = 7 - (y % 8);
+ for (int i = 0; i < 8; i++)
+ {
+ newLCD[x - i][y / 8] |= ((data >> (7 - i)) << offset) & (1 << offset);
+ }
+ }
+}
+#endif
+
+void cDriverSSD1306::Refresh(bool refreshAll)
+{
+ int x;
+ int y;
+ uint8_t numPages = (height + 7) / 8;
+ unsigned char data[16];
+
+ if (CheckSetup() == 1)
+ refreshAll = true;
+
+ if (config->refreshDisplay > 0)
+ {
+ refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !refreshCounter)
+ refreshAll = true;
+ }
+
+ refreshAll = true;
+ if (refreshAll)
+ {
+ WriteCommand(kCmdSetColumnAddress, 0, width - 1);
+ WriteCommand(kCmdSetPageAddress, 0, numPages - 1);
+ for (x = 0; x < width; x++)
+ {
+ for (y = 0; y < numPages; y++)
+ {
+ data[y] = (newLCD[x][y]) ^ (config->invert ? 0xff : 0x00);
+ }
+ WriteData(data, numPages);
+ memcpy(oldLCD[x], newLCD[x], numPages);
+ }
+ // and reset RefreshCounter
+ refreshCounter = 0;
+ }
+ else
+ {
+ // draw only the changed bytes
+ }
+}
+
+void cDriverSSD1306::SetBrightness(unsigned int percent)
+{
+ WriteCommand(kCmdSetContrast, percent * 255 / 100);
+}
+
+void cDriverSSD1306::Reset()
+{
+ digitalWrite(kGpioReset, LOW);
+ usleep(1000);
+ digitalWrite(kGpioReset, HIGH);
+}
+
+void cDriverSSD1306::WriteCommand(uint8_t command)
+{
+ wiringPiSPIDataRW(kSpiBus, &command, 1);
+}
+
+void cDriverSSD1306::WriteCommand(uint8_t command, uint8_t argument)
+{
+ uint8_t buffer[2] = {command, argument};
+ wiringPiSPIDataRW(kSpiBus, buffer, 2);
+}
+
+void cDriverSSD1306::WriteCommand(uint8_t command, uint8_t argument1, uint8_t argument2)
+{
+ uint8_t buffer[3] = {command, argument1, argument2};
+ wiringPiSPIDataRW(kSpiBus, buffer, 3);
+}
+
+void cDriverSSD1306::WriteData(uint8_t * buffer, uint32_t length)
+{
+ digitalWrite(kGpioDC, HIGH);
+ wiringPiSPIDataRW(kSpiBus, buffer, length);
+ digitalWrite(kGpioDC, LOW);
+}
+
+} // end of namespace
diff --git a/glcddrivers/ssd1306.h b/glcddrivers/ssd1306.h
new file mode 100644
index 0000000..5d06b4c
--- /dev/null
+++ b/glcddrivers/ssd1306.h
@@ -0,0 +1,53 @@
+/*
+ * GraphLCD driver library
+ *
+ * ssd1306.h - SSD1306 OLED driver class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2014 Andreas Regel <andreas.regel AT powarman.de>
+ */
+
+#ifndef _GLCDDRIVERS_SSD1306_H_
+#define _GLCDDRIVERS_SSD1306_H_
+
+#include "driver.h"
+
+namespace GLCD
+{
+
+class cDriverConfig;
+
+class cDriverSSD1306 : public cDriver
+{
+private:
+ unsigned char ** newLCD; // wanted state
+ unsigned char ** oldLCD; // current state
+ int refreshCounter;
+
+ int CheckSetup();
+
+ void Reset();
+ void WriteCommand(uint8_t command);
+ void WriteCommand(uint8_t command, uint8_t argument);
+ void WriteCommand(uint8_t command, uint8_t argument1, uint8_t argument2);
+ void WriteData(uint8_t * buffer, uint32_t length);
+
+public:
+ cDriverSSD1306(cDriverConfig * config);
+ virtual ~cDriverSSD1306();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ 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);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/t6963c.c b/glcddrivers/t6963c.c
index d42da35..aec2585 100644
--- a/glcddrivers/t6963c.c
+++ b/glcddrivers/t6963c.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2003-2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#include <syslog.h>
@@ -107,10 +108,8 @@ const unsigned char kSerialCDLO = 0x04; //
cDriverT6963C::cDriverT6963C(cDriverConfig * config)
-: config(config)
+: cDriver(config)
{
- oldConfig = new cDriverConfig(*config);
-
port = new cParallelPort();
//width = config->width;
@@ -125,7 +124,6 @@ cDriverT6963C::cDriverT6963C(cDriverConfig * config)
cDriverT6963C::~cDriverT6963C()
{
delete port;
- delete oldConfig;
}
int cDriverT6963C::Init()
@@ -376,6 +374,52 @@ void cDriverT6963C::Clear()
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 @@ void cDriverT6963C::Set8Pixels(int x, int y, unsigned char data)
}
}
}
+#endif
void cDriverT6963C::Refresh(bool refreshAll)
{
diff --git a/glcddrivers/t6963c.h b/glcddrivers/t6963c.h
index 88be16b..a9388b4 100644
--- a/glcddrivers/t6963c.h
+++ b/glcddrivers/t6963c.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2003-2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
*/
#ifndef _GLCDDRIVERS_T6963C_H_
@@ -28,8 +29,6 @@ private:
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 @@ public:
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 --git a/glcddrivers/vncserver.c b/glcddrivers/vncserver.c
new file mode 100644
index 0000000..8461548
--- /dev/null
+++ b/glcddrivers/vncserver.c
@@ -0,0 +1,211 @@
+/*
+ * GraphLCD driver library
+ *
+ * vncserver.h - vncserver device
+ * Output goes to a vncserver device
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2013 Michael Heyer
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+#include "common.h"
+#include "config.h"
+#include "vncserver.h"
+
+
+namespace GLCD
+{
+
+cDriverVncServer::cDriverVncServer(cDriverConfig * config)
+: cDriver(config),
+ offbuff(0)
+{
+}
+
+int cDriverVncServer::Init()
+{
+ printf(" init.\n");
+
+ width = config->width;
+ height = config->height;
+
+ // Figure out the size of the screen in bytes
+ screensize = width * height * 4;
+ depth = 24;
+ server = rfbGetScreen(NULL,NULL,width,height,8,3,4);
+ if (!server)
+ {
+ syslog(LOG_ERR, "failed to creat vncserver device.\n");
+ return -1;
+ }
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "HttpDir")
+ {
+ server->httpDir = (char *)config->options[i].value.c_str();
+ }
+ }
+
+ // 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
+
+ // reserve another memory to draw into
+ offbuff = new char[screensize];
+ if (!offbuff)
+ {
+ syslog(LOG_ERR, "%s: failed to alloc memory for vncserver device.\n", config->name.c_str());
+ return -1;
+ }
+
+ server->frameBuffer=offbuff;
+ rfbInitServer(server);
+
+ *oldConfig = *config;
+
+ // clear display
+ Refresh(true);
+
+ rfbRunEventLoop(server, 5000, true);
+
+ syslog(LOG_INFO, "%s: VncServer initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverVncServer::DeInit()
+{
+ if (offbuff)
+ delete[] offbuff;
+ return 0;
+}
+
+int cDriverVncServer::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 32 != oldConfig->width ||
+ config->height != oldConfig->height)
+ {
+ DeInit();
+ Init();
+ return 0;
+ }
+
+ if (config->upsideDown != oldConfig->upsideDown ||
+ config->invert != oldConfig->invert)
+ {
+ oldConfig->upsideDown = config->upsideDown;
+ oldConfig->invert = config->invert;
+ return 1;
+ }
+ return 0;
+}
+
+void cDriverVncServer::SetPixel(int x, int y, uint32_t data)
+{
+ int location;
+
+ if (x >= width || y >= height)
+ return;
+
+ if (config->upsideDown)
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ }
+
+ location = (x + y * width) * 4;
+ unsigned char r,g,b;
+ r = (data & 0x00FF0000) >> 16;
+ g = (data & 0x0000FF00) >> 8;
+ b = (data & 0x000000FF) >> 0;
+ if (config->invert) {
+ r = 255 - r;
+ g = 255 - g;
+ b = 255 - b;
+ }
+ *(offbuff + location + 0) = r;
+ *(offbuff + location + 1) = g;
+ *(offbuff + location + 2) = b;
+
+ 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 cDriverVncServer::Clear()
+{
+ memset(offbuff, 0, screensize);
+ processDamage();
+}
+
+void cDriverVncServer::Refresh(bool refreshAll)
+{
+ if (refreshAll) {
+ bbox[0] = 0;
+ bbox[1] = 0;
+ bbox[2] = width - 1;
+ bbox[3] = height - 1;
+ }
+ processDamage();
+}
+
+bool cDriverVncServer::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() */
+void cDriverVncServer::processDamage (void) {
+
+ if (!((bbox[0] == (width - 1)) && (bbox[1] == (height - 1)) && (bbox[2] == 0) && (bbox[3] == 0))) {
+ rfbMarkRectAsModified(server,bbox[0],bbox[1],bbox[2],bbox[3]);
+ }
+
+ /* reset bounding box */
+ bbox[0] = width - 1;
+ bbox[1] = height - 1;
+ bbox[2] = 0;
+ bbox[3] = 0;
+}
+
+} // end of namespace
diff --git a/glcddrivers/vncserver.h b/glcddrivers/vncserver.h
new file mode 100644
index 0000000..e1d155d
--- /dev/null
+++ b/glcddrivers/vncserver.h
@@ -0,0 +1,50 @@
+/*
+ * GraphLCD driver library
+ *
+ * vncserver.h - vncserver device
+ * Output goes to a vncserver device
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2013 Michael Heyer
+ */
+
+#ifndef _GLCDDRIVERS_VNCSERVER_H_
+#define _GLCDDRIVERS_VNCSERVER_H_
+
+#include "driver.h"
+#include <rfb/rfb.h>
+
+namespace GLCD
+{
+
+class cDriverConfig;
+
+class cDriverVncServer : public cDriver
+{
+private:
+ char *offbuff;
+ rfbScreenInfoPtr server;
+ long int screensize;
+ int bbox[4];
+ int depth;
+
+ int CheckSetup();
+ void processDamage (void);
+protected:
+ virtual bool GetDriverFeature (const std::string & Feature, int & value);
+public:
+ cDriverVncServer(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);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcdgraphics/Makefile b/glcdgraphics/Makefile
index 7f7ff74..2d6e7ff 100644
--- a/glcdgraphics/Makefile
+++ b/glcdgraphics/Makefile
@@ -4,31 +4,39 @@
-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:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
-MAKEDEP = g++ -MM -MG
-DEPFILE = .dependencies
-$(DEPFILE): Makefile
- @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+DEPFILE = $(OBJS:%.o=%.d)
-include $(DEPFILE)
@@ -41,7 +49,22 @@ ifdef HAVE_FREETYPE2
LIBS += -lfreetype
endif
DEFINES += -DHAVE_FREETYPE2
-endif### Targets:
+endif
+
+# 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
+
+
+### Targets:
all: $(LIBNAME)
diff --git a/glcdgraphics/bitmap.c b/glcdgraphics/bitmap.c
index fe4b497..227e140 100644
--- a/glcdgraphics/bitmap.c
+++ b/glcdgraphics/bitmap.c
@@ -9,14 +9,15 @@
* This file is released under the GNU General Public License. Refer
* to the COPYING file distributed with this package.
*
- * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2012 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
-#include <syslog.h>
#include "bitmap.h"
#include "common.h"
@@ -26,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 HAVE_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 HAVE_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)
@@ -48,63 +128,91 @@ cBitmap::cBitmap(const cBitmap & b)
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 HAVE_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)
@@ -152,43 +260,43 @@ void cBitmap::DrawLine(int x1, int y1, int x2, int y2, eColor color)
}
}
-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 HAVE_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)
+void cBitmap::DrawVLine(int x, int y1, int y2, uint32_t color)
{
- int y;
+#ifdef HAVE_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 HAVE_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);
@@ -208,8 +316,13 @@ void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, eColor color, bool f
}
}
-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 HAVE_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);
@@ -231,10 +344,14 @@ void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, b
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
@@ -257,8 +374,13 @@ void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, b
}
}
-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 HAVE_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;
@@ -398,8 +520,13 @@ void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, eColor color, bool fil
}
}
-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 HAVE_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;
@@ -411,7 +538,7 @@ void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type)
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);
@@ -433,82 +560,59 @@ void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type)
}
}
-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 HAVE_DEBUG
+ printf("%s:%s(%d) '%03d' x '%03d' \n", __FILE__, __FUNCTION__, __LINE__, x, y);
+#endif
+ color = cColor::AlignAlpha(color);
+ bgcolor = cColor::AlignAlpha(bgcolor);
- w = bitmap.Width();
- h = bitmap.Height();
+ uint32_t cl = 0;
+ const uint32_t * data = bitmap.Data();
+ bool ismono = bitmap.IsMonochrome();
+
+ int xt, yt;
+ uint32_t alpha;
if (data)
{
- if (!(x % 8))
+ for (yt = 0; yt < bitmap.Height(); yt++)
{
- // 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
- {
- // 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 (ismono) {
+ cl = (cl == cColor::Black) ? color : bgcolor;
+ }
+ if (opacity != 255) {
+ alpha = (cl & 0xFF000000) >> 24;
+ alpha = (alpha * opacity) / 255;
+ cl = (cl & 0x00FFFFFF) | (alpha << 24);
+ }
+ if (cl & 0xFF000000) // only draw if alpha > 0
+ 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 HAVE_DEBUG
+ printf("%s:%s(%d) text '%s', color '%08x'/'%08x'\n", __FILE__, __FUNCTION__, __LINE__, text.c_str(), color, bgcolor);
+#endif
int xt;
int yt;
unsigned int i;
- int c;
- int start;
+ uint32_t c;
+ unsigned int start;
+
+ color = cColor::AlignAlpha(color);
+ bgcolor = cColor::AlignAlpha(bgcolor);
clip(x, 0, width - 1);
clip(y, 0, height - 1);
@@ -537,17 +641,22 @@ int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cF
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() )
{
- cFont::Utf8CodeAdjustCounter(text, c, i);
+ encodedCharAdjustCounter(font->IsUTF8(), text, c, i);
if (xt > xmax)
{
@@ -559,13 +668,13 @@ int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cF
{
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();
}
}
@@ -573,12 +682,12 @@ int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cF
{
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)
{
@@ -586,15 +695,26 @@ int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cF
}
}
}
+ i++;
}
}
return xt;
}
-int cBitmap::DrawCharacter(int x, int y, int xmax, int 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 HAVE_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);
@@ -602,32 +722,54 @@ int cBitmap::DrawCharacter(int x, int y, int xmax, int c, const cFont * font,
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 HAVE_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);
@@ -644,62 +786,80 @@ cBitmap * cBitmap::SubBitmap(int x1, int y1, int x2, int y2) const
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 HAVE_DEBUG
+ printf("%s:%s(%d)\n", __FILE__, __FUNCTION__, __LINE__);
+#endif
FILE * pbmFile;
char str[32];
int i;
@@ -775,13 +935,12 @@ bool cBitmap::LoadPBM(const std::string & fileName)
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;
@@ -789,6 +948,9 @@ bool cBitmap::LoadPBM(const std::string & fileName)
void cBitmap::SavePBM(const std::string & fileName)
{
+#ifdef HAVE_DEBUG
+ printf("%s:%s(%d)\n", __FILE__, __FUNCTION__, __LINE__);
+#endif
int i;
char str[32];
FILE * fp;
@@ -805,6 +967,6 @@ void cBitmap::SavePBM(const std::string & fileName)
fclose(fp);
}
}
+#endif
} // end of namespace
-
diff --git a/glcdgraphics/bitmap.h b/glcdgraphics/bitmap.h
index 9e5c7e6..2c4a2af 100644
--- a/glcdgraphics/bitmap.h
+++ b/glcdgraphics/bitmap.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2012 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#ifndef _GLCDGRAPHICS_BITMAP_H_
#define _GLCDGRAPHICS_BITMAP_H_
#include <string>
+#include <inttypes.h>
+
+// 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 @@ protected:
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, int 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 ismono) { ismonochrome = ismono; }
+ 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 --git a/glcdgraphics/common.c b/glcdgraphics/common.c
index 8942424..0fd78b8 100644
--- a/glcdgraphics/common.c
+++ b/glcdgraphics/common.c
@@ -6,10 +6,12 @@
* This file is released under the GNU General Public License. Refer
* to the COPYING file distributed with this package.
*
- * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2012 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#include <ctype.h>
+#include <syslog.h>
#include "common.h"
@@ -48,7 +50,7 @@ std::string trim(const std::string & s)
start++;
}
end = s.length() - 1;
- while (end >= 0)
+ while (end > start)
{
if (!isspace(s[end]))
break;
@@ -57,4 +59,66 @@ std::string trim(const std::string & s)
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 --git a/glcdgraphics/common.h b/glcdgraphics/common.h
index 2865602..f0376bf 100644
--- a/glcdgraphics/common.h
+++ b/glcdgraphics/common.h
@@ -13,6 +13,13 @@
#define _GLCDGRAPHICS_COMMON_H_
#include <string>
+#include <stdint.h>
+
+// 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 @@ namespace GLCD
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 --git a/glcdgraphics/extformats.c b/glcdgraphics/extformats.c
new file mode 100644
index 0000000..5734fce
--- /dev/null
+++ b/glcdgraphics/extformats.c
@@ -0,0 +1,184 @@
+/*
+ * 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-2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <syslog.h>
+
+#include <cstring>
+
+#include "bitmap.h"
+#include "extformats.h"
+#include "image.h"
+
+#ifdef HAVE_IMAGEMAGICK
+#include <Magick++.h>
+//#elif defined(HAVE_IMLIB2)
+//#include "quantize.h"
+//#include <Imlib2.h>
+#endif
+
+
+namespace GLCD
+{
+
+using namespace std;
+
+
+cExtFormatFile::cExtFormatFile()
+{
+#ifdef HAVE_IMAGEMAGICK
+ Magick::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<Magick::Image> extimages;
+ try {
+ uint16_t width = 0;
+ uint16_t height = 0;
+ //uint16_t count;
+ uint32_t delay;
+
+ std::vector<Magick::Image>::iterator it;
+ readImages(&extimages, fileName);
+ if (extimages.size() == 0) {
+ syslog(LOG_ERR, "glcdgraphics: Couldn't load '%s' (cExtFormatFile::LoadScaled)", 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( Magick::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).sample(Magick::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).sample(Magick::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 Magick::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 && Magick::Color::scaleQuantumToDouble(pix->opacity) * 255 == 255 ) {
+ bmpdata[iy*width+ix] = cColor::Transparent;
+ } else {
+ bmpdata[iy*width+ix] = (uint32_t)(
+ (uint32_t(255 - (Magick::Color::scaleQuantumToDouble(pix->opacity) * 255)) << 24) |
+ (uint32_t( Magick::Color::scaleQuantumToDouble(pix->red) * 255) << 16) |
+ (uint32_t( Magick::Color::scaleQuantumToDouble(pix->green) * 255) << 8) |
+ uint32_t( Magick::Color::scaleQuantumToDouble(pix->blue) * 255)
+ );
+ //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 (Magick::Exception &e) {
+ syslog(LOG_ERR, "glcdgraphics: Couldn't load '%s': %s (cExtFormatFile::LoadScaled)", fileName.c_str(), e.what());
+ return false;
+ } catch (...) {
+ syslog(LOG_ERR, "glcdgraphics: Couldn't load '%s': Unknown exception caught (cExtFormatFile::LoadScaled)", 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 --git a/glcdgraphics/extformats.h b/glcdgraphics/extformats.h
new file mode 100644
index 0000000..23f6ea2
--- /dev/null
+++ b/glcdgraphics/extformats.h
@@ -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-2012 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ */
+
+#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 --git a/glcdgraphics/font.c b/glcdgraphics/font.c
index 3b71247..db14638 100644
--- a/glcdgraphics/font.c
+++ b/glcdgraphics/font.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#include <stdio.h>
@@ -18,9 +20,7 @@
#include <fcntl.h>
#include <unistd.h>
-#include <cstring>
#include <algorithm>
-#include <cstring>
#include "common.h"
#include "font.h"
@@ -28,6 +28,9 @@
#ifdef HAVE_FREETYPE2
#include <ft2build.h>
#include FT_FREETYPE_H
+#include <iconv.h>
+#else
+#include <string.h>
#endif
namespace GLCD
@@ -64,13 +67,13 @@ private:
protected:
cBitmapCache *next; // next bitmap
cBitmap *ptr;
- int charcode;
+ uint32_t charcode;
public:
cBitmapCache();
~cBitmapCache();
- void PushBack(int ch, cBitmap *bitmap);
- cBitmap *GetBitmap(int ch) const;
+ void PushBack(uint32_t ch, cBitmap *bitmap);
+ cBitmap *GetBitmap(uint32_t ch) const;
};
cBitmapCache::cBitmapCache()
@@ -86,7 +89,7 @@ cBitmapCache::~cBitmapCache()
delete next;
}
-void cBitmapCache::PushBack(int ch, cBitmap *bitmap)
+void cBitmapCache::PushBack(uint32_t ch, cBitmap *bitmap)
{
if (!ptr)
{
@@ -102,7 +105,7 @@ void cBitmapCache::PushBack(int ch, cBitmap *bitmap)
next->PushBack(ch, bitmap);
}
-cBitmap *cBitmapCache::GetBitmap(int ch) const
+cBitmap *cBitmapCache::GetBitmap(uint32_t ch) const
{
if (ptr && charcode==ch)
return ptr;
@@ -124,11 +127,12 @@ cFont::~cFont()
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();
- loadedFontType = lftFNT; //original fonts
+ fontType = ftFNT; //original fonts
+ isutf8 = (encoding == "UTF-8");
FILE * fontFile;
int i;
@@ -148,6 +152,7 @@ bool cFont::LoadFNT(const std::string & fileName)
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;
}
@@ -165,11 +170,32 @@ bool cFont::LoadFNT(const std::string & fileName)
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 HAVE_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<fontHeight * ((charWidth + 7) / 8);num++) {
+ y = (charWidth + 7) / 8;
+ for (loop=0;loop<((charWidth + 7) / 8); loop++) {
+ for (b=0;b<charWidth;b++) {
+ dot=buffer[num+loop] & (0x80 >> 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);
@@ -197,7 +223,7 @@ bool cFont::SaveFNT(const std::string & fileName) const
numChars = 0;
for (i = 0; i < 256; i++)
{
- if (characters[i])
+ if (GetCharacter(i))
{
numChars++;
}
@@ -220,16 +246,20 @@ bool cFont::SaveFNT(const std::string & fileName) const
// 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;
}
}
@@ -245,7 +275,9 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding,
{
// cleanup if we already had a loaded font
Unload();
- loadedFontType = lftFT2; // ft2 fonts
+ fontType = ftFT2; // ft2 fonts
+ isutf8 = (encoding == "UTF-8");
+
#ifdef HAVE_FREETYPE2
if (access(fileName.c_str(), F_OK) != 0)
{
@@ -286,6 +318,40 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding,
// set Size
FT_Set_Char_Size(face, 0, size * 64, 0, 0);
+ // 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)
+ {
+ syslog(LOG_ERR, "cFont::LoadFT2: Iconv encoding not supported: %s", encoding.c_str());
+ error = FT_Done_Face(face);
+ syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error);
+ error = FT_Done_FreeType(library);
+ syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error);
+ return false;
+ }
+ for (int c = 0; c < 256; c++)
+ {
+ char char_buff = c;
+ wchar_t wchar_buff;
+ char * in_buff,* out_buff;
+ size_t in_len, out_len, count;
+
+ in_len = 1;
+ out_len = 4;
+ in_buff = (char *) &char_buff;
+ out_buff = (char *) &wchar_buff;
+ count = iconv(cd, &in_buff, &in_len, &out_buff, &out_len);
+ 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
SetTotalHeight( (face->size->metrics.ascender >> 6) - (face->size->metrics.descender >> 6) );
SetTotalWidth ( face->size->metrics.max_advance >> 6 );
@@ -304,7 +370,7 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding,
#endif
}
-int cFont::Width(int ch) const
+int cFont::Width(uint32_t ch) const
{
const cBitmap *bitmap = GetCharacter(ch);
if (bitmap)
@@ -313,72 +379,32 @@ int cFont::Width(int ch) const
return 0;
}
-void cFont::Utf8CodeAdjustCounter(const std::string & str, int & c, unsigned int & i)
-{
- int c0,c1,c2,c3;
- if (i < str.length())
- {
- 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;
- c0 &=0xff; c1 &=0xff; c2 &=0xff; c3 &=0xff;
-
- if( c0 >= 0xc2 && c0 <= 0xdf && c1 >= 0x80 && c1 <= 0xbf ){ //2 byte UTF-8 sequence found
- i+=1;
- c = ((c0&0x1f)<<6) | (c1&0x3f);
- }else if( (c0 == 0xE0 && c1 >= 0xA0 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf)
- || (c0 >= 0xE1 && c1 <= 0xEC && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf)
- || (c0 == 0xED && c1 >= 0x80 && c1 <= 0x9f && c2 >= 0x80 && c2 <= 0xbf)
- || (c0 >= 0xEE && c0 <= 0xEF && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) ){ //3 byte UTF-8 sequence found
- c = ((c0&0x0f)<<4) | ((c1&0x3f)<<6) | (c2&0x3f);
- i+=2;
- }else if( (c0 == 0xF0 && c1 >= 0x90 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf)
- || (c0 >= 0xF1 && c0 >= 0xF3 && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf)
- || (c0 == 0xF4 && c1 >= 0x80 && c1 <= 0x8f && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf) ){ //4 byte UTF-8 sequence found
- c = ((c0&0x07)<<2) | ((c1&0x3f)<<4) | ((c2&0x3f)<<6) | (c3&0x3f);
- i+=3;
- }
- }
-}
-
int cFont::Width(const std::string & str) const
{
- unsigned int i;
- int sum = 0;
- int symcount=0;
- int c;
-
- for (i = 0; i < str.length(); i++)
- {
- Utf8CodeAdjustCounter(str, c, i);
- symcount++;
- sum += Width(c);
- }
- sum += spaceBetween * (symcount - 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;
- int symcount=0;
- int c;
+ unsigned int symcount=0;
+ uint32_t c;
- for (i = 0; i < str.length() && symcount < len; i++)
+ i = 0;
+ while (i < (unsigned int)str.length() && symcount < len)
{
- Utf8CodeAdjustCounter(str, c, i);
+ encodedCharAdjustCounter(IsUTF8(), str, c, i);
symcount++;
sum += Width(c);
+ i++;
}
sum += spaceBetween * (symcount - 1);
return sum;
}
-int cFont::Height(int ch) const
+int cFont::Height(uint32_t ch) const
{
const cBitmap *bitmap = GetCharacter(ch);
if (bitmap)
@@ -407,10 +433,10 @@ int cFont::Height(const std::string & str, unsigned int len) const
return sum;
}
-const cBitmap * cFont::GetCharacter(int ch) const
+const cBitmap * cFont::GetCharacter(uint32_t ch) const
{
#ifdef HAVE_FREETYPE2
- if ( loadedFontType == lftFT2 ) {
+ if ( fontType == ftFT2 ) {
//lookup in cache
cBitmap *ptr=characters_cache->GetBitmap(ch);
if (ptr)
@@ -419,7 +445,11 @@ const cBitmap * cFont::GetCharacter(int ch) const
FT_Face face = (FT_Face) ft2_face;
FT_UInt glyph_index;
//Get FT char index
- glyph_index = FT_Get_Char_Index(face, ch);
+ 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);
@@ -443,7 +473,8 @@ const cBitmap * cFont::GetCharacter(int ch) const
} else {
// now, fill our pixel data
cBitmap *charBitmap = new cBitmap(face->glyph->advance.x >> 6, TotalHeight());
- charBitmap->Clear();
+ 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++)
@@ -454,7 +485,7 @@ const cBitmap * cFont::GetCharacter(int ch) const
if (pixel)
charBitmap->DrawPixel((face->glyph->metrics.horiBearingX >> 6) + x,
(face->size->metrics.ascender >> 6) - (face->glyph->metrics.horiBearingY >> 6) + y,
- GLCD::clrBlack);
+ /*GLCD::clrBlack*/ cColor::Black);
}
bufPtr += face->glyph->bitmap.pitch;
}
@@ -475,7 +506,7 @@ const cBitmap * cFont::GetCharacter(int ch) const
void cFont::SetCharacter(char ch, cBitmap * bitmapChar)
{
#ifdef HAVE_FREETYPE2
- if ( loadedFontType == lftFT2 ) {
+ if ( fontType == ftFT2 ) {
syslog(LOG_ERR, "cFont::SetCharacter: is not supported with FreeType2 fonts!!!");
return;
}
@@ -503,12 +534,12 @@ void cFont::Init()
{
characters[i] = NULL;
}
- loadedFontType = lftFNT;
#ifdef HAVE_FREETYPE2
ft2_library = NULL;
ft2_face = NULL;
characters_cache = NULL;
#endif
+ fontType = ftFNT;
}
void cFont::Unload()
@@ -539,97 +570,84 @@ void cFont::WrapText(int Width, int Height, std::string & Text,
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 --git a/glcdgraphics/font.h b/glcdgraphics/font.h
index f3427d5..a77de14 100644
--- a/glcdgraphics/font.h
+++ b/glcdgraphics/font.h
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#ifndef _GLCDGRAPHICS_FONT_H_
@@ -28,12 +30,12 @@ class cBitmapCache;
class cFont
{
public:
- enum eLoadedFntType
+ enum eFontType
{
// native glcd font loaded
- lftFNT,
+ ftFNT,
// freetype2 font loaded
- lftFT2
+ ftFT2
};
private:
int totalWidth;
@@ -43,7 +45,10 @@ private:
int lineHeight;
cBitmap * characters[256];
- eLoadedFntType loadedFontType;
+ eFontType fontType;
+
+ bool isutf8;
+ wchar_t iconv_lut[256]; // lookup table needed if encoding != UTF-8
cBitmapCache *characters_cache;
void *ft2_library; //FT_Library
@@ -55,7 +60,7 @@ public:
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);
@@ -71,20 +76,19 @@ public:
void SetSpaceBetween(int width) { spaceBetween = width; };
void SetLineHeight(int height) { lineHeight = height; };
- int Width(int 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(int 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(int 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 <std::string> & Lines, int * TextWidth = NULL) const;
-
- static void Utf8CodeAdjustCounter(const std::string & str, int & c, unsigned int & i);
+ bool IsUTF8(void) const { return isutf8; }
};
} // end of namespace
diff --git a/glcdgraphics/glcd.c b/glcdgraphics/glcd.c
index e79b6b8..6e97208 100644
--- a/glcdgraphics/glcd.c
+++ b/glcdgraphics/glcd.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#include <stdio.h>
@@ -67,7 +69,7 @@ bool cGLCDFile::Load(cImage & image, const string & fileName)
fp = fopen(fileName.c_str(), "rb");
if (!fp)
{
- syslog(LOG_ERR, "glcdgraphics: open %s failed (cGLCDFile::Load).", fileName.c_str());
+ syslog(LOG_ERR, "glcdgraphics: opening of '%s' failed (cGLCDFile::Load).", fileName.c_str());
return false;
}
@@ -96,7 +98,7 @@ bool cGLCDFile::Load(cImage & image, const string & fileName)
// check header sign
if (strncmp(sign, kGLCDFileSign, 3) != 0)
{
- syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong header (cGLCDFile::Load).", fileName.c_str());
+ syslog(LOG_ERR, "glcdgraphics: loading of '%s' failed, wrong header (cGLCDFile::Load).", fileName.c_str());
fclose(fp);
return false;
}
@@ -112,7 +114,7 @@ bool cGLCDFile::Load(cImage & image, const string & fileName)
height = (buf[3] << 8) | buf[2];
if (width == 0 || height == 0)
{
- syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong header (cGLCDFile::Load).", fileName.c_str());
+ syslog(LOG_ERR, "glcdgraphics: loading of '%s' failed, wrong header (cGLCDFile::Load).", fileName.c_str());
fclose(fp);
return false;
}
@@ -124,7 +126,7 @@ bool cGLCDFile::Load(cImage & image, const string & fileName)
// check file length
if (fileSize != (long) (height * ((width + 7) / 8) + 8))
{
- syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong size (cGLCDFile::Load).", fileName.c_str());
+ syslog(LOG_ERR, "glcdgraphics: loading of '%s' failed, wrong size (cGLCDFile::Load).", fileName.c_str());
fclose(fp);
return false;
}
@@ -134,7 +136,7 @@ bool cGLCDFile::Load(cImage & image, const string & fileName)
// read count and delay
if (fread(buf, 6, 1, fp) != 1)
{
- syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong header (cGLCDFile::Load).", fileName.c_str());
+ syslog(LOG_ERR, "glcdgraphics: loading of '%s' failed, wrong header (cGLCDFile::Load).", fileName.c_str());
fclose(fp);
return false;
}
@@ -144,7 +146,7 @@ bool cGLCDFile::Load(cImage & image, const string & fileName)
if (count == 0 ||
fileSize != (long) (count * (height * ((width + 7) / 8)) + 14))
{
- syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong size (cGLCDFile::Load).", fileName.c_str());
+ syslog(LOG_ERR, "glcdgraphics: loading of '%s' failed, wrong size (cGLCDFile::Load).", fileName.c_str());
fclose(fp);
return false;
}
@@ -154,7 +156,7 @@ bool cGLCDFile::Load(cImage & image, const string & fileName)
}
else
{
- syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong header (cGLCDFile::Load).", fileName.c_str());
+ syslog(LOG_ERR, "glcdgraphics: loading of '%s' failed, wrong header (cGLCDFile::Load).", fileName.c_str());
fclose(fp);
return false;
}
@@ -163,32 +165,55 @@ bool cGLCDFile::Load(cImage & image, const string & fileName)
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 HAVE_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());
+ syslog(LOG_DEBUG, "glcdgraphics: image '%s' loaded.", fileName.c_str());
return true;
}
@@ -209,7 +234,7 @@ bool cGLCDFile::Save(cImage & image, const string & fileName)
fp = fopen(fileName.c_str(), "wb");
if (!fp)
{
- syslog(LOG_ERR, "glcdgraphics: open %s failed (cGLCDFile::Save).", fileName.c_str());
+ syslog(LOG_ERR, "glcdgraphics: opening '%s' failed (cGLCDFile::Save).", fileName.c_str());
return false;
}
@@ -260,7 +285,7 @@ bool cGLCDFile::Save(cImage & image, const string & fileName)
{
if (bitmap->Width() == width && bitmap->Height() == height)
{
- if (fwrite(bitmap->Data(), height * ((width + 7) / 8), 1, fp) != 1)
+ if (fwrite( cBitmap::ConvertTo1BPP(*bitmap), height * ((width + 7) / 8), 1, fp) != 1)
{
fclose(fp);
return false;
@@ -270,7 +295,7 @@ bool cGLCDFile::Save(cImage & image, const string & fileName)
}
fclose(fp);
- syslog(LOG_DEBUG, "glcdgraphics: image %s saved.", fileName.c_str());
+ syslog(LOG_DEBUG, "glcdgraphics: image '%s' saved.", fileName.c_str());
return true;
}
diff --git a/glcdgraphics/image.c b/glcdgraphics/image.c
index 72003b1..1240b80 100644
--- a/glcdgraphics/image.c
+++ b/glcdgraphics/image.c
@@ -10,11 +10,17 @@
* to the COPYING file distributed with this package.
*
* (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#include "bitmap.h"
#include "image.h"
+#include "imagefile.h"
+#include "glcd.h"
+#include "pbm.h"
+#include "extformats.h"
+#include <string.h>
namespace GLCD
{
@@ -64,4 +70,187 @@ void cImage::Clear()
lastChange = 0;
}
+
+uint32_t cImage::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 cImage::Scale(uint16_t scalew, uint16_t scaleh, bool AntiAlias)
+{
+ if (! (scalew || scaleh) )
+ return false;
+
+ unsigned int orig_w = Width();
+ unsigned int orig_h = Height();
+
+ // one out of scalew/h == 0 ? -> auto aspect ratio
+ if (scalew && ! scaleh) {
+ scaleh = (uint16_t)( ((uint32_t)scalew * (uint32_t)orig_h) / (uint32_t)orig_w );
+ } else if (!scalew && scaleh) {
+ scalew = (uint16_t)( ((uint32_t)scaleh * (uint32_t)orig_w) / (uint32_t)orig_h );
+ }
+
+ 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)orig_w;
+ FactorY = (double)scaleh / (double)orig_h;
+ RatioX = (orig_w << 16) / scalew;
+ RatioY = (orig_h << 16) / scaleh;
+ } else {
+ FactorX = (double)scalew / (double)(orig_w-1);
+ FactorY = (double)scaleh / (double)(orig_h-1);
+ RatioX = ((orig_w-1) << 16) / scalew;
+ RatioY = ((orig_h-1) << 16) / scaleh;
+ }
+
+ bool downscale = (!AntiAlias || (FactorX <= 1.0 && FactorY <= 1.0));
+
+ for (unsigned int frame = 0; frame < Count() ; frame ++ ) {
+ cBitmap *b = new cBitmap(scalew, scaleh, GRAPHLCD_Transparent);
+
+ cBitmap *currFrame = GetBitmap(frame);
+
+ b->SetMonochrome(currFrame->IsMonochrome());
+
+ 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) * orig_w;
+ 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 this image
+ unsigned int temp_delay = Delay();
+ Clear();
+ // set new resolution
+ SetWidth(scalew);
+ SetHeight(scaleh);
+ SetDelay(temp_delay);
+ // re-add bitmaps from scaled image container
+ cBitmap * b;
+ cBitmap * tempb;
+ for (unsigned int frame = 0; frame < tempImg.Count(); frame ++) {
+ tempb = tempImg.GetBitmap(frame);
+ b = new cBitmap(scalew, scaleh, (uint32_t*)tempb->Data());
+ b->SetMonochrome(tempb->IsMonochrome());
+ AddBitmap(b);
+ }
+ return true;
+}
+
+
+/* static methods */
+bool cImage::LoadImage(cImage & image, const std::string & fileName) {
+ const std::string fext = GetFilenameExtension(fileName);
+ cImageFile* imgFile = NULL;
+ bool result = true;
+
+ if (fext == "PBM") {
+ imgFile = new cPBMFile();
+ } else if (fext == "GLCD") {
+ imgFile = new cGLCDFile();
+ } else {
+ imgFile = new cExtFormatFile();
+ }
+
+ uint16_t scale_w = 0;
+ uint16_t scale_h = 0;
+
+ if (!imgFile || (imgFile->LoadScaled(image, fileName, scale_w, scale_h) == false) )
+ result = false;
+
+ if (imgFile) delete imgFile;
+ return result;
+}
+
+
+bool cImage::SaveImage(cImage & image, const std::string & fileName) {
+ const std::string fext = GetFilenameExtension(fileName);
+ cImageFile* imgFile = NULL;
+ bool result = false;
+
+ if (fext == "PBM") {
+ imgFile = new cPBMFile();
+ } else if (fext == "GLCD") {
+ imgFile = new cGLCDFile();
+ } else {
+ imgFile = new cExtFormatFile();
+ }
+ if ( imgFile && imgFile->Save(image, fileName) )
+ result = true;
+
+ if (imgFile) delete imgFile;
+ return result;
+}
+
+
+const std::string cImage::GetFilenameExtension(const std::string & fileName) {
+ size_t pos = fileName.find_last_of('.');
+ std::string ext = "";
+ if (pos != std::string::npos) {
+ ext = fileName.substr(pos+1);
+ for (size_t i = 0; i < ext.size(); i++)
+ ext[i] = toupper(ext[i]);
+ }
+ return ext;
+}
+
+
} // end of namespace
diff --git a/glcdgraphics/image.h b/glcdgraphics/image.h
index 888d942..f594886 100644
--- a/glcdgraphics/image.h
+++ b/glcdgraphics/image.h
@@ -10,6 +10,7 @@
* to the COPYING file distributed with this package.
*
* (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#ifndef _GLCDGRAPHICS_IMAGE_H_
@@ -18,6 +19,7 @@
#include <stdint.h>
#include <vector>
+#include <string>
namespace GLCD
{
@@ -33,6 +35,8 @@ private:
unsigned int curBitmap;
uint64_t lastChange;
std::vector <cBitmap *> bitmaps;
+
+ uint32_t Blend(uint32_t fgcol, uint32_t bgcol, uint8_t level, double antiAliasGranularity = 0.0) const;
public:
cImage();
~cImage();
@@ -51,6 +55,12 @@ public:
cBitmap * GetBitmap() const;
void AddBitmap(cBitmap * Bitmap) { bitmaps.push_back(Bitmap); }
void Clear();
+
+ bool Scale(uint16_t scalew, uint16_t scaleh, bool AntiAlias = false);
+
+ static bool LoadImage(cImage & image, const std::string & fileName);
+ static bool SaveImage(cImage & image, const std::string & fileName);
+ static const std::string GetFilenameExtension(const std::string & fileName);
};
} // end of namespace
diff --git a/glcdgraphics/imagefile.c b/glcdgraphics/imagefile.c
index 2f56f4a..0f9ec25 100644
--- a/glcdgraphics/imagefile.c
+++ b/glcdgraphics/imagefile.c
@@ -6,11 +6,13 @@
* This file is released under the GNU General Public License. Refer
* to the COPYING file distributed with this package.
*
- * (c) 2006 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2006 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#include "image.h"
#include "imagefile.h"
+#include "bitmap.h"
namespace GLCD
{
@@ -32,4 +34,21 @@ bool cImageFile::Save(cImage & image, const std::string & fileName)
return false;
}
+
+
+bool cImageFile::LoadScaled(cImage & image, const std::string & fileName, uint16_t & scalew, uint16_t & scaleh)
+{
+ if (Load(image, fileName)) {
+ if (scalew || scaleh) {
+ return image.Scale(scalew, scaleh, true);
+ } else {
+ return true;
+ }
+ } else {
+ scalew = 0;
+ scaleh = 0;
+ return false;
+ }
+}
+
} // end of namespace
diff --git a/glcdgraphics/imagefile.h b/glcdgraphics/imagefile.h
index bf5ff5e..fd7dbcc 100644
--- a/glcdgraphics/imagefile.h
+++ b/glcdgraphics/imagefile.h
@@ -6,7 +6,8 @@
* This file is released under the GNU General Public License. Refer
* to the COPYING file distributed with this package.
*
- * (c) 2006 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2006 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
*/
#ifndef _GLCDGRAPHICS_IMAGEFILE_H_
@@ -26,6 +27,10 @@ public:
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 --git a/glcdgraphics/pbm.c b/glcdgraphics/pbm.c
index 2bca3ef..3bf94c1 100644
--- a/glcdgraphics/pbm.c
+++ b/glcdgraphics/pbm.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2006-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#include <stdio.h>
@@ -113,18 +115,35 @@ bool cPBMFile::Load(cImage & image, const std::string & fileName)
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
{
@@ -133,7 +152,7 @@ bool cPBMFile::Load(cImage & image, const std::string & fileName)
return false;
}
fclose(pbmFile);
- syslog(LOG_DEBUG, "glcdgraphics: image %s loaded.", fileName.c_str());
+ syslog(LOG_DEBUG, "glcdgraphics: image '%s' loaded.", fileName.c_str());
return true;
}
@@ -143,6 +162,9 @@ bool cPBMFile::Save(cImage & image, const std::string & fileName)
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,34 +172,71 @@ bool cPBMFile::Save(cImage & image, const std::string & fileName)
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(rawdata, rawdata_size, 1, fp);
}
fclose(fp);
+ delete[] rawdata;
+ rawdata = NULL;
}
}
else
{
uint16_t i;
char tmpStr[256];
+ size_t pos = fileName.find_last_of('.');
+ std::string fileExt = "";
+ std::string fileBase = fileName;
+ if (pos != std::string::npos) {
+ fileExt = fileName.substr(pos);
+ fileBase = fileName.substr(0, fileName.length() - fileExt.length());
+ }
for (i = 0; i < image.Count(); i++)
{
- sprintf(tmpStr, "%.248s.%05d", fileName.c_str(), i);
+ sprintf(tmpStr, "%.244s-%05d%s", fileBase.c_str(), i, fileExt.c_str());
fp = fopen(tmpStr, "wb");
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(rawdata, rawdata_size, 1, fp);
}
fclose(fp);
+ delete[] rawdata;
+ rawdata = NULL;
}
}
}
diff --git a/glcdskin/Makefile b/glcdskin/Makefile
index 9b3b867..90fe310 100644
--- a/glcdskin/Makefile
+++ b/glcdskin/Makefile
@@ -7,8 +7,8 @@
CXXFLAGS += -fPIC
-VERMAJOR = 1
-VERMINOR = 0
+VERMAJOR = 2
+VERMINOR = 1
VERMICRO = 0
BASENAME = libglcdskin.so
@@ -19,17 +19,23 @@ OBJS = cache.o config.o display.o font.o function.o object.o parser.o skin.o str
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
+
+ifdef HAVE_FONTCONFIG
+ LIBS += -lfontconfig
+ DEFINES += -DHAVE_FONTCONFIG
+endif
+
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -I.. -c $(DEFINES) $(INCLUDES) $<
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -I.. -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
-MAKEDEP = g++ -MM -MG
-DEPFILE = .dependencies
-$(DEPFILE): Makefile
- @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+DEPFILE = $(OBJS:%.o=%.d)
-include $(DEPFILE)
diff --git a/glcdskin/cache.c b/glcdskin/cache.c
index 83629a0..f0543d9 100644
--- a/glcdskin/cache.c
+++ b/glcdskin/cache.c
@@ -12,20 +12,25 @@
#include <glcdgraphics/image.h>
#include <glcdgraphics/glcd.h>
#include <glcdgraphics/pbm.h>
+#include <glcdgraphics/extformats.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
+
#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(cSkin * Parent, int Size)
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 <cImageItem *>::iterator it;
cImageItem * item;
uint64_t maxCounter;
std::vector <cImageItem *>::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 @@ cImage * cImageCache::Get(const std::string & path)
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 @@ cImageItem * cImageCache::LoadImage(const std::string & path)
}
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 @@ cImageItem * cImageCache::LoadImage(const std::string & path)
}
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 --git a/glcdskin/cache.h b/glcdskin/cache.h
index 925ebcc..533f009 100644
--- a/glcdskin/cache.h
+++ b/glcdskin/cache.h
@@ -29,11 +29,13 @@ private:
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 @@ private:
cSkin * skin;
size_t size;
std::vector <cImageItem *> images;
+ std::vector <std::string> 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 --git a/glcdskin/config.h b/glcdskin/config.h
index ce68513..eede1cc 100644
--- a/glcdskin/config.h
+++ b/glcdskin/config.h
@@ -17,12 +17,15 @@
#include <stdint.h>
+#include "../glcddrivers/driver.h"
+
namespace GLCD
{
class cType;
class cFont;
struct tSkinToken;
+class cDriver;
class cSkinConfig
{
@@ -37,6 +40,7 @@ public:
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 --git a/glcdskin/display.c b/glcdskin/display.c
index a926bd9..6f7a673 100644
--- a/glcdskin/display.c
+++ b/glcdskin/display.c
@@ -39,6 +39,21 @@ bool cSkinDisplay::NeedsUpdate(uint64_t CurrentTime)
}
+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 --git a/glcdskin/display.h b/glcdskin/display.h
index 3b19b0c..ec0ee8b 100644
--- a/glcdskin/display.h
+++ b/glcdskin/display.h
@@ -45,6 +45,8 @@ public:
void Render(cBitmap * screen);
bool NeedsUpdate(uint64_t CurrentTime);
+
+ std::string CheckAction(cGLCDEvent * ev);
};
class cSkinDisplays: public std::vector<cSkinDisplay *>
diff --git a/glcdskin/font.c b/glcdskin/font.c
index 731b1fa..a8c22c8 100644
--- a/glcdskin/font.c
+++ b/glcdskin/font.c
@@ -6,9 +6,16 @@
#include "skin.h"
#include "function.h"
+#ifdef HAVE_FONTCONFIG
+ #include <fontconfig/fontconfig.h>
+#endif
+
namespace GLCD
{
+int cSkinFont::FcInitCount = 0;
+
+
cSkinFont::cSkinFont(cSkin * Parent)
: mSkin(Parent),
mCondition(NULL),
@@ -17,36 +24,114 @@ cSkinFont::cSkinFont(cSkin * Parent)
{
}
+cSkinFont::~cSkinFont(void) {
+#ifdef HAVE_FONTCONFIG
+ cSkinFont::FcInitCount --;
+ if (cSkinFont::FcInitCount <= 0) {
+ FcFini();
+ }
+#endif
+}
+
bool cSkinFont::ParseUrl(const std::string & url)
{
- std::string::size_type count = std::string::npos;
+ bool isFontconfig = false;
+ std::string rawfont = "";
if (url.find("fnt:") == 0)
{
mType = ftFNT;
+ rawfont = url.substr(4);
mSize = 0;
}
else if (url.find("ft2:") == 0)
{
mType = ftFT2;
- std::string::size_type pos = url.find(":", 4);
+ rawfont = url.substr(4);
+ std::string::size_type pos = rawfont.find(":");
if (pos == std::string::npos)
{
syslog(LOG_ERR, "cFontElement::Load(): No font size specified in %s\n", url.c_str());
return false;
}
- std::string tmp = url.substr(pos + 1);
+ std::string tmp = rawfont.substr(pos + 1);
mSize = atoi(tmp.c_str());
- count = pos - 4;
+ rawfont = rawfont.substr(0,pos);
}
+#ifdef HAVE_FONTCONFIG
+ else if (url.find("fc:") == 0)
+ {
+ mType = ftFT2;
+ isFontconfig = true;
+ rawfont = url.substr(3);
+
+ std::string::size_type pos = rawfont.find(":size=");
+ if (pos == std::string::npos) {
+ syslog(LOG_ERR, "cFontElement::Load(): No font size specified in %s (e.g.: 'size=<fontsize>')\n", url.c_str());
+ return false;
+ }
+ std::string sizeterm = rawfont.substr(pos + 1);
+
+ pos = sizeterm.find(":"); // find terminating :
+ if (pos != std::string::npos) {
+ sizeterm = sizeterm.substr(0, pos);
+ }
+
+ pos = sizeterm.find("=");
+ if (pos == std::string::npos) {
+ syslog(LOG_ERR, "cFontElement::Load(): Invalid size term '%s' (must be 'size=<fontsize>')\n", url.c_str());
+ return false;
+ }
+
+ std::string tmp = sizeterm.substr(pos + 1);
+ mSize = atoi(tmp.c_str());
+ if (mSize <= 0) {
+ syslog(LOG_ERR, "cFontElement::Load(): Invalid font size in '%s'\n", url.c_str());
+ return false;
+ }
+
+ if (cSkinFont::FcInitCount <= 0) {
+ FcInit();
+ }
+ cSkinFont::FcInitCount ++;
+
+ FcPattern *pat = FcNameParse((FcChar8 *) rawfont.c_str() );
+ rawfont = "";
+ FcPatternAddBool(pat, FC_SCALABLE, FcTrue);
+ FcConfigSubstitute(NULL, pat, FcMatchPattern);
+ FcDefaultSubstitute(pat);
+ FcResult result;
+ FcFontSet *fontset = FcFontSort(NULL, pat, FcFalse, NULL, &result);
+ if (fontset) {
+ FcBool scalable;
+ for (int i = 0; i < fontset->nfont; i++) {
+ FcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable);
+ if (scalable) {
+ FcChar8 *s = NULL;
+ FcPatternGetString(fontset->fonts[i], FC_FILE, 0, &s);
+ rawfont = (char *)s; // set font path
+ break;
+ }
+ }
+ FcFontSetDestroy(fontset);
+ }
+ FcPatternDestroy(pat);
+
+ if (rawfont == "") {
+ syslog(LOG_ERR, "cFontElement::Load(): No usable font found for '%s'\n", url.c_str());
+ return false;
+ }
+ }
+#endif
else
{
syslog(LOG_ERR, "cSkinFont::ParseUrl(): Unknown font type in %s\n", url.c_str());
return false;
}
- if (url[4] == '/' || url.find("./") == 4 || url.find("../") == 4)
- mFile = url.substr(4, count);
+ if (isFontconfig || (rawfont[0] == '/' || rawfont.find("./") == 0 || rawfont.find("../") == 0)) {
+ mFile = rawfont;
+ }
else
{
// first try skin's font dir
@@ -57,7 +142,7 @@ bool cSkinFont::ParseUrl(const std::string & url)
mFile += '/';
}
mFile += "fonts/";
- mFile += url.substr(4, count);
+ mFile += rawfont;
#if (__GNUC__ < 3)
std::ifstream f(mFile.c_str(), std::ios::in | std::ios::binary);
#else
@@ -76,7 +161,7 @@ bool cSkinFont::ParseUrl(const std::string & url)
if (mFile[mFile.length() - 1] != '/')
mFile += '/';
}
- mFile += url.substr(4, count);
+ mFile += rawfont;
}
}
diff --git a/glcdskin/font.h b/glcdskin/font.h
index d11fa50..80e5556 100644
--- a/glcdskin/font.h
+++ b/glcdskin/font.h
@@ -49,8 +49,11 @@ private:
cSkinDisplay mDummyDisplay;
cSkinObject mDummyObject;
+ static int FcInitCount;
+
public:
cSkinFont(cSkin * Parent);
+ ~cSkinFont(void);
bool ParseUrl(const std::string & Text);
bool ParseCondition(const std::string & Text);
diff --git a/glcdskin/function.c b/glcdskin/function.c
index 8582ad5..a2d58ca 100644
--- a/glcdskin/function.c
+++ b/glcdskin/function.c
@@ -22,7 +22,7 @@ namespace GLCD
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 @@ static const char * Internals[] =
"FontTextHeight",
"ImageWidth",
"ImageHeight",
+ "QueryFeature",
NULL
};
@@ -74,7 +75,7 @@ cSkinFunction::~cSkinFunction()
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 @@ bool cSkinFunction::Parse(const std::string & Text)
|| (*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 @@ bool cSkinFunction::Parse(const std::string & Text)
// 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 @@ bool cSkinFunction::Parse(const std::string & Text)
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 @@ bool cSkinFunction::Parse(const std::string & Text)
}
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 @@ bool cSkinFunction::Parse(const std::string & Text)
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 @@ bool cSkinFunction::Parse(const std::string & Text)
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 @@ bool cSkinFunction::Parse(const std::string & Text)
params = -1;
break;
+ case fun_equal:
case fun_eq:
case fun_ne:
case fun_gt:
@@ -247,13 +263,17 @@ bool cSkinFunction::Parse(const std::string & Text)
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 @@ bool cSkinFunction::Parse(const std::string & Text)
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 @@ cType cSkinFunction::Evaluate(void) const
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,23 +404,24 @@ cType cSkinFunction::Evaluate(void) const
}
return false;
+ case fun_equal:
case fun_eq:
- return mParams[0]->Evaluate() == mParams[1]->Evaluate();
+ return (std::string) mParams[0]->Evaluate() == (std::string) mParams[1]->Evaluate();
case fun_ne:
- return mParams[0]->Evaluate() != mParams[1]->Evaluate();
+ return (std::string) mParams[0]->Evaluate() != (std::string) mParams[1]->Evaluate();
case fun_gt:
- return mParams[0]->Evaluate() > mParams[1]->Evaluate();
+ return (int) mParams[0]->Evaluate() > (int) mParams[1]->Evaluate();
case fun_lt:
- return mParams[0]->Evaluate() < mParams[1]->Evaluate();
+ return (int) mParams[0]->Evaluate() < (int) mParams[1]->Evaluate();
case fun_ge:
- return mParams[0]->Evaluate() >= mParams[1]->Evaluate();
+ return (int) mParams[0]->Evaluate() >= (int) mParams[1]->Evaluate();
case fun_le:
- return mParams[0]->Evaluate() <= mParams[1]->Evaluate();
+ return (int) mParams[0]->Evaluate() <= (int) mParams[1]->Evaluate();
case fun_file:
return FunFile(mParams[0]->Evaluate());
@@ -443,9 +479,18 @@ cType cSkinFunction::Evaluate(void) const
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 --git a/glcdskin/function.h b/glcdskin/function.h
index 4b3732f..16bcfb7 100644
--- a/glcdskin/function.h
+++ b/glcdskin/function.h
@@ -47,6 +47,7 @@ public:
fun_not = INTERNAL,
fun_and,
fun_or,
+ fun_equal,
fun_eq,
fun_gt,
fun_lt,
@@ -70,7 +71,9 @@ public:
funFontTextHeight,
funImageWidth,
- funImageHeight
+ funImageHeight,
+
+ funQueryFeature
};
private:
@@ -94,7 +97,7 @@ public:
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 --git a/glcdskin/object.c b/glcdskin/object.c
index ab00a44..796e436 100644
--- a/glcdskin/object.c
+++ b/glcdskin/object.c
@@ -4,6 +4,8 @@
#include "cache.h"
#include "function.h"
+#include <typeinfo>
+
namespace GLCD
{
@@ -19,18 +21,27 @@ static const std::string ObjectNames[] =
"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 @@ cSkinObject::cSkinObject(cSkinDisplay * Parent)
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 @@ cSkinObject::cSkinObject(cSkinDisplay * Parent)
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 @@ cSkinObject::cSkinObject(const cSkinObject & Src)
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 @@ cSkinObject::cSkinObject(const cSkinObject & Src)
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 @@ bool cSkinObject::ParseType(const std::string & Text)
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 @@ bool cSkinObject::ParseVerticalAlignment(const std::string & Text)
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 @@ bool cSkinObject::ParseIntParam(const std::string &Text, int & Param)
return true;
}
+#if 0
bool cSkinObject::ParseWidth(const std::string &Text)
{
int w;
@@ -214,6 +313,7 @@ bool cSkinObject::ParseHeight(const std::string &Text)
}
return false;
}
+#endif
bool cSkinObject::ParseFontFace(const std::string & Text)
{
@@ -292,16 +392,33 @@ const std::string & cSkinObject::TypeName(void) const
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
{
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
mCurrText = text;
mScrollLoopReached = false;
mLastChange = timestamp;
+ mMultilineScrollPosition = 0;
}
if (mMultiline)
@@ -492,7 +805,24 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
mScrollLoopReached = true; // avoid check in NeedsUpdate()
std::vector <std::string> 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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
{
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
currScrollTime = mScrollTime;
if (currScrollLoopMode > 0 && (!mScrollLoopReached || mScrollOffset) &&
- ((int)(timestamp-mLastChange) >= currScrollTime)
+ ((uint32_t)(timestamp-mLastChange) >= (uint32_t)currScrollTime)
)
{
if (mScrollLoopReached)
@@ -615,22 +958,31 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
}
}
}
+ screen->DrawBitmap(Pos().x, Pos().y, *pane, cColor::White, cColor::Transparent);
+ delete pane;
}
break;
}
@@ -651,6 +1005,44 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
// 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 <std::string> 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 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
{
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 @@ bool cSkinObject::NeedsUpdate(uint64_t CurrentTime)
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 @@ bool cSkinObject::NeedsUpdate(uint64_t CurrentTime)
}
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 @@ bool cSkinObject::NeedsUpdate(uint64_t CurrentTime)
if ( (text != mCurrText) ||
( (currScrollLoopMode > 0) && (!mScrollLoopReached || mScrollOffset) &&
- ((int)(CurrentTime-mLastChange) >= currScrollTime)
+ ((uint32_t)(CurrentTime-mLastChange) >= (uint32_t)currScrollTime)
)
)
{
@@ -788,6 +1189,71 @@ bool cSkinObject::NeedsUpdate(uint64_t CurrentTime)
}
+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(cTouchEvent))) {
+ cTouchEvent * stev = (cTouchEvent*)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 --git a/glcdskin/object.h b/glcdskin/object.h
index 0dd996d..cb2f180 100644
--- a/glcdskin/object.h
+++ b/glcdskin/object.h
@@ -24,6 +24,8 @@
#include "type.h"
#include "string.h"
+#include <glcddrivers/driver.h>
+
namespace GLCD
{
@@ -58,6 +60,54 @@ enum eTextVerticalAlignment
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<std::string,std::string> & attrs);
@@ -77,6 +127,7 @@ public:
text,
scrolltext,
scrollbar,
+ button,
block,
list,
item,
@@ -87,9 +138,16 @@ private:
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 @@ private:
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 @@ private:
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 @@ private:
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 <list>
@@ -130,14 +199,17 @@ public:
~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 @@ public:
// 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<cSkinObject *>
diff --git a/glcdskin/parser.c b/glcdskin/parser.c
index d42cfb8..5aa5515 100644
--- a/glcdskin/parser.c
+++ b/glcdskin/parser.c
@@ -16,28 +16,33 @@
#include <vector>
#include <string>
+#include <clocale>
+
#include "parser.h"
#include "xml.h"
#include "skin.h"
+/* workaround for thread-safe parsing */
+#include <pthread.h>
+
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 @@ namespace GLCD
#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 @@ namespace GLCD
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 @@ namespace GLCD
#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 @@ namespace GLCD
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 @@ namespace GLCD
#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 @@ namespace GLCD
#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 @@ namespace GLCD
#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 std::vector<std::string> context;
static cSkin * skin = NULL;
static cSkinFont * font = NULL;
static cSkinVariable * variable = NULL;
+static cSkinVariable * variable_default = NULL;
static cSkinDisplay * display = NULL;
static std::vector <cSkinObject *> 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<std::string,std::string> & 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<std::string,std::string> & 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 @@ bool StartElem(const std::string & name, std::map<std::string,std::string> & att
}
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 @@ bool StartElem(const std::string & name, std::map<std::string,std::string> & att
--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 @@ bool CharData(const std::string & text)
//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 @@ bool EndElem(const std::string & name)
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 @@ bool EndElem(const std::string & name)
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 --git a/glcdskin/parser.h b/glcdskin/parser.h
index d7d7f63..855c626 100644
--- a/glcdskin/parser.h
+++ b/glcdskin/parser.h
@@ -16,13 +16,23 @@
#include <string>
+// 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 --git a/glcdskin/skin.c b/glcdskin/skin.c
index a7facdd..122b162 100644
--- a/glcdskin/skin.c
+++ b/glcdskin/skin.c
@@ -21,6 +21,8 @@ cSkin::cSkin(cSkinConfig & Config, const std::string & Name)
name(Name)
{
mImageCache = new cImageCache(this, 100);
+ tsEvalTick = 0;
+ tsEvalSwitch = 0;
}
cSkin::~cSkin(void)
@@ -79,4 +81,16 @@ cSkinVariable * cSkin::GetVariable(const std::string & Id)
}
+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 --git a/glcdskin/skin.h b/glcdskin/skin.h
index b2d8496..048c193 100644
--- a/glcdskin/skin.h
+++ b/glcdskin/skin.h
@@ -43,6 +43,8 @@ private:
cSkinDisplays displays;
cSkinVariables mVariables;
cImageCache * mImageCache;
+ uint64_t tsEvalTick;
+ uint64_t tsEvalSwitch;
public:
cSkin(cSkinConfig & Config, const std::string & Name);
@@ -61,6 +63,16 @@ public:
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 --git a/glcdskin/string.c b/glcdskin/string.c
index dc9d9dc..3966449 100644
--- a/glcdskin/string.c
+++ b/glcdskin/string.c
@@ -55,18 +55,23 @@ std::string tSkinToken::Token(const tSkinToken & Token)
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 @@ cSkinString::~cSkinString()
break;
}
}
+#endif
}
+#if 0
void cSkinString::Reparse(void)
{
tStringList::iterator it = mStrings.begin();
@@ -84,6 +91,14 @@ void cSkinString::Reparse(void)
(*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 cSkinString::Parse(const std::string & Text, bool Translate)
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 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
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 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
}
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 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
{
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 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
}
if (inToken) {
- syslog(LOG_ERR, "ERROR: Expecting '}' in token");
+ syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Expecting '}' in token");
return false;
}
@@ -214,19 +244,92 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
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);
+ if (idxend != std::string::npos) {
+ 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());
+ } else {
+ result_trans.append (result_raw.substr(idxstart, idxend-idxstart)); // no variable found: print as raw text
+ }
+ idxstart = idxend+1;
+ pos = idxstart;
+ } else {
+ result_trans.append ("#"); // no closing '#' -> print # as raw text
+ idxstart ++;
+ 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;
+ }
+
+ // look for $(..)$-expressions
+ result_raw = result_trans;
+ result_trans = "";
+ idxstart = 0;
+ pos = 0;
+ bool err = false;
+ while ( !err && ((idxstart = result_raw.find("$(", idxstart)) != std::string::npos) ) {
+ result_trans.append (result_raw.substr(pos, idxstart - pos) );
+ idxend = result_raw.find(")$", idxstart + 2);
+ if ( idxend == std::string::npos ) { // no $) found: ignore leading $( and pass rest of whole string unparsed
+ result_trans.append(result_raw.substr(pos));
+ err = true;
+ } else {
+ std::string func = result_raw.substr( idxstart + 2, idxend - idxstart - 2 );
+ cSkinFunction *result = new cSkinFunction(mObject);
+ if (result->Parse(func, true)) {
+ std::string result_rescan = (std::string)result->Evaluate();
+ if (result_rescan != "")
+ result_trans.append( result_rescan );
+ }
+ delete result;
+
+ idxstart = idxend + 2;
+ pos = idxstart;
+ }
+ }
+ result_trans.append( result_raw.substr(pos) );
+ return result_trans;
}
} // end of namespace
diff --git a/glcdskin/string.h b/glcdskin/string.h
index b75fa11..20c517c 100644
--- a/glcdskin/string.h
+++ b/glcdskin/string.h
@@ -86,8 +86,10 @@ class cSkin;
class cSkinString
{
private:
+#if 0
typedef std::vector<cSkinString*> tStringList;
static tStringList mStrings;
+#endif
cSkinObject * mObject;
cSkin * mSkin;
@@ -97,7 +99,9 @@ private:
bool mTranslate;
public:
+#if 0
static void Reparse(void);
+#endif
cSkinString(cSkinObject *Parent, bool Translate);
~cSkinString();
diff --git a/glcdskin/type.h b/glcdskin/type.h
index ad02a15..4d54de8 100644
--- a/glcdskin/type.h
+++ b/glcdskin/type.h
@@ -54,6 +54,10 @@ public:
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 --git a/glcdskin/variable.c b/glcdskin/variable.c
index b07773a..b300afc 100644
--- a/glcdskin/variable.c
+++ b/glcdskin/variable.c
@@ -11,23 +11,63 @@ cSkinVariable::cSkinVariable(cSkin * Parent)
: 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 @@ bool cSkinVariable::ParseCondition(const std::string & Text)
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 --git a/glcdskin/variable.h b/glcdskin/variable.h
index 449f6b0..8c6ef6f 100644
--- a/glcdskin/variable.h
+++ b/glcdskin/variable.h
@@ -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 @@ private:
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 --git a/glcdskin/xml.c b/glcdskin/xml.c
index ed29d11..a3ad976 100644
--- a/glcdskin/xml.c
+++ b/glcdskin/xml.c
@@ -15,32 +15,15 @@
#include <iostream>
#include <fstream>
+#include <string.h>
+#include <stdlib.h>
+
#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 @@ enum {
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 @@ cXML::cXML(const std::string & file)
{
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 @@ cXML::cXML(const std::string & file)
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 @@ cXML::cXML(const char * mem, unsigned int len)
{
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 cXML::Parse(void)
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 @@ int cXML::Parse(void)
last = percent;
}
}
+ i++;
}
return 0;
}
@@ -156,8 +178,15 @@ bool cXML::IsTokenChar(bool start, int c)
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 @@ int cXML::ReadChar(int c)
cdata.replace(pos, 4, ">");
else if (cdata.substr(pos, 5) == "&amp;")
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 @@ int cXML::ReadChar(int c)
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 --git a/glcdskin/xml.h b/glcdskin/xml.h
index 009679c..0978cf4 100644
--- a/glcdskin/xml.h
+++ b/glcdskin/xml.h
@@ -15,6 +15,7 @@
#include <string>
#include <map>
+#include <iconv.h>
namespace GLCD
{
@@ -33,10 +34,14 @@ void (*CB)(int percent)
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<std::string, std::string> attr;
@@ -49,11 +54,12 @@ private:
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 --git a/graphlcd.conf b/graphlcd.conf
index 4c0ea52..24aa61e 100644
--- a/graphlcd.conf
+++ b/graphlcd.conf
@@ -22,7 +22,7 @@
# 1 - nanosleep
# 2 - nanosleep (sched_rr) - This is recommended on kernel 2.4 systems
# 3 - gettimeofday - This is recommended on kernel 2.6 systems
-# Defaukt value: 3
+# Default value: 3
WaitMethod=3
# WaitPriority
@@ -76,7 +76,7 @@ WaitPriority=0
# 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 @@ WaitPriority=0
[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
########################################################################
@@ -566,8 +581,8 @@ Driver=dm140gink
# USB ID activy 5xx:
#Vendor=0x1509
#Product=0x925d
-
########################################################################
+
[futabaMDM166A]
# futabaMDM166A driver
# This is an driver module for Futaba MDM166A VFD displays.
@@ -581,3 +596,110 @@ Driver=futabaMDM166A
#Invert=no
#Brightness=50
#RefreshDisplay=1000
+########################################################################
+
+[ax206dpf]
+# THIS IS AN EXPERIMENTAL DRIVER!
+# You have to uncomment the variable HAVE_DRIVER_AX206DPF
+# 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
+#
+# 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
+#
+
+########################################################################
+
+[vncserver]
+# vncserver driver
+# Output goes to a vncserver device
+# Default size: 320 x 240
+Driver=vncserver
+Width=320
+Height=240
+#
+# HttpDir
+# Webclients directory of libvncserver installation (only needed for webclient access)
+#HttpDir=/usr/share/webclients
+
+########################################################################
+
+[ssd1306]
+# ssd1306 driver
+# This is a driver module for the SSD1306 OLED display controller.
+# Default size: 128 x 64
+Driver=ssd1306
+Device=0
+Width=128
+Height=64
+
+[ili9341]
+# ili9341 driver
+# This is a driver module for the ILI9341 TFT display controller.
+# Default size: 320x240
+Driver=ili9341
+Device=0
+Width=320
+Height=240
+
diff --git a/tools/Makefile b/tools/Makefile
index 572067b..d923139 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -16,6 +16,7 @@ endif
@$(MAKE) -C showpic all
@$(MAKE) -C showtext all
@$(MAKE) -C lcdtestpattern all
+ @$(MAKE) -C skintest all
install:
@$(MAKE) -C convpic install
@@ -26,6 +27,7 @@ endif
@$(MAKE) -C showpic install
@$(MAKE) -C showtext install
@$(MAKE) -C lcdtestpattern install
+ @$(MAKE) -C skintest install
uninstall:
@$(MAKE) -C convpic uninstall
@@ -36,6 +38,7 @@ endif
@$(MAKE) -C showpic uninstall
@$(MAKE) -C showtext uninstall
@$(MAKE) -C lcdtestpattern uninstall
+ @$(MAKE) -C skintest uninstall
clean:
@$(MAKE) -C convpic clean
@@ -44,4 +47,5 @@ clean:
@$(MAKE) -C showpic clean
@$(MAKE) -C showtext clean
@$(MAKE) -C lcdtestpattern clean
+ @$(MAKE) -C skintest clean
diff --git a/tools/convpic/Makefile b/tools/convpic/Makefile
index da5494b..3d57aa4 100644
--- a/tools/convpic/Makefile
+++ b/tools/convpic/Makefile
@@ -6,7 +6,7 @@
PRGNAME = convpic
-OBJS = $(PRGNAME).o bmp.o tiff.o tuxbox.o
+OBJS = $(PRGNAME).o
INCLUDES += -I../../
LIBDIRS += -L../../glcdgraphics/
@@ -18,14 +18,11 @@ all: $(PRGNAME)
# Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
-MAKEDEP = $(CXX) -MM -MG
-DEPFILE = .dependencies
-$(DEPFILE): Makefile
- @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+DEPFILE = $(OBJS:%.o=%.d)
-include $(DEPFILE)
@@ -36,7 +33,7 @@ $(PRGNAME): $(OBJS)
install: $(PRGNAME)
install -d $(BINDIR)
- install -m 755 -o root -g root $(STRIP) $(PRGNAME) $(BINDIR)
+ install -m 755 -o root -g root $(HAVE_STRIP) $(PRGNAME) $(BINDIR)
uninstall:
rm -f $(BINDIR)/$(PRGNAME)
diff --git a/tools/convpic/bmp.c b/tools/convpic/bmp.c
deleted file mode 100644
index 0829302..0000000
--- a/tools/convpic/bmp.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/**
- * GraphLCD plugin for the Video Disk Recorder
- *
- * bmp.c - bmp logo class
- *
- * (C) 2004 Andreas Brachold <vdr04 AT deltab de>
- * (C) 2001-2004 Carsten Siebholz <c.siebholz AT t-online de>
- **/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; *
- * if not, write to the Free Software Foundation, Inc., *
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
- * *
- ***************************************************************************/
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <cstring>
-#include <cstdlib>
-
-#include <glcdgraphics/bitmap.h>
-#include <glcdgraphics/image.h>
-
-#include "bmp.h"
-
-
-#pragma pack(1)
-typedef struct BMPH {
- uint16_t bmpIdentifier;
- uint32_t bmpFileSize;
- uint32_t bmpReserved;
- uint32_t bmpBitmapDataOffset;
- uint32_t bmpBitmapHeaderSize;
- uint32_t bmpWidth;
- uint32_t bmpHeight;
- uint16_t bmpPlanes;
- uint16_t bmpBitsPerPixel;
- uint32_t bmpCompression;
- uint32_t bmpBitmapDataSize;
- uint32_t bmpHResolution;
- uint32_t bmpVResolution;
- uint32_t bmpColors;
- uint32_t bmpImportantColors;
-} BMPHEADER; // 54 bytes
-
-typedef struct RGBQ {
- uint8_t rgbBlue;
- uint8_t rgbGreen;
- uint8_t rgbRed;
- uint8_t rgbReserved;
-} RGBQUAD; // 4 bytes
-#pragma pack()
-
-
-uint8_t bitmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
-uint8_t bitmaskl[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
-uint8_t bitmaskr[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
-
-cBMPFile::cBMPFile()
-{
-}
-
-cBMPFile::~cBMPFile()
-{
-}
-
-bool cBMPFile::Load(GLCD::cImage & image, const std::string & fileName)
-{
- FILE *fIN;
- BMPHEADER bmpHeader;
- RGBQUAD *pPalette;
- char *pByte;
- char Dummy;
- long iNumColors;
- long iSize;
- uint32_t x, y;
- uint16_t iRead;
- uint8_t * bitmap = NULL;
- bool bInvert = false;
-
- if (fileName.length() > 0)
- {
- fIN = fopen(fileName.c_str(), "rb");
- if (fIN)
- {
- if (fread(&bmpHeader, sizeof(BMPHEADER), 1, fIN)!=1)
- {
- fclose(fIN);
- return false;
- }
-
- // check for Windows BMP
- if (bmpHeader.bmpBitmapHeaderSize != 0x00000028 )
- {
- fprintf(stderr, "ERROR: only Windows BMP images are allowed.\n");
- fclose(fIN);
- return false;
- }
-
- // check for 2 color
- iNumColors = (1 << bmpHeader.bmpBitsPerPixel);
- if (iNumColors != 2)
- {
- fprintf(stderr, "ERROR: the image has %ld colors, but only images with 2 colors are allowed.\n", iNumColors);
- fclose(fIN);
- return false;
- }
-
- iSize = bmpHeader.bmpHeight * bmpHeader.bmpWidth;
-
- pPalette = (RGBQUAD *) malloc( iNumColors*sizeof(RGBQUAD));
- if (!pPalette)
- {
- fprintf(stderr, "ERROR: cannot allocate memory\n");
- fclose(fIN);
- return false;
- }
-
- if (fread( pPalette, iNumColors*sizeof(RGBQUAD), 1, fIN)!=1)
- {
- free(pPalette);
- fclose(fIN);
- return false;
- }
-
- // check colors
- if (pPalette->rgbBlue+pPalette->rgbGreen+pPalette->rgbRed <
- (pPalette+1)->rgbBlue+(pPalette+1)->rgbGreen+(pPalette+1)->rgbRed)
- {
- // index 0 represents 'black', index 1 'white'
- bInvert = !bInvert;
- }
- else
- {
- // index 0 represents 'white', index 1 'black'
- }
-
- if (fseek(fIN, bmpHeader.bmpBitmapDataOffset, SEEK_SET)==EOF)
- {
- free(pPalette);
- fclose(fIN);
- return false;
- }
-
- switch (bmpHeader.bmpCompression)
- {
- case 0: // BI_RGB no compression
- image.Clear();
- image.SetWidth(bmpHeader.bmpWidth);
- image.SetHeight(bmpHeader.bmpHeight);
- image.SetDelay(100);
- bitmap = new unsigned char[bmpHeader.bmpHeight * ((bmpHeader.bmpWidth + 7) / 8)];
- if (!bitmap)
- {
- fprintf(stderr, "ERROR: cannot allocate memory\n");
- free(pPalette);
- fclose(fIN);
- image.Clear();
- return false;
- }
-
- for (y = bmpHeader.bmpHeight; y > 0; y--)
- {
- pByte = (char*)bitmap + (y-1)*((bmpHeader.bmpWidth+7)/8);
- iRead = 0;
- for (x = 0; x < bmpHeader.bmpWidth / 8; x++)
- {
- if (fread(pByte, sizeof(char), 1, fIN) != 1)
- {
- delete[] bitmap;
- free(pPalette);
- fclose(fIN);
- image.Clear();
- return false;
- }
- iRead++;
- if (bInvert)
- *pByte = *pByte ^ 0xff;
- pByte++;
- }
-
- if (bmpHeader.bmpWidth % 8)
- {
- if (fread(pByte, sizeof(char), 1, fIN) != 1)
- {
- delete [] bitmap;
- free(pPalette);
- fclose(fIN);
- image.Clear();
- return false;
- }
- iRead++;
- if (bInvert)
- *pByte = *pByte^0xff;
- *pByte = *pByte & bitmaskl[bmpHeader.bmpWidth%8];
- pByte++;
- }
-
- // Scan line must be 4-byte-alligned
- while (iRead % 4)
- {
- if (fread(&Dummy, sizeof(char), 1, fIN) != 1)
- {
- delete [] bitmap;
- free(pPalette);
- fclose(fIN);
- image.Clear();
- return false;
- }
- iRead++;
- }
- }
- image.AddBitmap(new GLCD::cBitmap(bmpHeader.bmpWidth, bmpHeader.bmpHeight, bitmap));
- break;
- case 1: // BI_RLE4 RLE 4bit/pixel
- case 2: // BI_RLE8 RLE 8bit/pixel
- case 3: // BI_BITFIELDS
- default:
- fprintf(stderr, "ERROR: only uncompressed RGB images are allowed.\n");
-
- free(pPalette);
- fclose(fIN);
- return false;
- }
- fclose(fIN);
- }
- else
- {
- fprintf(stderr, "ERROR: cannot open picture %s\n", fileName.c_str());
- }
- }
- else
- {
- fprintf(stderr, "ERROR: no FileName given!\n");
- }
- return true;
-}
-
-bool cBMPFile::Save(const GLCD::cBitmap * bitmap, const std::string & fileName)
-{
- FILE *fOut;
- BMPHEADER bmpHeader;
- RGBQUAD bmpColor1, bmpColor2;
- uint32_t dBDO, dBDSx, dBDS;
- char *pByte;
- char Dummy = 0x00;
- uint32_t x, y;
- uint16_t iWrote;
- const uint8_t * bmpdata = bitmap->Data();
-
- if (bitmap
- && bitmap->Width() > 0
- && bitmap->Height() > 0)
- {
- memset(&bmpHeader, 0, sizeof(BMPHEADER));
-
- dBDO = sizeof(BMPHEADER)+2*sizeof(RGBQUAD);
- dBDSx = ((bitmap->Width() + 7) / 8 + 3) & 0xfffffffc;
- dBDS = dBDSx * bitmap->Height();
-
- bmpHeader.bmpIdentifier = 0x4d42; // "BM"
- bmpHeader.bmpFileSize = dBDO + dBDS;
- bmpHeader.bmpBitmapDataOffset = dBDO;
- bmpHeader.bmpBitmapHeaderSize = 0x28;
- bmpHeader.bmpWidth = bitmap->Width();
- bmpHeader.bmpHeight = bitmap->Height();
- bmpHeader.bmpPlanes = 0x01;
- bmpHeader.bmpBitsPerPixel = 0x01;
- bmpHeader.bmpCompression = 0x00;
- bmpHeader.bmpBitmapDataSize = dBDS;
- bmpHeader.bmpHResolution = 0xb13; // 72dpi
- bmpHeader.bmpVResolution = 0xb13; // 72dpi
- bmpHeader.bmpColors = 0x02;
- bmpHeader.bmpImportantColors = 0x02;
-
- bmpColor1.rgbBlue = 0x00;
- bmpColor1.rgbGreen = 0x00;
- bmpColor1.rgbRed = 0x00;
- bmpColor1.rgbReserved = 0x00;
- bmpColor2.rgbBlue = 0xff;
- bmpColor2.rgbGreen = 0xff;
- bmpColor2.rgbRed = 0xff;
- bmpColor2.rgbReserved = 0x00;
-
-
- fOut = fopen(fileName.c_str(), "wb");
- if (!fOut)
- {
- fprintf(stderr,"Cannot create file: %s\n", fileName.c_str());
- return false;
- }
- fwrite(&bmpHeader, sizeof(BMPHEADER), 1, fOut);
- fwrite(&bmpColor1, sizeof(RGBQUAD), 1, fOut);
- fwrite(&bmpColor2, sizeof(RGBQUAD), 1, fOut);
-
- for (y=bitmap->Height(); y>0; y--)
- {
- pByte = (char*)bmpdata + (y-1)*((bitmap->Width()+7)/8);
- iWrote = 0;
- for (x=0; x<(uint32_t) bitmap->Width()/8; x++)
- {
- *pByte = *pByte^0xff;
- if (fwrite(pByte, sizeof(char), 1, fOut)!=1)
- {
- fclose(fOut);
- return false;
- }
- iWrote++;
- pByte++;
- }
- // Scan line must be 4-byte-alligned
- while (iWrote%4)
- {
- if (fwrite(&Dummy, sizeof(char), 1, fOut)!=1)
- {
- fclose(fOut);
- return 3;
- }
- iWrote++;
- }
- }
- fclose(fOut);
- }
- return true;
-}
-
-bool cBMPFile::Save(GLCD::cImage & image, const std::string & fileName)
-{
- const GLCD::cBitmap * bitmap;
-
- if (image.Count() == 1)
- {
- bitmap = image.GetBitmap(0);
- if (bitmap)
- {
- if (!Save(bitmap, fileName))
- {
- return false;
- }
- }
- }
- else
- {
- uint16_t i;
- char tmpStr[256];
-
- for (i = 0; i < image.Count(); i++)
- {
- sprintf(tmpStr, "%.248s.%05d", fileName.c_str(), i);
- bitmap = image.GetBitmap(i);
- if (bitmap)
- {
- if (!Save(bitmap, tmpStr))
- {
- return false;
- }
- }
- }
- }
- return true;
-}
diff --git a/tools/convpic/bmp.h b/tools/convpic/bmp.h
deleted file mode 100644
index 8419838..0000000
--- a/tools/convpic/bmp.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * GraphLCD plugin for the Video Disk Recorder
- *
- * bmp.h - bmp logo class
- *
- * (C) 2004 Andreas Brachold <vdr04 AT deltab de>
- * (C) 2001-2004 Carsten Siebholz <c.siebholz AT t-online de>
- **/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; *
- * if not, write to the Free Software Foundation, Inc., *
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
- * *
- ***************************************************************************/
-
-#ifndef _BMP_H_
-#define _BMP_H_
-
-#include <glcdgraphics/imagefile.h>
-
-class cBMPFile : public GLCD::cImageFile
-{
-private:
- bool Save(const GLCD::cBitmap * bitmap, const std::string & fileName);
-public:
- cBMPFile();
- virtual ~cBMPFile();
- virtual bool Load(GLCD::cImage & image, const std::string & fileName);
- virtual bool Save(GLCD::cImage & image, const std::string & fileName);
-};
-
-#endif
diff --git a/tools/convpic/convpic.c b/tools/convpic/convpic.c
index 732738c..0adba60 100644
--- a/tools/convpic/convpic.c
+++ b/tools/convpic/convpic.c
@@ -5,6 +5,7 @@
*
* (C) 2004 Andreas Brachold <vdr04 AT deltab de>
* (C) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
+ * (C) 2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
**/
/***************************************************************************
@@ -40,98 +41,46 @@
#include <glcdgraphics/glcd.h>
#include <glcdgraphics/pbm.h>
-#include "bmp.h"
-#include "tiff.h"
-#include "tuxbox.h"
-
static const char *prgname = "convpic";
-static const char *VERSION = "0.1.1";
+static const char *VERSION = "0.1.3";
unsigned int delay = 250;
-enum ePicFormat
-{
- pfUndefined,
- pfTIFF,
- pfBMP,
- pfGLCD,
- pfPBM,
- pfTUXBOX
-};
-
-void usage(void);
-
-ePicFormat getFormat(const char* szFile)
-{
- static const struct tagformats {const char* szExt; ePicFormat picformat;} formats[] =
- {
- {".tiff", pfTIFF },
- {".tif", pfTIFF },
- {".bmp", pfBMP },
- {".glcd", pfGLCD },
- {".pbm", pfPBM },
- {".ani", pfTUXBOX}
- };
- ePicFormat pf = pfUndefined;
-
- if (szFile)
- {
- for (int i = strlen(szFile) - 1; i >= 0; i--)
- {
- if (*(szFile+i) == '.' && strlen(szFile + i + 1))
- {
- for (unsigned int n = 0; n < sizeof(formats)/sizeof(*formats); n++)
- {
- if (!strcasecmp((szFile+i), formats[n].szExt))
- {
- return formats[n].picformat;
- }
- }
- }
- }
- }
- return pf;
+void usage(void) {
+ fprintf(stdout, "\n");
+ fprintf(stdout, "%s v%s\n", prgname, VERSION);
+ fprintf(stdout, "%s is a tool to convert images to or from a GLCD file.\n\n", prgname);
+ fprintf(stdout, " Usage: %s [-n] -i file[s...] -o outfile \n\n", prgname);
+ fprintf(stdout, " -n --invert inverts the output (default: no)\n");
+ fprintf(stdout, " -i --infile specifies the name of the input file(s)\n");
+ fprintf(stdout, " -o --outfile specifies the name of the output file\n");
+ fprintf(stdout, " -d --delay specifies the delay (in ms) between multiple images (default: %d)\n",delay);
+ fprintf(stdout, "\n" );
+ fprintf(stdout, " examples:\n");
+ fprintf(stdout, " # convert an input image to a single frame GLCD\n");
+ fprintf(stdout, " %s -i vdr-logo.bmp -o vdr-logo.glcd\n", prgname );
+ fprintf(stdout, " # convert multiple input images to an animated GLCD (delay: 500 ms between two frames)\n");
+ fprintf(stdout, " %s -d 500 -i vdr-logo-??.bmp -o vdr-logo.glcd\n", prgname );
+ fprintf(stdout, " # convert a GLCD file to PBM file(s)\n");
+ fprintf(stdout, " %s -i vdr-logo.glcd -o vdr-logo.pbm\n", prgname );
}
-GLCD::cImageFile * GetFileTranslator(ePicFormat Format)
-{
- switch (Format)
- {
- case pfGLCD:
- return new GLCD::cGLCDFile();
-
- case pfPBM:
- return new GLCD::cPBMFile();
-
- case pfBMP:
- return new cBMPFile();
-
- case pfTIFF:
- return new cTIFFFile();
-
- case pfTUXBOX:
- return new cTuxBoxFile();
-
- default:
- return NULL;
- }
-
-}
int main(int argc, char *argv[]) {
- ePicFormat inFormat = pfUndefined;
- ePicFormat outFormat = pfUndefined;
std::string inFile = "";
std::string outFile = "";
+ std::string inExtension = "";
+ std::string outExtension = "";
GLCD::cImage image;
GLCD::cImage nextImage;
- GLCD::cImageFile * pInBitmap = NULL;
- GLCD::cImageFile * pOutBitmap = NULL;
bool bError = false;
bool bInvert = false;
bool bDelay = false;
+ unsigned int image_w = 0;
+ unsigned int image_h = 0;
+
static struct option long_options[] =
{
@@ -162,97 +111,108 @@ int main(int argc, char *argv[]) {
bDelay = true;
if (delay < 10)
{
- fprintf(stderr, "Warning: You have specify a to short delay, minimum are 10 ms\n");
+ fprintf(stderr, "WARNING: Delay is too short, minimum delay is 10 ms\n");
delay = 10;
}
break;
default:
+ usage();
return 1;
}
}
- if (inFile.length() == 0)
- {
+ if (inFile.length() == 0) {
fprintf(stderr, "ERROR: You have to specify the infile (-i filename)\n");
bError = true;
}
- if (pfUndefined == (inFormat = getFormat(inFile.c_str())))
- {
- fprintf(stderr, "ERROR: You have to specify a correct extension for the %s\n", inFile.c_str());
+ inExtension = GLCD::cImage::GetFilenameExtension(inFile);
+
+ if (outFile.length() == 0) {
+ outFile = inFile.substr(0, inFile.length() - inExtension.length() - 1);
+ if (inExtension == "GLCD") {
+ outFile += ".pbm";
+ outExtension = "PBM";
+ } else {
+ outFile += ".glcd";
+ outExtension = "GLCD";
+ }
+ fprintf(stderr, "WARNING: No output filename given, will use '%s'\n", outFile.c_str());
+ }
+
+ if (outExtension.length() == 0) {
+ outExtension = GLCD::cImage::GetFilenameExtension(outFile);
+ }
+
+ if ( !(outExtension == "GLCD" || outExtension == "PBM") ) {
+ fprintf(stderr, "ERROR: Unsupported format for outfile ('%s')\n", outExtension.c_str());
bError = true;
}
- if (outFile.length() == 0)
- {
- fprintf(stderr, "ERROR: You have to specify the outfile (-o filename)\n");
+ if ( inExtension != "GLCD" && outExtension != "GLCD" ) {
+ fprintf(stderr, "ERROR: Either infile or outfile needs to be a GLCD file\n");
bError = true;
}
- if (pfUndefined == (outFormat = getFormat(outFile.c_str())))
- {
- fprintf(stderr, "ERROR: You have to specify a correct extension for the %s \n", outFile.c_str());
+ if ( outExtension != "GLCD" && outExtension != "PBM" ) {
+ fprintf(stderr, "ERROR: outfile needs to be either GLCD or PBM\n");
bError = true;
}
- if (bError)
- {
+ if (bError) {
usage();
return 1;
}
-
- pInBitmap = GetFileTranslator(inFormat);
- if (!pInBitmap)
- return 2;
-
- pOutBitmap = GetFileTranslator(outFormat);
- if (!pOutBitmap)
- return 3;
-
// Load Picture
fprintf(stdout, "loading %s\n", inFile.c_str());
- bError = !pInBitmap->Load(image, inFile);
- if (!bError)
- {
+ if (GLCD::cImage::LoadImage(image, inFile) == false) {
+ fprintf(stderr, "ERROR: Failed loading file %s\n", inFile.c_str());
+ bError = true;
+ }
+
+ /* if more than one input image: following images must match width and height of first image */
+ image_w = image.GetBitmap(0)->Width();
+ image_h = image.GetBitmap(0)->Height();
+
+ if (!bError) {
+ GLCD::cImageFile * outImage = NULL;
// Load more in files
- while (optind < argc && !bError)
- {
+ while (optind < argc && !bError) {
inFile = argv[optind++];
- inFormat = getFormat(inFile.c_str());
- if (inFormat == pfUndefined)
- {
- fprintf(stderr, "ERROR: You have to specify a correct extension for the %s\n", inFile.c_str());
- bError = true;
- break;
- }
- pInBitmap = GetFileTranslator(inFormat);
- if (!pInBitmap)
- break;
fprintf(stdout, "loading %s\n", inFile.c_str());
- if (pInBitmap->Load(nextImage, inFile))
- {
+ if (GLCD::cImage::LoadImage(nextImage, inFile) == false) {
+ fprintf(stderr, "ERROR: Failed loading file '%s', ignoring it ...\n", inFile.c_str());
+ } else {
+ unsigned int nim_w = nextImage.GetBitmap(0)->Width();
+ unsigned int nim_h = nextImage.GetBitmap(0)->Height();
+ if ( nim_w != image_w || nim_h != image_h) {
+ fprintf(stderr, "ERROR: Image '%s' is not matching dimensions of first image, ignoring it ...\n", inFile.c_str());
+ } else {
uint16_t i;
- for (i = 0; i < nextImage.Count(); i++)
- {
+ for (i = 0; i < nextImage.Count(); i++) {
image.AddBitmap(new GLCD::cBitmap(*nextImage.GetBitmap(i)));
}
+ }
}
}
if (bDelay)
image.SetDelay(delay);
- if (bInvert)
- {
+ if (bInvert) {
uint16_t i;
- for (i = 0; i < image.Count(); i++)
- {
+ for (i = 0; i < image.Count(); i++) {
image.GetBitmap(i)->Invert();
}
}
+ if (outExtension == "PBM") {
+ outImage = new GLCD::cPBMFile();
+ } else {
+ outImage = new GLCD::cGLCDFile();
+ }
fprintf(stdout, "saving %s\n", outFile.c_str());
- bError = !pOutBitmap->Save(image, outFile);
+ bError = !outImage->Save(image, outFile);
}
if (bError) {
return 4;
@@ -262,18 +222,3 @@ int main(int argc, char *argv[]) {
return 0;
}
-
-void usage(void)
-{
- fprintf(stdout, "\n");
- fprintf(stdout, "%s v%s\n", prgname, VERSION);
- fprintf(stdout, "%s is a tool to convert images to a simple format (*.glcd)\n", prgname);
- fprintf(stdout, " that is used by the graphlcd plugin for VDR.\n\n");
- fprintf(stdout, " Usage: %s [-n] -i file[s...] -o outfile \n\n", prgname);
- fprintf(stdout, " -n --invert inverts the output (default: none)\n");
- fprintf(stdout, " -i --infile specifies the name of the input file[s]\n");
- fprintf(stdout, " -o --outfile specifies the name of the output file\n");
- fprintf(stdout, " -d --delay specifies the delay between multiple images [Default: %d ms] \n",delay);
- fprintf(stdout, "\n" );
- fprintf(stdout, " example: %s -i vdr-logo.bmp -o vdr-logo.glcd \n", prgname );
-}
diff --git a/tools/convpic/tiff.c b/tools/convpic/tiff.c
deleted file mode 100644
index 4b8bf0e..0000000
--- a/tools/convpic/tiff.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * GraphLCD plugin for the Video Disk Recorder
- *
- * tiff.c - tiff logo class
- *
- * (c) 2004 Andreas Brachold <vdr04 AT deltab de>
- * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online de>
- **/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; *
- * if not, write to the Free Software Foundation, Inc., *
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
- * *
- ***************************************************************************/
-
-#include <stdio.h>
-#include <string.h>
-
-#include <string>
-
-#include <glcdgraphics/bitmap.h>
-#include <glcdgraphics/image.h>
-
-#include "tiff.h"
-
-
-#pragma pack(1)
-typedef struct TIFFT{
- unsigned short tag;
- unsigned short type;
- unsigned long length;
- /* 1 = BYTE. 8-bit unsigned integer. */
- /* 2 = ASCII. 8-bit bytes that store ASCII codes; the last byte must be null. */
- /* 3 = SHORT. A 16-bit (2-byte) unsigned integer. */
- /* 4 = LONG. A 32-bit (4-byte) unsigned integer. */
- /* 5 = RATIONAL. Two LONGs: the first represents the numerator of a fraction, the second the denominator. */
- unsigned long off_val;
-} TIFFTAG;
-#pragma pack()
-
-#define GETANDCHECK { t=fgetc(fIN);if(t==EOF) {fclose(fIN);return false;};}
-
-cTIFFFile::cTIFFFile()
-{
-}
-
-cTIFFFile::~cTIFFFile()
-{
-}
-
-bool cTIFFFile::Load(GLCD::cImage & image, const std::string & fileName)
-{
- FILE *fIN;
- TIFFTAG tifftag;
- unsigned int tiff_header, tiff_anztags, tiff_data;
- unsigned char cl,ch,y,i;
- unsigned char height, width, strip, invert;
- unsigned char fLittleEndian=0;
- int j;
- int t;
- unsigned char *bitmap = NULL;
- bool bInvert = false;
-
- if (fileName.length() > 0)
- {
- fIN = fopen(fileName.c_str(), "rb");
- if (fIN)
- {
- // isyslog("graphlcd plugin: try to load logo %s.", szFileName);
- if (fseek(fIN, 0, SEEK_SET)==EOF)
- {
- fclose(fIN);
- return false;
- }
- GETANDCHECK; cl=(unsigned char)t;
- GETANDCHECK; ch=(unsigned char)t;
- if ((cl==0x49) && (ch==0x49))
- {
- fLittleEndian=1;
- }
-
- if (fseek(fIN, 4, SEEK_SET)==EOF)
- {
- fclose(fIN);
- return false;
- }
- GETANDCHECK; cl=(unsigned char)t;
- GETANDCHECK; ch=(unsigned char)t;
- tiff_header = cl+256*ch;
- //printf("tiff_header:%d %x\n", tiff_header, tiff_header);
-
- if (fseek(fIN, tiff_header, SEEK_SET)==EOF)
- {
- fclose(fIN);
- return false;
- }
-
- GETANDCHECK; cl=(unsigned char)t;
- GETANDCHECK; ch=(unsigned char)t;
- tiff_anztags = cl+256*ch;
- //printf("tiff_anztags:%d %x\n", tiff_anztags, tiff_anztags);
-
- height=0;
- width=0;
- strip=0;
- invert=0;
- for (i=0; (i<tiff_anztags)&&(!height||!width||!strip||!invert); i++)
- {
- if (fread(&tifftag, sizeof(tifftag), 1, fIN)!=1)
- {
- fclose(fIN);
- return false;
- }
- if (tifftag.tag==0x0100) width=tifftag.off_val;
- if (tifftag.tag==0x0101) height=tifftag.off_val;
- if (tifftag.tag==0x0111) strip=tifftag.off_val;
- if (tifftag.tag==0x0106) invert=tifftag.off_val+1;
- //printf("tag%d: %d %d %ld %ld\n", i,tifftag.tag, tifftag.type, tifftag.length, tifftag.off_val );
- }
-
- if (fseek(fIN,strip, SEEK_SET)==EOF)
- {
- fclose(fIN);
- return false;
- }
- GETANDCHECK; cl=(unsigned char)t;
- GETANDCHECK; ch=(unsigned char)t;
- tiff_data = cl+256*ch;
- //printf("tiff_data:%d %x\n", tiff_data, tiff_data);
-
- if (fseek(fIN, tiff_data, SEEK_SET)==EOF)
- {
- fclose(fIN);
- return false;
- }
-
-
- image.Clear();
- image.SetWidth(width);
- image.SetHeight(height);
- image.SetDelay(100);
- bitmap = new unsigned char[height * ((width + 7) / 8)];
- if (bitmap)
- {
- if (fread(bitmap, height*((width+7)/8), 1, fIN)!=1)
- {
- delete [] bitmap;
- fclose(fIN);
- image.Clear();
- return false;
- }
-
- if (invert-1==1) bInvert = !bInvert; // 'Black is zero'
- if (bInvert)
- {
- for (j=0; j < height * ((width+7)/8); j++)
- {
- (*(bitmap+j)) = (*(bitmap+j))^0xff;
- }
- }
-
- // cut the rest of the line
- if (width%8)
- {
- for (y=1; y<=height; y++) {
- j=y*((width+7)/8)-1;
- (*(bitmap+j)) = ((*(bitmap+j))>>(8-width%8))<<(8-width%8);
- }
- }
- image.AddBitmap(new GLCD::cBitmap(width, height, bitmap));
- }
- else
- {
- fprintf(stderr, "ERROR: cannot allocate memory\n");
- }
- fclose(fIN);
- }
- else
- {
- fprintf(stderr, "ERROR: cannot open picture %s\n", fileName.c_str());
- }
- }
- else
- {
- fprintf(stderr, "ERROR: no szFileName given!\n");
- }
- return true;
-}
diff --git a/tools/convpic/tiff.h b/tools/convpic/tiff.h
deleted file mode 100644
index f6e66c1..0000000
--- a/tools/convpic/tiff.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * GraphLCD plugin for the Video Disk Recorder
- *
- * tiff.h - tiff logo class
- *
- * (c) 2004 Andreas Brachold <vdr04 AT deltab de>
- * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online de>
- **/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; *
- * if not, write to the Free Software Foundation, Inc., *
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
- * *
- ***************************************************************************/
-
-#ifndef _TIFF_H_
-#define _TIFF_H_
-
-#include <glcdgraphics/imagefile.h>
-
-class cTIFFFile : public GLCD::cImageFile
-{
-public:
- cTIFFFile();
- virtual ~cTIFFFile();
- virtual bool Load(GLCD::cImage & image, const std::string & fileName);
-};
-
-#endif
diff --git a/tools/convpic/tuxbox.c b/tools/convpic/tuxbox.c
deleted file mode 100644
index 55d6e1d..0000000
--- a/tools/convpic/tuxbox.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/**
- * GraphLCD plugin for the Video Disk Recorder
- *
- * tuxbox.c - tuxbox logo class
- *
- * (c) 2004 Andreas Brachold <vdr04 AT deltab de>
- **/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; *
- * if not, write to the Free Software Foundation, Inc., *
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
- * *
- ***************************************************************************/
-
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
-
-#include <string>
-
-#include <glcdgraphics/bitmap.h>
-#include <glcdgraphics/image.h>
-
-#include "tuxbox.h"
-
-#pragma pack(1)
-struct ani_header {
- unsigned char magic[4]; // = "LCDA"
- unsigned short format; // Format
- unsigned short width; // Breite
- unsigned short height; // Höhe
- unsigned short count; // Anzahl Einzelbilder
- unsigned long delay; // µs zwischen Einzelbildern
-};
-#pragma pack()
-
-cTuxBoxFile::cTuxBoxFile()
-{
-}
-
-cTuxBoxFile::~cTuxBoxFile()
-{
-}
-
-bool cTuxBoxFile::Load(GLCD::cImage & image, const std::string & fileName)
-{
- bool ret = false;
- FILE * fIN;
- long fileLen;
- struct ani_header header;
- bool bInvert = false;
-
- fIN = fopen(fileName.c_str(), "rb");
- if (fIN)
- {
- // get len of file
- if (fseek(fIN, 0, SEEK_END))
- {
- fclose(fIN);
- return false;
- }
- fileLen = ftell(fIN);
-
- // rewind and get Header
- if (fseek(fIN, 0, SEEK_SET))
- {
- fclose(fIN);
- return false;
- }
-
- // Read header
- if (fread(&header, sizeof(header), 1, fIN) != 1)
- {
- fclose(fIN);
- return false;
- }
-
- image.Clear();
- image.SetWidth(ntohs(header.width));
- image.SetHeight(ntohs(header.height));
- image.SetDelay(ntohl(header.delay) / 1000);
-
- // check Header
- if (strncmp((const char*)header.magic, "LCDA", sizeof(header.magic)) ||
- !image.Width() || !image.Height() || ntohs(header.format) != 0)
- {
- fprintf(stderr, "ERROR: load %s failed, wrong header.\n", fileName.c_str());
- fclose(fIN);
- return false;
- }
-
- //fprintf(stderr,"%d %dx%d (%d %d) %d\n",ntohs(header.count),image.Width(),image.Height(),fileLen, ( (ntohs(header.count) * (image.Width() * ((image.Height() + 7) / 8))) + sizeof(header)),lhdr.delay);
-
- // check file length
- if (!ntohs(header.count)
- || (fileLen != (long) ( (ntohs(header.count) * (image.Width() * ((image.Height() + 7) / 8))) + sizeof(header))))
- {
- fprintf(stderr, "ERROR: load %s failed, wrong size.\n", fileName.c_str());
- fclose(fIN);
- return false;
- }
- // Set minimal limit for next image
- if (image.Delay() < 10)
- image.SetDelay(10);
- for (unsigned int n=0;n<ntohs(header.count);++n)
- {
- ret = false;
- unsigned int nBmpSize = image.Height() * ((image.Width() + 7) / 8);
- unsigned char *bitmap = new unsigned char[nBmpSize];
- if (!bitmap)
- {
- fprintf(stderr, "ERROR: malloc failed.");
- break;
- }
- unsigned int nAniSize = image.Width() * ((image.Height() + 7) / 8);
- unsigned char *pAni = new unsigned char[nAniSize];
- if (!pAni)
- {
- delete[] bitmap;
- fprintf(stderr, "ERROR: malloc failed.");
- break;
- }
-
- if (1 != fread(pAni, nAniSize, 1, fIN))
- {
- fprintf(stderr,"ERROR: Cannot read filedata: %s\n", fileName.c_str());
- delete[] bitmap;
- delete[] pAni;
- break;
- }
-
- vert2horz(pAni,bitmap, image.Width(), image.Height());
- delete[] pAni;
-
- if (bInvert)
- for (unsigned int i=0;i<nBmpSize;++i)
- bitmap[i] ^= 0xFF;
-
- image.AddBitmap(new GLCD::cBitmap(image.Width(), image.Height(), bitmap));
- ret = true;
- }
- fclose(fIN);
- if (!ret)
- image.Clear();
- }
- return ret;
-}
-
-
-bool cTuxBoxFile::Save(GLCD::cImage & image, const std::string & fileName)
-{
- FILE * fOut;
- struct ani_header header;
- bool bRet = false;
-
- if (image.Count() > 0
- && image.Width()
- && image.Height())
- {
- memcpy(header.magic, "LCDA", 4);
- header.format = htons(0);
- header.width = htons(image.Width());
- header.height = htons(image.Height());
- header.count = htons(image.Count());
- header.delay = htonl(image.Delay() * 1000);
-
-
- if (image.Width() != 120 || image.Height() != 64)
- {
- fprintf(stderr,"WARNING: Maybe wrong image dimension (for all I know is 120x64 wanted) %s\n", fileName.c_str());
- }
-
- fOut = fopen(fileName.c_str(), "wb");
- if (!fOut) {
- fprintf(stderr,"ERROR: Cannot create file: %s\n", fileName.c_str());
- return false;
- }
-
- if (1 != fwrite(&header, sizeof(header), 1, fOut))
- {
- fprintf(stderr,"ERROR: Cannot write fileheader: %s\n", fileName.c_str());
- fclose(fOut);
- return false;
- }
-
- for (unsigned int n = 0; n < image.Count(); n++)
- {
- bRet = false;
- unsigned int nAniSize = image.Width() * ((image.Height() + 7) / 8);
- unsigned char *pAni = new unsigned char[nAniSize];
- if (!pAni)
- {
- fprintf(stderr, "ERROR: malloc failed.");
- break;
- }
- horz2vert(image.GetBitmap(n)->Data(), pAni, image.Width(), image.Height());
-
- if (1 != fwrite(pAni, nAniSize, 1, fOut))
- {
- delete [] pAni;
- fprintf(stderr,"ERROR: Cannot write filedata: %s\n", fileName.c_str());
- break;
- }
- delete [] pAni;
- bRet = true;
- }
-
- fclose(fOut);
- }
- return bRet;
-}
-
-/** Translate memory alignment from vertical to horizontal
-rotate from {Byte} to {Byte}
-{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] => [ 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] => [ 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) {
- int x, y, off;
- memset(dest,0,height*((width+7)/8));
-
- for (y=0; y<height; ++y)
- {
- for (x=0; x<width; ++x)
- {
- off = x + ((y/8) * width);
- if (source[off] & (0x1 << (y % 8)))
- {
- off = (x / 8) + (y * ((width+7)/8));
- dest[off] |= (unsigned char)(0x80 >> (x % 8));
- }
- }
- }
-}
-
-/** Translate memory alignment from horizontal to vertical (rotate byte)
-rotate from {Byte} to {Byte}
-{ 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]
-[ 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]
-[ 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) {
- int x, y, off;
- memset(dest,0,width*((height+7)/8));
-
- for (y=0; y<height; ++y)
- {
- for (x=0; x<width; ++x)
- {
- off = (x / 8) + ((y) * ((width+7)/8));
- if (source[off] & (0x80 >> (x % 8)))
- {
- off = x + ((y/8) * width);
- dest[off] |= (unsigned char)(0x1 << (y % 8));
- }
- }
- }
-}
diff --git a/tools/convpic/tuxbox.h b/tools/convpic/tuxbox.h
deleted file mode 100644
index 1214fb5..0000000
--- a/tools/convpic/tuxbox.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * GraphLCD plugin for the Video Disk Recorder
- *
- * tuxbox.h - tuxbox logo class
- *
- * (c) 2004 Andreas Brachold <vdr04 AT deltab de>
- **/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; *
- * if not, write to the Free Software Foundation, Inc., *
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
- * *
- ***************************************************************************/
-#ifndef _TUXBOX_H_
-#define _TUXBOX_H_
-
-#include <glcdgraphics/imagefile.h>
-
-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);
-public:
- cTuxBoxFile();
- virtual ~cTuxBoxFile();
- virtual bool Load(GLCD::cImage & image, const std::string & fileName);
- virtual bool Save(GLCD::cImage & image, const std::string & fileName);
-};
-
-#endif
diff --git a/tools/crtfont/Makefile b/tools/crtfont/Makefile
index 592d123..6c6abdf 100644
--- a/tools/crtfont/Makefile
+++ b/tools/crtfont/Makefile
@@ -17,14 +17,11 @@ all: $(PRGNAME)
# Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
-MAKEDEP = $(CXX) -MM -MG
-DEPFILE = .dependencies
-$(DEPFILE): Makefile
- @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+DEPFILE = $(OBJS:%.o=%.d)
-include $(DEPFILE)
@@ -35,7 +32,7 @@ $(PRGNAME): $(OBJS)
install: $(PRGNAME)
install -d $(BINDIR)
- install -m 755 -o root -g root $(STRIP) $(PRGNAME) $(BINDIR)
+ install -m 755 -o root -g root $(HAVE_STRIP) $(PRGNAME) $(BINDIR)
uninstall:
rm -f $(BINDIR)/$(PRGNAME)
diff --git a/tools/crtfont/crtfont.c b/tools/crtfont/crtfont.c
index 97e57fe..fc7beef 100644
--- a/tools/crtfont/crtfont.c
+++ b/tools/crtfont/crtfont.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#include <getopt.h>
@@ -20,6 +22,8 @@
#include <string.h>
#include <glcdgraphics/bitmap.h>
#include <glcdgraphics/font.h>
+#include <glcdgraphics/image.h>
+#include <glcdgraphics/pbm.h>
static const char *prgname = "crtfont";
static const char *version = "0.1.6";
@@ -151,15 +155,25 @@ int main(int argc, char *argv[])
// 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 @@ void usage(void)
fprintf(stdout, " graphlcd plugin for VDR.\n\n");
fprintf(stdout, " Usage: %s -f <format> -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 --git a/tools/genfont/Makefile b/tools/genfont/Makefile
index e516a21..f97d8e7 100644
--- a/tools/genfont/Makefile
+++ b/tools/genfont/Makefile
@@ -20,14 +20,11 @@ all: $(PRGNAME)
# Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
-MAKEDEP = $(CXX) -MM -MG
-DEPFILE = .dependencies
-$(DEPFILE): Makefile
- @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+DEPFILE = $(OBJS:%.o=%.d)
-include $(DEPFILE)
@@ -38,7 +35,7 @@ $(PRGNAME): $(OBJS)
install: $(PRGNAME)
install -d $(BINDIR)
- install -m 755 -o root -g root $(STRIP) $(PRGNAME) $(BINDIR)
+ install -m 755 -o root -g root $(HAVE_STRIP) $(PRGNAME) $(BINDIR)
uninstall:
rm -f $(BINDIR)/$(PRGNAME)
diff --git a/tools/genfont/genfont.c b/tools/genfont/genfont.c
index 7553e4c..775d142 100644
--- a/tools/genfont/genfont.c
+++ b/tools/genfont/genfont.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#include <getopt.h>
@@ -17,6 +19,8 @@
#include <glcdgraphics/bitmap.h>
#include <glcdgraphics/font.h>
+#include <glcdgraphics/image.h>
+#include <glcdgraphics/pbm.h>
static const char *prgname = "genfont";
static const char *version = "0.0.2";
@@ -136,13 +140,14 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
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 --git a/tools/lcdtestpattern/Makefile b/tools/lcdtestpattern/Makefile
index 51b1123..e29305b 100644
--- a/tools/lcdtestpattern/Makefile
+++ b/tools/lcdtestpattern/Makefile
@@ -18,25 +18,22 @@ all: $(PRGNAME)
# Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
-MAKEDEP = $(CXX) -MM -MG
-DEPFILE = .dependencies
-$(DEPFILE): Makefile
- @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+DEPFILE = $(OBJS:%.o=%.d)
-include $(DEPFILE)
# 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)
- install -m 755 -o root -g root $(STRIP) $(PRGNAME) $(BINDIR)
+ install -m 755 -o root -g root $(HAVE_STRIP) $(PRGNAME) $(BINDIR)
uninstall:
rm -f $(BINDIR)/$(PRGNAME)
diff --git a/tools/showpic/Makefile b/tools/showpic/Makefile
index 52c1850..de7560a 100644
--- a/tools/showpic/Makefile
+++ b/tools/showpic/Makefile
@@ -18,14 +18,11 @@ all: $(PRGNAME)
# Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
-MAKEDEP = $(CXX) -MM -MG
-DEPFILE = .dependencies
-$(DEPFILE): Makefile
- @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+DEPFILE = $(OBJS:%.o=%.d)
-include $(DEPFILE)
@@ -36,7 +33,7 @@ $(PRGNAME): $(OBJS)
install: $(PRGNAME)
install -d $(BINDIR)
- install -m 755 -o root -g root $(STRIP) $(PRGNAME) $(BINDIR)
+ install -m 755 -o root -g root $(HAVE_STRIP) $(PRGNAME) $(BINDIR)
uninstall:
rm -f $(BINDIR)/$(PRGNAME)
diff --git a/tools/showpic/showpic.c b/tools/showpic/showpic.c
index ebeb73f..7c05ca3 100644
--- a/tools/showpic/showpic.c
+++ b/tools/showpic/showpic.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2013 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#include <stdio.h>
@@ -18,240 +20,276 @@
#include <getopt.h>
#include <dlfcn.h>
#include <unistd.h>
-#include <syslog.h>
#include <signal.h>
#include <string>
#include <glcdgraphics/bitmap.h>
-#include <glcdgraphics/glcd.h>
#include <glcdgraphics/image.h>
+
#include <glcddrivers/config.h>
#include <glcddrivers/driver.h>
#include <glcddrivers/drivers.h>
static const char *prgname = "showpic";
-static const char *version = "0.1.2";
+static const char *version = "0.1.3";
static const int kDefaultSleepMs = 100;
static const char * kDefaultConfigFile = "/etc/graphlcd.conf";
static volatile bool stopProgramm = false;
-static void sighandler(int signal)
-{
- switch (signal)
- {
- case SIGINT:
- case SIGQUIT:
- case SIGTERM:
- stopProgramm = true;
- }
+static void sighandler(int signal) {
+ switch (signal) {
+ case SIGINT:
+ case SIGQUIT:
+ case SIGTERM:
+ stopProgramm = true;
+ }
}
-void usage()
-{
- 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, "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);
- fprintf(stdout, " -c --config specifies the location of the config file\n");
- fprintf(stdout, " (default: /etc/graphlcd.conf)\n");
- fprintf(stdout, " -d --display specifies the output display (default is the first one)\n");
- fprintf(stdout, " -u --upsidedown rotates the output by 180 degrees (default: no)\n");
- 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, " (default: config file value)\n");
- fprintf(stdout, "\n" );
- fprintf(stdout, " examples: %s -c /etc/graphlcd.conf vdr-logo.glcd\n", prgname);
- fprintf(stdout, " %s -c /etc/graphlcd.conf -d LCD_T6963 -u -i vdr-logo.glcd\n", prgname);
- fprintf(stdout, "\n" );
+void usage() {
+ fprintf(stdout, "\n");
+ fprintf(stdout, "%s v%s\n", prgname, version);
+ fprintf(stdout, "%s is a tool to show an image on an LCD.\n", prgname);
+ fprintf(stdout, "The image format must be supported by libglcdgraphics.\n\n");
+ fprintf(stdout, " Usage: %s [-c CONFIGFILE] [-d DISPLAY] [-s SLEEP] [-uie] file [more files]\n\n", prgname);
+ fprintf(stdout, " -c --config specifies the location of the config file\n");
+ fprintf(stdout, " (default: /etc/graphlcd.conf)\n");
+ fprintf(stdout, " -d --display specifies the output display (default is the first one)\n");
+ fprintf(stdout, " -u --upsidedown rotates the output by 180 degrees (default: no)\n");
+ 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 supported by the driver) [%%]\n");
+ fprintf(stdout, " (default: config file value)\n");
+ fprintf(stdout, " -S --scale scale algorithm to be used\n");
+ fprintf(stdout, " 0: don't scale (default)\n");
+ fprintf(stdout, " 1: fit to display if larger but not if smaller (keeping aspect ratio) \n");
+ fprintf(stdout, " 2: fit to display if larger or smaller (keeping aspect ratio)\n");
+ fprintf(stdout, " 3: fill display (ignoring aspect ratio)\n");
+ fprintf(stdout, " -C --center center image (default: no)\n");
+ fprintf(stdout, "\n" );
+ fprintf(stdout, " examples: %s -c /etc/graphlcd.conf vdr-logo.glcd\n", prgname);
+ fprintf(stdout, " %s -c /etc/graphlcd.conf -d somedisplay -u -i vdr-animation.glcd\n", prgname);
+ fprintf(stdout, "\n" );
}
-int main(int argc, char *argv[])
-{
- static struct option long_options[] =
- {
- {"config", required_argument, NULL, 'c'},
- {"display", required_argument, NULL, 'd'},
- {"sleep", required_argument, NULL, 's'},
- {"endless", no_argument, NULL, 'e'},
- {"upsidedown", no_argument, NULL, 'u'},
- {"invert", no_argument, NULL, 'i'},
- {"brightness", required_argument, NULL, 'b'},
- {NULL}
- };
-
- std::string configName = "";
- std::string displayName = "";
- bool upsideDown = false;
- bool invert = false;
- int brightness = -1;
- bool delay = false;
- int sleepMs = 100;
- bool endless = false;
- unsigned int displayNumber = 0;
-
- int c, option_index = 0;
- while ((c = getopt_long(argc, argv, "c:d:s:euib:", long_options, &option_index)) != -1)
- {
- switch(c)
- {
- case 'c':
- configName = optarg;
- break;
-
- case 'd':
- displayName = optarg;
- break;
-
- case 'u':
- upsideDown = true;
- break;
-
- case 'i':
- invert = true;
- break;
-
- case 's':
- sleepMs = atoi(optarg);
- delay = true;
- break;
-
- case 'e':
- endless = true;
- break;
-
- case 'b':
- brightness = atoi(optarg);
- if (brightness < 0) brightness = 0;
- if (brightness > 100) brightness = 100;
- break;
-
- default:
- usage();
- return 1;
- }
- }
-
- if (configName.length() == 0)
- {
- configName = kDefaultConfigFile;
- syslog(LOG_INFO, "Error: No config file specified, using default (%s).\n", configName.c_str());
- }
-
- if (GLCD::Config.Load(configName) == false)
- {
- fprintf(stdout, "Error loading config file!\n");
- return 2;
- }
- if (GLCD::Config.driverConfigs.size() > 0)
- {
- if (displayName.length() > 0)
- {
- for (displayNumber = 0; displayNumber < GLCD::Config.driverConfigs.size(); displayNumber++)
- {
- if (GLCD::Config.driverConfigs[displayNumber].name == displayName)
- break;
- }
- if (displayNumber == GLCD::Config.driverConfigs.size())
- {
- fprintf(stdout, "ERROR: Specified display %s not found in config file!\n", displayName.c_str());
- return 3;
- }
- }
- else
- {
- fprintf(stdout, "WARNING: No display specified, using first one.\n");
- displayNumber = 0;
- }
- }
- else
- {
- fprintf(stdout, "ERROR: No displays specified in config file!\n");
- return 4;
- }
-
- if (optind == argc)
- {
- usage();
- fprintf(stderr, "ERROR: You have to specify the image\n");
- return 5;
- }
-
- GLCD::Config.driverConfigs[displayNumber].upsideDown ^= upsideDown;
- GLCD::Config.driverConfigs[displayNumber].invert ^= invert;
- if (brightness != -1)
- GLCD::Config.driverConfigs[displayNumber].brightness = brightness;
- GLCD::cDriver * lcd = GLCD::CreateDriver(GLCD::Config.driverConfigs[displayNumber].id, &GLCD::Config.driverConfigs[displayNumber]);
- if (!lcd)
- {
- fprintf(stderr, "ERROR: Failed creating display object %s\n", displayName.c_str());
- return 6;
- }
- if (lcd->Init() != 0)
- {
- fprintf(stderr, "ERROR: Failed initializing display %s\n", displayName.c_str());
- delete lcd;
- return 7;
- }
+int main(int argc, char *argv[]) {
+ static struct option long_options[] =
+ {
+ {"config", required_argument, NULL, 'c'},
+ {"display", required_argument, NULL, 'd'},
+ {"sleep", required_argument, NULL, 's'},
+ {"endless", no_argument, NULL, 'e'},
+ {"upsidedown", no_argument, NULL, 'u'},
+ {"invert", no_argument, NULL, 'i'},
+ {"brightness", required_argument, NULL, 'b'},
+ {"scale", required_argument, NULL, 'S'},
+ {"center", no_argument, NULL, 'C'},
+ {NULL}
+ };
+
+ std::string configName = "";
+ std::string displayName = "";
+ bool upsideDown = false;
+ bool invert = false;
+ int brightness = -1;
+ bool delay = false;
+ int sleepMs = 100;
+ bool endless = false;
+ unsigned int displayNumber = 0;
+ int scaleAlgo = 0;
+ bool center = false;
+
+ int c, option_index = 0;
+ while ((c = getopt_long(argc, argv, "c:d:s:S:euib:C", long_options, &option_index)) != -1) {
+ switch(c) {
+ case 'c':
+ configName = optarg;
+ break;
+
+ case 'd':
+ displayName = optarg;
+ break;
+
+ case 'u':
+ upsideDown = true;
+ break;
+
+ case 'i':
+ invert = true;
+ break;
+
+ case 's':
+ sleepMs = atoi(optarg);
+ delay = true;
+ break;
+
+ case 'S':
+ scaleAlgo = atoi(optarg);
+ if (scaleAlgo < 0 || scaleAlgo > 3) scaleAlgo = 0;
+ break;
+
+ case 'e':
+ endless = true;
+ break;
+
+ case 'b':
+ brightness = atoi(optarg);
+ if (brightness < 0) brightness = 0;
+ if (brightness > 100) brightness = 100;
+ break;
+
+ case 'C':
+ center = true;
+ break;
+
+ default:
+ usage();
+ return 1;
+ }
+ }
+
+ if (configName.length() == 0) {
+ configName = kDefaultConfigFile;
+ fprintf(stderr, "Error: No config file specified, using default (%s).\n", configName.c_str());
+ }
+
+ if (GLCD::Config.Load(configName) == false) {
+ fprintf(stderr, "Error loading config file!\n");
+ return 2;
+ }
+ if (GLCD::Config.driverConfigs.size() > 0) {
+ if (displayName.length() > 0) {
+ for (displayNumber = 0; displayNumber < GLCD::Config.driverConfigs.size(); displayNumber++) {
+ if (GLCD::Config.driverConfigs[displayNumber].name == displayName)
+ break;
+ }
+ if (displayNumber == GLCD::Config.driverConfigs.size()) {
+ fprintf(stderr, "ERROR: Specified display %s not found in config file!\n", displayName.c_str());
+ return 3;
+ }
+ } else {
+ fprintf(stderr, "WARNING: No display specified, using first one.\n");
+ displayNumber = 0;
+ }
+ } else {
+ fprintf(stderr, "ERROR: No displays specified in config file!\n");
+ return 4;
+ }
+
+ if (optind == argc) {
+ usage();
+ fprintf(stderr, "ERROR: You have to specify the image\n");
+ return 5;
+ }
+
+ GLCD::Config.driverConfigs[displayNumber].upsideDown ^= upsideDown;
+ GLCD::Config.driverConfigs[displayNumber].invert ^= invert;
+ if (brightness != -1)
+ GLCD::Config.driverConfigs[displayNumber].brightness = brightness;
+ GLCD::cDriver * lcd = GLCD::CreateDriver(GLCD::Config.driverConfigs[displayNumber].id, &GLCD::Config.driverConfigs[displayNumber]);
+ if (!lcd) {
+ fprintf(stderr, "ERROR: Failed creating display object %s\n", displayName.c_str());
+ return 6;
+ }
+ if (lcd->Init() != 0) {
+ fprintf(stderr, "ERROR: Failed initializing display %s\n", displayName.c_str());
+ delete lcd;
+ return 7;
+ }
lcd->SetBrightness(GLCD::Config.driverConfigs[displayNumber].brightness);
- signal(SIGINT, sighandler);
- signal(SIGQUIT, sighandler);
- signal(SIGTERM, sighandler);
- signal(SIGHUP, sighandler);
-
- const GLCD::cBitmap * bitmap;
- GLCD::cImage image;
- GLCD::cGLCDFile glcd;
- int optFile;
- std::string picFile;
-
- optFile = optind;
- while (optFile < argc && !stopProgramm)
- {
- picFile = argv[optFile++];
- if (glcd.Load(image, picFile) == false)
- {
- fprintf(stderr, "ERROR: Failed loading file %s\n", picFile.c_str());
- delete lcd;
- return 8;
- }
-
- if (delay)
- image.SetDelay(sleepMs);
-
- while ((bitmap = image.GetBitmap()) != NULL && !stopProgramm)
- {
- lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height(), bitmap->LineSize());
- lcd->Refresh(true);
-
- if (image.Next(0)) // Select next image
- {
- usleep(image.Delay() * 1000);
- }
- else if (endless && argc == (optind + 1)) // Endless and one and only image
- {
- image.First(0);
- usleep(image.Delay() * 1000);
- }
- else
- break;
- }
-
- if (optFile < argc || endless)
- usleep(sleepMs * 1000);
- if (optFile >= argc && endless)
- optFile = optind;
- }
-
- lcd->DeInit();
- delete lcd;
-
- return 0;
+ signal(SIGINT, sighandler);
+ signal(SIGQUIT, sighandler);
+ signal(SIGTERM, sighandler);
+ signal(SIGHUP, sighandler);
+
+ const GLCD::cBitmap * bitmap;
+ GLCD::cImage image;
+
+ GLCD::cBitmap * buffer = new GLCD::cBitmap(lcd->Width(), lcd->Height());
+
+ int optFile;
+ std::string picFile;
+
+ optFile = optind;
+ while (optFile < argc && !stopProgramm) {
+ picFile = argv[optFile++];
+ if (GLCD::cImage::LoadImage(image, picFile) == false) {
+ fprintf(stderr, "ERROR: Failed loading file %s\n", picFile.c_str());
+ return 8;
+ }
+
+ if (scaleAlgo > 0) {
+ uint16_t scalew = 0;
+ uint16_t scaleh = 0;
+ uint16_t imagew = image.Width();
+ uint16_t imageh = image.Height();
+
+ switch (scaleAlgo) {
+ case 1:
+ case 2:
+ if (imagew > lcd->Width() || imageh > lcd->Height()) {
+ if ((double)imagew / (double)lcd->Width() > (double)imageh / (double)lcd->Height())
+ scalew = lcd->Width();
+ else
+ scaleh = lcd->Height();
+ } else if (scaleAlgo == 2 && imagew < lcd->Width() && imageh < lcd->Height()) {
+ if ((double)imagew / (double)lcd->Width() > (double)imageh / (double)lcd->Height())
+ scalew = lcd->Width();
+ else
+ scaleh = lcd->Height();
+ }
+ break;
+ default: /* 3 */
+ scalew = lcd->Width();
+ scaleh = lcd->Height();
+ }
+ image.Scale(scalew, scaleh, false);
+ }
+
+ if (delay)
+ image.SetDelay(sleepMs);
+
+
+ uint16_t xstart = 0;
+ uint16_t ystart = 0;
+
+ if (center) {
+ if ((unsigned int)(lcd->Width()) > image.Width())
+ xstart = (lcd->Width() - image.Width()) >> 1;
+ if ((unsigned int)(lcd->Height()) > image.Height())
+ ystart = (lcd->Height() - image.Height()) >> 1;
+ }
+
+ lcd->Refresh(true);
+ while ((bitmap = image.GetBitmap()) != NULL && !stopProgramm) {
+ buffer->Clear();
+ buffer->DrawBitmap(xstart, ystart, *bitmap);
+ lcd->SetScreen(buffer->Data(), buffer->Width(), buffer->Height());
+ lcd->Refresh(false);
+
+ if (image.Next(0)) { // Select next image
+ usleep(image.Delay() * 1000);
+ } else if (endless && argc == (optind + 1)) { // Endless and one and only image
+ image.First(0);
+ usleep(image.Delay() * 1000);
+ } else {
+ break;
+ }
+ }
+
+ if (optFile < argc || endless)
+ usleep(sleepMs * 1000);
+ if (optFile >= argc && endless)
+ optFile = optind;
+ }
+
+ delete buffer;
+ lcd->DeInit();
+ delete lcd;
+
+ return 0;
}
diff --git a/tools/showtext/Makefile b/tools/showtext/Makefile
index d43c986..516f966 100644
--- a/tools/showtext/Makefile
+++ b/tools/showtext/Makefile
@@ -18,14 +18,11 @@ all: $(PRGNAME)
# Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
# Dependencies:
-MAKEDEP = $(CXX) -MM -MG
-DEPFILE = .dependencies
-$(DEPFILE): Makefile
- @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+DEPFILE = $(OBJS:%.o=%.d)
-include $(DEPFILE)
@@ -36,7 +33,7 @@ $(PRGNAME): $(OBJS)
install: $(PRGNAME)
install -d $(BINDIR)
- install -m 755 -o root -g root $(STRIP) $(PRGNAME) $(BINDIR)
+ install -m 755 -o root -g root $(HAVE_STRIP) $(PRGNAME) $(BINDIR)
uninstall:
rm -f $(BINDIR)/$(PRGNAME)
diff --git a/tools/showtext/showtext.c b/tools/showtext/showtext.c
index 333d9e3..00e6893 100644
--- a/tools/showtext/showtext.c
+++ b/tools/showtext/showtext.c
@@ -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 <andreas.regel AT powarman.de>
+ * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de>
+ * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net>
+ * Andreas 'randy' Weinberger
*/
#include <stdio.h>
@@ -35,7 +37,7 @@ void usage()
{
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 @@ int main(int argc, char *argv[])
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();
diff --git a/tools/skintest/DejaVuSans.ttf b/tools/skintest/DejaVuSans.ttf
new file mode 100644
index 0000000..2375915
--- /dev/null
+++ b/tools/skintest/DejaVuSans.ttf
Binary files differ
diff --git a/tools/skintest/Makefile b/tools/skintest/Makefile
new file mode 100644
index 0000000..fe73388
--- /dev/null
+++ b/tools/skintest/Makefile
@@ -0,0 +1,42 @@
+#
+# Makefile for the GraphLCD tool showtext
+#
+
+-include ../../Make.config
+
+PRGNAME = skintest
+
+OBJS = skintest.o
+
+INCLUDES += -I../../
+LIBDIRS += -L../../glcdgraphics/ -L../../glcddrivers/ -L../../glcdskin/
+
+
+all: $(PRGNAME)
+.PHONY: all
+
+# Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXEXTRA) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+DEPFILE = $(OBJS:%.o=%.d)
+
+-include $(DEPFILE)
+
+# The main program:
+
+$(PRGNAME): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LDFLAGS) -rdynamic $(OBJS) $(LIBS) $(LIBDIRS) -lglcdgraphics -lglcddrivers -lglcdskin -lstdc++ -o $(PRGNAME)
+
+install: $(PRGNAME)
+ install -d $(BINDIR)
+ install -m 755 -o root -g root $(HAVE_STRIP) $(PRGNAME) $(BINDIR)
+
+uninstall:
+ rm -f $(BINDIR)/$(PRGNAME)
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) $(PRGNAME) *~
diff --git a/tools/skintest/skintest.c b/tools/skintest/skintest.c
new file mode 100644
index 0000000..747dd91
--- /dev/null
+++ b/tools/skintest/skintest.c
@@ -0,0 +1,190 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <glcdgraphics/bitmap.h>
+#include <glcdgraphics/font.h>
+#include <glcddrivers/config.h>
+#include <glcddrivers/driver.h>
+#include <glcddrivers/drivers.h>
+#include <glcdskin/parser.h>
+#include <glcdskin/skin.h>
+#include <glcdskin/config.h>
+#include <glcdskin/string.h>
+
+class cMySkinConfig : public GLCD::cSkinConfig
+{
+private:
+ GLCD::cDriver * mDriver;
+public:
+ cMySkinConfig(GLCD::cDriver * Driver);
+ virtual std::string SkinPath(void);
+ virtual std::string CharSet(void);
+ virtual std::string Translate(const std::string & Text);
+ virtual GLCD::cType GetToken(const GLCD::tSkinToken & Token);
+ virtual GLCD::cDriver * GetDriver(void) const { return mDriver; }
+};
+
+cMySkinConfig::cMySkinConfig(GLCD::cDriver * Driver)
+: mDriver(Driver)
+{
+}
+
+std::string cMySkinConfig::SkinPath(void)
+{
+ return ".";
+}
+
+std::string cMySkinConfig::CharSet(void)
+{
+ return "iso8859-15";
+}
+
+std::string cMySkinConfig::Translate(const std::string & Text)
+{
+ return Text;
+}
+
+GLCD::cType cMySkinConfig::GetToken(const GLCD::tSkinToken & Token)
+{
+ return 10;
+}
+
+
+static const char * kDefaultConfigFile = "/etc/graphlcd.conf";
+
+int main(int argc, char ** argv)
+{
+ static struct option long_options[] =
+ {
+ {"config", required_argument, NULL, 'c'},
+ {"display", required_argument, NULL, 'd'},
+ {"skin", required_argument, NULL, 's'},
+ {"upsidedown", no_argument, NULL, 'u'},
+ {"invert", no_argument, NULL, 'i'},
+ {"brightness", required_argument, NULL, 'b'},
+ {NULL}
+ };
+
+ std::string configName = "";
+ std::string displayName = "";
+ std::string skinFileName = "";
+ bool upsideDown = false;
+ bool invert = false;
+ int brightness = -1;
+ unsigned int displayNumber = 0;
+
+ int c, option_index = 0;
+ while ((c = getopt_long(argc, argv, "c:d:s:uib:", long_options, &option_index)) != -1)
+ {
+ switch (c)
+ {
+ case 'c':
+ configName = optarg;
+ break;
+
+ case 'd':
+ displayName = optarg;
+ break;
+
+ case 's':
+ skinFileName = optarg;
+ break;
+
+ case 'u':
+ upsideDown = true;
+ break;
+
+ case 'i':
+ invert = true;
+ break;
+
+ case 'b':
+ brightness = atoi(optarg);
+ if (brightness < 0) brightness = 0;
+ if (brightness > 100) brightness = 100;
+ break;
+
+ default:
+ //usage();
+ return 1;
+ }
+ }
+
+ if (configName.length() == 0)
+ {
+ configName = kDefaultConfigFile;
+ fprintf(stdout, "WARNING: No config file specified, using default (%s).\n", configName.c_str());
+ }
+
+ if (GLCD::Config.Load(configName) == false)
+ {
+ fprintf(stderr, "Error loading config file!\n");
+ return 1;
+ }
+ if (GLCD::Config.driverConfigs.size() > 0)
+ {
+ if (displayName.length() > 0)
+ {
+ for (displayNumber = 0; displayNumber < GLCD::Config.driverConfigs.size(); displayNumber++)
+ {
+ if (GLCD::Config.driverConfigs[displayNumber].name == displayName)
+ break;
+ }
+ if (displayNumber == GLCD::Config.driverConfigs.size())
+ {
+ fprintf(stderr, "ERROR: Specified display %s not found in config file!\n", displayName.c_str());
+ return 1;
+ }
+ }
+ else
+ {
+ fprintf(stdout, "WARNING: No display specified, using first one.\n");
+ displayNumber = 0;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: No displays specified in config file!\n");
+ return 1;
+ }
+
+ GLCD::Config.driverConfigs[displayNumber].upsideDown ^= upsideDown;
+ GLCD::Config.driverConfigs[displayNumber].invert ^= invert;
+ if (brightness != -1)
+ GLCD::Config.driverConfigs[displayNumber].brightness = brightness;
+
+ GLCD::cDriver * lcd = GLCD::CreateDriver(GLCD::Config.driverConfigs[displayNumber].id, &GLCD::Config.driverConfigs[displayNumber]);
+ if (!lcd)
+ {
+ fprintf(stderr, "ERROR: Failed creating display object %s\n", displayName.c_str());
+ return 9;
+ }
+ if (lcd->Init() != 0)
+ {
+ fprintf(stderr, "ERROR: Failed initializing display %s\n", displayName.c_str());
+ delete lcd;
+ return 10;
+ }
+
+ GLCD::cBitmap * screen = new GLCD::cBitmap(lcd->Width(), lcd->Height());
+ screen->Clear();
+
+ cMySkinConfig skinConfig(lcd);
+ GLCD::cSkin * skin = GLCD::XmlParse(skinConfig, "test", skinFileName);
+ skin->SetBaseSize(screen->Width(), screen->Height());
+ GLCD::cSkinDisplay * display = skin->GetDisplay("normal");
+
+ display->Render(screen);
+ lcd->SetScreen(screen->Data(), screen->Width(), screen->Height());
+ lcd->Refresh(true);
+
+ lcd->DeInit();
+ delete lcd;
+
+ return 0;
+}
diff --git a/tools/skintest/test.skin b/tools/skintest/test.skin
new file mode 100644
index 0000000..1632b03
--- /dev/null
+++ b/tools/skintest/test.skin
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<skin version="1.0" name="Demo">
+ <font id="small" url="ft2:DejaVuSans.ttf:10"/>
+ <font id="medium" url="ft2:DejaVuSans.ttf:20"/>
+ <font id="large" url="ft2:DejaVuSans.ttf:20"/>
+
+ <display id="normal">
+ <rectangle x1="0" x2="-1" y1="0" y2="-1" color="black" filled="yes"/>
+<!--
+ <rectangle x1="0" x2="100" y1="5" y2="25" color="white" filled="yes"/>
+ <rectangle x1="10" x2="20" y1="10" y2="20" color="black"/>
+ <rectangle x1="30" x2="40" y1="10" y2="20" color="black" filled="yes"/>
+ <rectangle x1="50" x2="60" y1="10" y2="20" color="black" radius="1"/>
+ <rectangle x1="70" x2="80" y1="10" y2="20" color="black" filled="yes" radius="1"/>
+ <rectangle x1="10" x2="20" y1="30" y2="40" color="white"/>
+ <rectangle x1="30" x2="40" y1="30" y2="40" color="white" filled="yes"/>
+ <rectangle x1="50" x2="60" y1="30" y2="40" color="white" radius="3"/>
+ <rectangle x1="70" x2="80" y1="30" y2="40" color="white" filled="yes" radius="1"/>
+ <line x1="10" x2="40" y1="50" y2="70" color="white" filled="yes" arc="0"/>
+ <line x1="50" x2="80" y1="50" y2="50" color="white" filled="yes" arc="1"/>
+ <line x1="90" x2="90" y1="50" y2="70" color="white" filled="yes" arc="2"/>
+ <slope x1="130" x2="160" y1="50" y2="70" color="white" filled="yes" arc="3"/>
+ <slope x1="170" x2="200" y1="50" y2="70" color="white" filled="yes" arc="4"/>
+ <slope x1="50" x2="80" y1="80" y2="100" color="white" filled="yes" arc="5"/>
+ <slope x1="90" x2="120" y1="80" y2="100" color="white" filled="yes" arc="6"/>
+ <slope x1="130" x2="160" y1="80" y2="100" color="white" filled="yes" arc="7"/>
+
+ <image x="100" y="60" color="white" path="ARTE_l.glcd"/>
+ <image x="100" y="50" color="white" path="ARTE_m.glcd"/>
+ <image x="50" y="50" color="white" condition="or(file('ARTE_m.glcd'),file('ARTE_l.glcd'))" path="ARTE_l.glcd"/>
+-->
+
+ <text x1="0" x2="-1" y1="0" y2="-1" color="white" align="left" font="medium">
+ This is a left aligned text.
+ </text>
+ <text x1="0" x2="-1" y1="20" y2="-1" color="blue" align="right" font="medium">
+ This is a right aligned text.
+ </text>
+ <text x1="0" x2="-1" y1="40" y2="-1" color="red" align="center" font="medium">
+ This is a centered text.
+ </text>
+ <text x1="0" x2="-1" y1="60" y2="-1" color="green" align="left" multiline="yes" font="medium">
+ This is a longer text that should be wrapped. It really works!
+ </text>
+<!--
+-->
+ <rectangle x1="10" x2="-10" y1="-30" y2="-10" color="white"/>
+ <progress x1="12" x2="-12" y1="-28" y2="-12" color="white" direction="0" current="{CurrentProgress}" total="20"/>
+ </display>
+</skin>