diff options
Diffstat (limited to 'glcddrivers')
58 files changed, 4590 insertions, 571 deletions
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 |