summaryrefslogtreecommitdiff
path: root/glcddrivers
diff options
context:
space:
mode:
authorandreas 'randy' weinberger <vdr@smue.org>2010-02-21 19:58:27 +0100
committerandreas 'randy' weinberger <vdr@smue.org>2010-02-21 19:58:27 +0100
commit10ab31fa86dbf9875b5f6baa6ac59fefaaf86be3 (patch)
tree60ad7c856565f03e145b2996d1bb5f9cd64c0532 /glcddrivers
downloadgraphlcd-base-10ab31fa86dbf9875b5f6baa6ac59fefaaf86be3.tar.gz
graphlcd-base-10ab31fa86dbf9875b5f6baa6ac59fefaaf86be3.tar.bz2
initial git upload, based on graphlcd-base-0.1.5
Diffstat (limited to 'glcddrivers')
-rw-r--r--glcddrivers/Makefile60
-rw-r--r--glcddrivers/avrctl.c355
-rw-r--r--glcddrivers/avrctl.h58
-rw-r--r--glcddrivers/common.c231
-rw-r--r--glcddrivers/common.h42
-rw-r--r--glcddrivers/config.c286
-rw-r--r--glcddrivers/config.h85
-rw-r--r--glcddrivers/driver.c54
-rw-r--r--glcddrivers/driver.h48
-rw-r--r--glcddrivers/drivers.c117
-rw-r--r--glcddrivers/drivers.h58
-rw-r--r--glcddrivers/framebuffer.c249
-rw-r--r--glcddrivers/framebuffer.h56
-rw-r--r--glcddrivers/g15daemon.c219
-rw-r--r--glcddrivers/g15daemon.h49
-rw-r--r--glcddrivers/gu126x64D-K610A4.c967
-rw-r--r--glcddrivers/gu126x64D-K610A4.h130
-rw-r--r--glcddrivers/gu140x32f.c443
-rw-r--r--glcddrivers/gu140x32f.h73
-rw-r--r--glcddrivers/gu256x64-372.c408
-rw-r--r--glcddrivers/gu256x64-372.h73
-rw-r--r--glcddrivers/gu256x64-3900.c651
-rw-r--r--glcddrivers/gu256x64-3900.h87
-rw-r--r--glcddrivers/hd61830.c391
-rw-r--r--glcddrivers/hd61830.h54
-rw-r--r--glcddrivers/image.c167
-rw-r--r--glcddrivers/image.h50
-rw-r--r--glcddrivers/ks0108.c593
-rw-r--r--glcddrivers/ks0108.h78
-rw-r--r--glcddrivers/network.c267
-rw-r--r--glcddrivers/network.h56
-rw-r--r--glcddrivers/noritake800.c537
-rw-r--r--glcddrivers/noritake800.h92
-rw-r--r--glcddrivers/port.c350
-rw-r--r--glcddrivers/port.h78
-rw-r--r--glcddrivers/sed1330.c630
-rw-r--r--glcddrivers/sed1330.h78
-rw-r--r--glcddrivers/sed1520.c402
-rw-r--r--glcddrivers/sed1520.h72
-rw-r--r--glcddrivers/serdisp.c467
-rw-r--r--glcddrivers/serdisp.h78
-rw-r--r--glcddrivers/simlcd.c183
-rw-r--r--glcddrivers/simlcd.h48
-rw-r--r--glcddrivers/t6963c.c678
-rw-r--r--glcddrivers/t6963c.h76
45 files changed, 10224 insertions, 0 deletions
diff --git a/glcddrivers/Makefile b/glcddrivers/Makefile
new file mode 100644
index 0000000..bd4f375
--- /dev/null
+++ b/glcddrivers/Makefile
@@ -0,0 +1,60 @@
+#
+# Makefile for the GraphLCD driver library
+#
+
+-include ../Make.config
+
+CXXFLAGS += -fPIC
+
+VERMAJOR = 1
+VERMINOR = 0
+VERMICRO = 0
+
+BASENAME = libglcddrivers.so
+
+LIBNAME = $(BASENAME).$(VERMAJOR).$(VERMINOR).$(VERMICRO)
+
+OBJS = common.o config.o driver.o drivers.o port.o simlcd.o framebuffer.o gu140x32f.o gu256x64-372.o gu256x64-3900.o hd61830.o ks0108.o image.o sed1330.o sed1520.o t6963c.o noritake800.o serdisp.o avrctl.o g15daemon.o network.o gu126x64D-K610A4.o
+
+HEADERS = config.h driver.h drivers.h
+
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = g++ -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: $(LIBNAME)
+
+$(LIBNAME): $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -ldl -lpthread -Wl,-soname="$(BASENAME).$(VERMAJOR)" -o $@
+ ln -sf $(LIBNAME) $(BASENAME)
+
+install: all
+ install -d $(LIBDIR)
+ install -m 755 $(LIBNAME) $(LIBDIR)/
+ install -d $(INCDIR)/glcddrivers
+ install -m 644 $(HEADERS) $(INCDIR)/glcddrivers/
+ ( cd $(LIBDIR); ln -sf $(LIBNAME) $(BASENAME).$(VERMAJOR); ln -sf $(LIBNAME) $(BASENAME) )
+
+uninstall:
+ rm -f $(LIBDIR)/$(BASENAME)
+ rm -f $(LIBDIR)/$(BASENAME).$(VERMAJOR)
+ rm -f $(LIBDIR)/$(LIBNAME)
+ (for i in $(HEADERS); do rm -f $(INCDIR)/glcddrivers/$$i; done)
+ rmdir $(INCDIR)/glcddrivers
+
+clean:
+ rm -f $(OBJS) $(DEPFILE) $(LIBNAME) $(BASENAME) *~
+
diff --git a/glcddrivers/avrctl.c b/glcddrivers/avrctl.c
new file mode 100644
index 0000000..4e1e4ea
--- /dev/null
+++ b/glcddrivers/avrctl.c
@@ -0,0 +1,355 @@
+/*
+ * GraphLCD driver library
+ *
+ * avrctl.c - AVR controlled LCD driver class
+ *
+ * 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>
+ */
+
+#include <stdint.h>
+#include <syslog.h>
+
+#include "common.h"
+#include "config.h"
+#include "port.h"
+#include "avrctl.h"
+
+
+namespace GLCD
+{
+
+/* command header:
+** 8 bits sync byte (0xAA for sent commands, 0x55 for received commands)
+** 8 bits command id
+** 16 bits command length (excluding header)
+*/
+const unsigned char CMD_HDR_SYNC = 0;
+const unsigned char CMD_HDR_COMMAND = 1;
+const unsigned char CMD_HDR_LENGTH = 2;
+const unsigned char CMD_DATA_START = 4;
+
+const unsigned char CMD_SYNC_SEND = 0xAA;
+const unsigned char CMD_SYNC_RECV = 0x55;
+
+const unsigned char CMD_SYS_SYNC = 0x00;
+const unsigned char CMD_SYS_ACK = 0x01;
+
+const unsigned char CMD_DISP_CLEAR_SCREEN = 0x10;
+const unsigned char CMD_DISP_SWITCH_SCREEN = 0x11;
+const unsigned char CMD_DISP_SET_BRIGHTNESS = 0x12;
+const unsigned char CMD_DISP_SET_COL_DATA = 0x13;
+const unsigned char CMD_DISP_SET_ROW_DATA = 0x14;
+const unsigned char CMD_DISP_UPDATE = 0x15;
+
+const int kBufferWidth = 256;
+const int kBufferHeight = 128;
+
+
+cDriverAvrCtl::cDriverAvrCtl(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ port = new cSerialPort();
+
+ //width = config->width;
+ //height = config->height;
+ refreshCounter = 0;
+}
+
+cDriverAvrCtl::~cDriverAvrCtl()
+{
+ delete port;
+ delete oldConfig;
+}
+
+int cDriverAvrCtl::Init()
+{
+ int x;
+
+ width = config->width;
+ if (width <= 0)
+ width = 256;
+ height = config->height;
+ if (height <= 0)
+ height = 128;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "")
+ {
+ }
+ }
+
+ // setup lcd array (wanted state)
+ newLCD = new unsigned char*[kBufferWidth];
+ if (newLCD)
+ {
+ for (x = 0; x < kBufferWidth; x++)
+ {
+ newLCD[x] = new unsigned char[(kBufferHeight + 7) / 8];
+ memset(newLCD[x], 0, (kBufferHeight + 7) / 8);
+ }
+ }
+ // setup lcd array (current state)
+ oldLCD = new unsigned char*[kBufferWidth];
+ if (oldLCD)
+ {
+ for (x = 0; x < kBufferWidth; x++)
+ {
+ oldLCD[x] = new unsigned char[(kBufferHeight + 7) / 8];
+ memset(oldLCD[x], 0, (kBufferHeight + 7) / 8);
+ }
+ }
+
+ if (config->device == "")
+ {
+ return -1;
+ }
+ if (port->Open(config->device.c_str()) != 0)
+ return -1;
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ syslog(LOG_INFO, "%s: AvrCtl initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverAvrCtl::DeInit()
+{
+ int x;
+ // free lcd array (wanted state)
+ if (newLCD)
+ {
+ for (x = 0; x < kBufferWidth; x++)
+ {
+ delete[] newLCD[x];
+ }
+ delete[] newLCD;
+ }
+ // free lcd array (current state)
+ if (oldLCD)
+ {
+ for (x = 0; x < kBufferWidth; x++)
+ {
+ delete[] oldLCD[x];
+ }
+ delete[] oldLCD;
+ }
+
+ if (port->Close() != 0)
+ return -1;
+ return 0;
+}
+
+int cDriverAvrCtl::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 cDriverAvrCtl::Clear()
+{
+ for (int x = 0; x < kBufferWidth; x++)
+ memset(newLCD[x], 0, (kBufferHeight + 7) / 8);
+}
+
+void cDriverAvrCtl::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);
+ }
+ }
+}
+
+void cDriverAvrCtl::Refresh(bool refreshAll)
+{
+ int x;
+ int y;
+ int i;
+ int num = kBufferWidth / 2;
+ unsigned char data[16*num];
+
+ if (CheckSetup() == 1)
+ refreshAll = true;
+
+ if (config->refreshDisplay > 0)
+ {
+ refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !refreshCounter)
+ refreshAll = true;
+ }
+
+ refreshAll = true;
+ if (refreshAll)
+ {
+ for (x = 0; x < kBufferWidth; x += num)
+ {
+ for (i = 0; i < num; i++)
+ {
+ for (y = 0; y < (kBufferHeight + 7) / 8; y++)
+ {
+ data[i * ((kBufferHeight + 7) / 8) + y] = (newLCD[x + i][y]) ^ (config->invert ? 0xff : 0x00);
+ }
+ memcpy(oldLCD[x + i], newLCD[x + i], (kBufferHeight + 7) / 8);
+ }
+ CmdDispSetColData(x, 0, 16 * num, data);
+ }
+ CmdDispUpdate();
+ CmdDispSwitchScreen();
+ // and reset RefreshCounter
+ refreshCounter = 0;
+ }
+ else
+ {
+ // draw only the changed bytes
+ }
+}
+
+void cDriverAvrCtl::SetBrightness(unsigned int percent)
+{
+ CmdDispSetBrightness(percent);
+}
+
+int cDriverAvrCtl::WaitForAck(void)
+{
+ uint8_t cmd[4];
+ int len;
+ int timeout = 10000;
+
+ len = 0;
+ while (len < 4 && timeout > 0)
+ {
+ len += port->ReadData(&cmd[len]);
+ timeout--;
+ }
+ if (timeout == 0)
+ return 0;
+ return 1;
+}
+
+void cDriverAvrCtl::CmdSysSync(void)
+{
+ uint8_t cmd[4];
+
+ cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
+ cmd[CMD_HDR_COMMAND] = CMD_SYS_SYNC;
+ cmd[CMD_HDR_LENGTH] = 0;
+ cmd[CMD_HDR_LENGTH+1] = 0;
+
+ port->WriteData(cmd, 4);
+ WaitForAck();
+}
+
+void cDriverAvrCtl::CmdDispClearScreen(void)
+{
+ uint8_t cmd[4];
+
+ cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
+ cmd[CMD_HDR_COMMAND] = CMD_DISP_CLEAR_SCREEN;
+ cmd[CMD_HDR_LENGTH] = 0;
+ cmd[CMD_HDR_LENGTH+1] = 0;
+
+ port->WriteData(cmd, 4);
+ WaitForAck();
+}
+
+void cDriverAvrCtl::CmdDispSwitchScreen(void)
+{
+ uint8_t cmd[4];
+
+ cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
+ cmd[CMD_HDR_COMMAND] = CMD_DISP_SWITCH_SCREEN;
+ cmd[CMD_HDR_LENGTH] = 0;
+ cmd[CMD_HDR_LENGTH+1] = 0;
+
+ port->WriteData(cmd, 4);
+ WaitForAck();
+}
+
+void cDriverAvrCtl::CmdDispSetBrightness(uint8_t percent)
+{
+ uint8_t cmd[5];
+
+ cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
+ cmd[CMD_HDR_COMMAND] = CMD_DISP_SET_BRIGHTNESS;
+ cmd[CMD_HDR_LENGTH] = 0;
+ cmd[CMD_HDR_LENGTH+1] = 1;
+ cmd[CMD_DATA_START] = percent;
+
+ port->WriteData(cmd, 5);
+ WaitForAck();
+}
+
+void cDriverAvrCtl::CmdDispSetColData(uint16_t column, uint16_t offset, uint16_t length, uint8_t * data)
+{
+ uint8_t cmd[2560];
+
+ cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
+ cmd[CMD_HDR_COMMAND] = CMD_DISP_SET_COL_DATA;
+ cmd[CMD_HDR_LENGTH] = (length + 6) >> 8;
+ cmd[CMD_HDR_LENGTH+1] = (length + 6);
+ cmd[CMD_DATA_START] = column >> 8;
+ cmd[CMD_DATA_START+1] = column;
+ cmd[CMD_DATA_START+2] = offset >> 8;
+ cmd[CMD_DATA_START+3] = offset;
+ cmd[CMD_DATA_START+4] = length >> 8;
+ cmd[CMD_DATA_START+5] = length;
+ memcpy(&cmd[CMD_DATA_START+6], data, length);
+
+ port->WriteData(cmd, length+10);
+ WaitForAck();
+}
+
+void cDriverAvrCtl::CmdDispUpdate(void)
+{
+ uint8_t cmd[4];
+
+ cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
+ cmd[CMD_HDR_COMMAND] = CMD_DISP_UPDATE;
+ cmd[CMD_HDR_LENGTH] = 0;
+ cmd[CMD_HDR_LENGTH+1] = 0;
+
+ port->WriteData(cmd, 4);
+ WaitForAck();
+}
+
+}
diff --git a/glcddrivers/avrctl.h b/glcddrivers/avrctl.h
new file mode 100644
index 0000000..557b7d2
--- /dev/null
+++ b/glcddrivers/avrctl.h
@@ -0,0 +1,58 @@
+/*
+ * GraphLCD driver library
+ *
+ * avrctl.h - AVR controlled LCD driver class
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_AVRCTL_H_
+#define _GLCDDRIVERS_AVRCTL_H_
+
+#include "driver.h"
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cSerialPort;
+
+class cDriverAvrCtl : public cDriver
+{
+private:
+ cSerialPort * port;
+ unsigned char ** newLCD; // wanted state
+ unsigned char ** oldLCD; // current state
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ int refreshCounter;
+
+ int WaitForAck(void);
+ void CmdSysSync(void);
+ void CmdDispClearScreen(void);
+ void CmdDispSwitchScreen(void);
+ void CmdDispSetBrightness(unsigned char percent);
+ void CmdDispSetColData(uint16_t column, uint16_t offset, uint16_t length, uint8_t * data);
+ void CmdDispUpdate(void);
+
+ int CheckSetup();
+
+public:
+ cDriverAvrCtl(cDriverConfig * config);
+ virtual ~cDriverAvrCtl();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ 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/common.c b/glcddrivers/common.c
new file mode 100644
index 0000000..0d0fad9
--- /dev/null
+++ b/glcddrivers/common.c
@@ -0,0 +1,231 @@
+/*
+ * GraphLCD driver library
+ *
+ * common.c - various functions
+ *
+ * parts were taken from graphlcd plugin for the Video Disc Recorder
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ *
+ * 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>
+ */
+
+#include <ctype.h>
+#include <sched.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include "common.h"
+#include "config.h"
+
+
+namespace GLCD
+{
+
+static const int BitReverseTable[256] =
+{
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+int nSleepInit()
+{
+ int ret = 0;
+
+ if (Config.waitPriority != 0)
+ {
+ ret = setpriority(PRIO_PROCESS, 0, Config.waitPriority);
+ }
+
+ if (!ret)
+ {
+ switch (Config.waitMethod)
+ {
+ case kWaitUsleep: // usleep
+ break;
+ case kWaitNanosleep: // nanosleep
+ break;
+ case kWaitNanosleepRR: // nanosleep (sched_rr)
+ // set sched algorithm
+ struct sched_param param;
+
+ param.sched_priority=1;
+ ret = sched_setscheduler(0, SCHED_RR, &param);
+ break;
+ case kWaitGettimeofday: // gettimeofday
+ break;
+ }
+ }
+ return ret;
+}
+
+int nSleepDeInit()
+{
+ int ret = 0;
+
+ if (Config.waitPriority != 0)
+ {
+ ret = setpriority(PRIO_PROCESS, 0, 0);
+ }
+
+ if (!ret)
+ {
+ switch (Config.waitMethod)
+ {
+ case kWaitUsleep: // usleep
+ break;
+ case kWaitNanosleep: // nanosleep
+ break;
+ case kWaitNanosleepRR: // nanosleep (sched_rr)
+ // set sched algorithm
+ struct sched_param param;
+
+ param.sched_priority=0;
+ ret = sched_setscheduler(0, SCHED_OTHER, &param);
+ break;
+ case kWaitGettimeofday: // gettimeofday
+ break;
+ }
+ }
+ return ret;
+}
+
+void nSleep(long ns)
+{
+ switch (Config.waitMethod)
+ {
+ case kWaitUsleep: // usleep
+ if (ns > 0)
+ {
+ usleep(std::max(1L, ns/1000));
+ }
+ break;
+ case kWaitNanosleep: // nanosleep
+ case kWaitNanosleepRR: // nanosleep(sched_rr)
+ struct timespec delay, remaining;
+ if (ns > 0)
+ {
+ delay.tv_sec = ns/1000000000;
+ delay.tv_nsec = ns%1000000000;
+ while (nanosleep(&delay, &remaining) == -1)
+ {
+ delay.tv_sec = remaining.tv_sec;
+ delay.tv_nsec = remaining.tv_nsec;
+ }
+ }
+ break;
+ case kWaitGettimeofday: //getTimeofday for Kernel 2.6
+ long us;
+ struct timeval tv1, tv2;
+ suseconds_t us2;
+ if (ns > 0)
+ {
+ us = ns / 1000;
+ if (us == 0)
+ us = 1;
+ gettimeofday(&tv1, 0);
+ do
+ {
+ gettimeofday(&tv2, 0);
+ us2 = tv2.tv_usec + ((tv2.tv_sec - tv1.tv_sec) * 1000000);
+ } while (us2 - tv1.tv_usec < us);
+ }
+ }
+}
+
+void uSleep(long us)
+{
+ if (Config.waitMethod == kWaitUsleep)
+ {
+ // usleep
+ if (us > 0)
+ usleep(std::max(1L, us));
+ }
+ else
+ {
+ nSleep(us * 1000);
+ }
+}
+
+
+
+unsigned char ReverseBits(unsigned char value)
+{
+ return BitReverseTable[value];
+}
+
+void clip(int & value, int min, int max)
+{
+ if (value < min)
+ value = min;
+ if (value > max)
+ value = max;
+}
+
+void sort(int & value1, int & value2)
+{
+ if (value2 < value1)
+ {
+ int tmp;
+ tmp = value2;
+ value2 = value1;
+ value1 = tmp;
+ }
+}
+
+std::string trim(const std::string & s)
+{
+ std::string::size_type start, end;
+
+ start = 0;
+ while (start < s.length())
+ {
+ if (!isspace(s[start]))
+ break;
+ start++;
+ }
+ end = s.length() - 1;
+ while (end >= 0)
+ {
+ if (!isspace(s[end]))
+ break;
+ end--;
+ }
+ return s.substr(start, end - start + 1);
+}
+
+} // end of namespace
diff --git a/glcddrivers/common.h b/glcddrivers/common.h
new file mode 100644
index 0000000..d1ddcda
--- /dev/null
+++ b/glcddrivers/common.h
@@ -0,0 +1,42 @@
+/*
+ * GraphLCD driver library
+ *
+ * common.c - various functions
+ *
+ * parts were taken from graphlcd plugin for the Video Disc Recorder
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_COMMON_H_
+#define _GLCDDRIVERS_COMMON_H_
+
+#include <string>
+
+namespace GLCD
+{
+
+const unsigned char bitmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+const unsigned char bitmaskl[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
+const unsigned char bitmaskr[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+// functions to enable/disable very short sleeps.
+// Therefore, the priority will be changed. => use with care !
+int nSleepInit(void);
+int nSleepDeInit(void);
+
+void nSleep(long ns);
+void uSleep(long us);
+
+unsigned char ReverseBits(unsigned char value);
+void clip(int & value, int min, int max);
+void sort(int & value1, int & value2);
+std::string trim(const std::string & s);
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/config.c b/glcddrivers/config.c
new file mode 100644
index 0000000..fec3372
--- /dev/null
+++ b/glcddrivers/config.c
@@ -0,0 +1,286 @@
+/*
+ * GraphLCD driver library
+ *
+ * config.c - config file classes
+ *
+ * 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>
+ */
+
+#include <syslog.h>
+#include <fstream>
+
+#include "common.h"
+#include "config.h"
+#include "drivers.h"
+
+
+namespace GLCD
+{
+
+cDriverConfig::cDriverConfig()
+: name(""),
+ driver(""),
+ id(kDriverUnknown),
+ device(""),
+ port(0),
+ width(0),
+ height(0),
+ upsideDown(false),
+ invert(false),
+ brightness(100),
+ contrast(5),
+ backlight(true),
+ adjustTiming(0),
+ refreshDisplay(5)
+{
+}
+
+cDriverConfig::cDriverConfig(const cDriverConfig & rhs)
+{
+ name = rhs.name;
+ driver = rhs.driver;
+ id = rhs.id;
+ device = rhs.device;
+ port = rhs.port;
+ width = rhs.width;
+ height = rhs.height;
+ upsideDown = rhs.upsideDown;
+ invert = rhs.invert;
+ brightness = rhs.brightness;
+ contrast = rhs.contrast;
+ backlight = rhs.backlight;
+ adjustTiming = rhs.adjustTiming;
+ refreshDisplay = rhs.refreshDisplay;
+ for (unsigned int i = 0; i < rhs.options.size(); i++)
+ options.push_back(rhs.options[i]);
+}
+
+cDriverConfig::~cDriverConfig()
+{
+}
+
+cDriverConfig & cDriverConfig::operator=(const cDriverConfig & rhs)
+{
+ if (this == &rhs)
+ return *this;
+
+ name = rhs.name;
+ driver = rhs.driver;
+ id = rhs.id;
+ device = rhs.device;
+ port = rhs.port;
+ width = rhs.width;
+ height = rhs.height;
+ upsideDown = rhs.upsideDown;
+ invert = rhs.invert;
+ brightness = rhs.brightness;
+ contrast = rhs.contrast;
+ backlight = rhs.backlight;
+ adjustTiming = rhs.adjustTiming;
+ refreshDisplay = rhs.refreshDisplay;
+ options.clear();
+ for (unsigned int i = 0; i < rhs.options.size(); i++)
+ options.push_back(rhs.options[i]);
+
+ return *this;
+}
+
+bool cDriverConfig::Parse(const std::string & line)
+{
+ std::string::size_type pos;
+ tOption option;
+
+ pos = line.find("=");
+ if (pos == std::string::npos)
+ return false;
+ option.name = trim(line.substr(0, pos));
+ option.value = trim(line.substr(pos + 1));
+ //printf("D %s = %s\n", option.name.c_str(), option.value.c_str());
+
+ if (option.name == "Driver")
+ {
+ int driverCount;
+ tDriver * drivers = GetAvailableDrivers(driverCount);
+ for (int i = 0; i < driverCount; i++)
+ {
+ if (option.value == drivers[i].name)
+ {
+ driver = drivers[i].name;
+ id = drivers[i].id;
+ break;
+ }
+ }
+ }
+ else if (option.name == "Device")
+ {
+ device = option.value;
+ }
+ else if (option.name == "Port")
+ {
+ port = GetInt(option.value);
+ }
+ else if (option.name == "Width")
+ {
+ width = GetInt(option.value);
+ }
+ else if (option.name == "Height")
+ {
+ height = GetInt(option.value);
+ }
+ else if (option.name == "UpsideDown")
+ {
+ upsideDown = GetBool(option.value);
+ }
+ else if (option.name == "Invert")
+ {
+ invert = GetBool(option.value);
+ }
+ else if (option.name == "Brightness")
+ {
+ brightness = GetInt(option.value);
+ }
+ else if (option.name == "Contrast")
+ {
+ contrast = GetInt(option.value);
+ }
+ else if (option.name == "Backlight")
+ {
+ backlight = GetBool(option.value);
+ }
+ else if (option.name == "AdjustTiming")
+ {
+ adjustTiming = GetInt(option.value);
+ }
+ else if (option.name == "RefreshDisplay")
+ {
+ refreshDisplay = GetInt(option.value);
+ }
+ else
+ {
+ options.push_back(option);
+ }
+ return true;
+}
+
+int cDriverConfig::GetInt(const std::string & value)
+{
+ return strtol(value.c_str(), NULL, 0);
+}
+
+bool cDriverConfig::GetBool(const std::string & value)
+{
+ return value == "yes";
+}
+
+
+cConfig::cConfig()
+: waitMethod(kWaitGettimeofday),
+ waitPriority(0)
+{
+}
+
+cConfig::~cConfig()
+{
+}
+
+bool cConfig::Load(const std::string & filename)
+{
+ std::fstream file;
+ char readLine[1000];
+ std::string line;
+ bool inSections = false;
+ int section = 0;
+
+#if (__GNUC__ < 3)
+ file.open(filename.c_str(), std::ios::in);
+#else
+ file.open(filename.c_str(), std::ios_base::in);
+#endif
+ if (!file.is_open())
+ return false;
+
+ while (!file.eof())
+ {
+ file.getline(readLine, 1000);
+ line = trim(readLine);
+ if (line.length() == 0)
+ continue;
+ if (line[0] == '#')
+ continue;
+ if (line[0] == '[' && line[line.length() - 1] == ']')
+ {
+ if (!inSections)
+ inSections = true;
+ else
+ section++;
+ driverConfigs.resize(section + 1);
+ driverConfigs[section].name = line.substr(1, line.length() - 2);
+ continue;
+ }
+ if (!inSections)
+ {
+ Parse(line);
+ }
+ else
+ {
+ driverConfigs[section].Parse(line);
+ }
+ }
+
+ file.close();
+ return true;
+}
+
+bool cConfig::Parse(const std::string & line)
+{
+ std::string::size_type pos;
+ tOption option;
+
+ pos = line.find("=");
+ if (pos == std::string::npos)
+ return false;
+ option.name = trim(line.substr(0, pos));
+ option.value = trim(line.substr(pos + 1));
+ //printf("%s = %s\n", option.name.c_str(), option.value.c_str());
+
+ if (option.name == "WaitMethod")
+ {
+ waitMethod = GetInt(option.value);
+ }
+ else if (option.name == "WaitPriority")
+ {
+ waitPriority = GetInt(option.value);
+ }
+ else
+ {
+ syslog(LOG_ERR, "Config error: unknown option %s given!\n", option.value.c_str());
+ return false;
+ }
+ return true;
+}
+
+int cConfig::GetInt(const std::string & value)
+{
+ return strtol(value.c_str(), NULL, 0);
+}
+
+bool cConfig::GetBool(const std::string & value)
+{
+ return value == "yes";
+}
+
+int cConfig::GetConfigIndex(const std::string & name)
+{
+ for (int i = 0; i < (int)driverConfigs.size(); i++)
+ if (driverConfigs[i].name == name)
+ return i;
+ syslog(LOG_ERR, "Config error: configuration %s not found!\n", name.c_str());
+ return -1;
+}
+
+cConfig Config;
+
+} // end of namespace
diff --git a/glcddrivers/config.h b/glcddrivers/config.h
new file mode 100644
index 0000000..8caa77e
--- /dev/null
+++ b/glcddrivers/config.h
@@ -0,0 +1,85 @@
+/*
+ * GraphLCD driver library
+ *
+ * config.h - config file classes
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_CONFIG_H_
+#define _GLCDDRIVERS_CONFIG_H_
+
+#include <string>
+#include <vector>
+
+
+namespace GLCD
+{
+
+const int kWaitUsleep = 0;
+const int kWaitNanosleep = 1;
+const int kWaitNanosleepRR = 2;
+const int kWaitGettimeofday = 3;
+
+
+struct tOption
+{
+ std::string name;
+ std::string value;
+};
+
+class cDriverConfig
+{
+public:
+ std::string name;
+ std::string driver;
+ int id;
+ std::string device;
+ int port;
+ int width;
+ int height;
+ bool upsideDown;
+ bool invert;
+ int brightness;
+ int contrast;
+ bool backlight;
+ int adjustTiming;
+ int refreshDisplay;
+ std::vector <tOption> options;
+
+public:
+ cDriverConfig();
+ cDriverConfig(const cDriverConfig & rhs);
+ ~cDriverConfig();
+ cDriverConfig & operator=(const cDriverConfig & rhs);
+ bool Parse(const std::string & line);
+ int GetInt(const std::string & value);
+ bool GetBool(const std::string & value);
+};
+
+class cConfig
+{
+public:
+ int waitMethod;
+ int waitPriority;
+ std::vector <cDriverConfig> driverConfigs;
+
+public:
+ cConfig();
+ ~cConfig();
+ bool Load(const std::string & filename);
+ bool Save(const std::string & filename);
+ bool Parse(const std::string & line);
+ int GetInt(const std::string & value);
+ bool GetBool(const std::string & value);
+ int GetConfigIndex(const std::string & name);
+};
+
+extern cConfig Config;
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/driver.c b/glcddrivers/driver.c
new file mode 100644
index 0000000..b1b6286
--- /dev/null
+++ b/glcddrivers/driver.c
@@ -0,0 +1,54 @@
+/*
+ * GraphLCD driver library
+ *
+ * driver.c - driver base class
+ *
+ * parts were taken from graphlcd plugin for the Video Disc Recorder
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ *
+ * 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>
+ */
+
+#include "common.h"
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+cDriver::cDriver()
+: width(0),
+ height(0)
+{
+}
+
+void cDriver::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]);
+ }
+ }
+ }
+}
+
+} // end of namespace
diff --git a/glcddrivers/driver.h b/glcddrivers/driver.h
new file mode 100644
index 0000000..1d82eaa
--- /dev/null
+++ b/glcddrivers/driver.h
@@ -0,0 +1,48 @@
+/*
+ * GraphLCD driver library
+ *
+ * driver.h - driver base class
+ *
+ * parts were taken from graphlcd plugin for the Video Disc Recorder
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_DRIVER_H_
+#define _GLCDDRIVERS_DRIVER_H_
+
+#include <stdint.h>
+
+namespace GLCD
+{
+
+class cDriver
+{
+protected:
+ int width;
+ int height;
+public:
+ cDriver();
+ virtual ~cDriver() {}
+
+ int Width() const { return width; }
+ int Height() const { return height; }
+
+ 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 Refresh(bool refreshAll = false) {}
+
+ virtual void SetBrightness(unsigned int percent) {}
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/drivers.c b/glcddrivers/drivers.c
new file mode 100644
index 0000000..ff1e439
--- /dev/null
+++ b/glcddrivers/drivers.c
@@ -0,0 +1,117 @@
+/*
+ * GraphLCD driver library
+ *
+ * drivers.c - global driver constants and functions
+ *
+ * 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>
+ */
+
+#include <string.h>
+
+#include "drivers.h"
+#include "simlcd.h"
+#include "gu140x32f.h"
+#include "gu256x64-372.h"
+#include "gu256x64-3900.h"
+#include "hd61830.h"
+#include "ks0108.h"
+#include "sed1330.h"
+#include "sed1520.h"
+#include "t6963c.h"
+#include "framebuffer.h"
+#include "image.h"
+#include "noritake800.h"
+#include "avrctl.h"
+#include "network.h"
+#include "gu126x64D-K610A4.h"
+#include "serdisp.h"
+#include "g15daemon.h"
+
+namespace GLCD
+{
+
+tDriver drivers[] =
+{
+ {"simlcd", kDriverSimLCD},
+ {"gu140x32f", kDriverGU140X32F},
+ {"gu256x64-372", kDriverGU256X64_372},
+ {"gu256x64-3900", kDriverGU256X64_3900},
+ {"hd61830", kDriverHD61830},
+ {"ks0108", kDriverKS0108},
+ {"sed1330", kDriverSED1330},
+ {"sed1520", kDriverSED1520},
+ {"t6963c", kDriverT6963C},
+ {"framebuffer", kDriverFramebuffer},
+ {"image", kDriverImage},
+ {"noritake800", kDriverNoritake800},
+ {"avrctl", kDriverAvrCtl},
+ {"network", kDriverNetwork},
+ {"gu126x64D-K610A4", kDriverGU126X64D_K610A4},
+ {"serdisp", kDriverSerDisp},
+ {"g15daemon", kDriverG15daemon},
+ {"", kDriverUnknown}
+};
+
+tDriver * GetAvailableDrivers(int & count)
+{
+ for (count = 0; drivers[count].name.length() > 0; count++)
+ ;
+ return drivers;
+}
+
+int GetDriverID(const std::string & driver)
+{
+ for (int i = 0; drivers[i].name.length() > 0; i++)
+ if (drivers[i].name == driver)
+ return drivers[i].id;
+ return kDriverUnknown;
+}
+
+cDriver * CreateDriver(int driverID, cDriverConfig * config)
+{
+ switch (driverID)
+ {
+ case kDriverSimLCD:
+ return new cDriverSimLCD(config);
+ case kDriverGU140X32F:
+ return new cDriverGU140X32F(config);
+ case kDriverGU256X64_372:
+ return new cDriverGU256X64_372(config);
+ case kDriverGU256X64_3900:
+ return new cDriverGU256X64_3900(config);
+ case kDriverHD61830:
+ return new cDriverHD61830(config);
+ case kDriverKS0108:
+ return new cDriverKS0108(config);
+ case kDriverSED1330:
+ return new cDriverSED1330(config);
+ case kDriverSED1520:
+ return new cDriverSED1520(config);
+ case kDriverT6963C:
+ return new cDriverT6963C(config);
+ case kDriverFramebuffer:
+ return new cDriverFramebuffer(config);
+ case kDriverImage:
+ return new cDriverImage(config);
+ case kDriverNoritake800:
+ return new cDriverNoritake800(config);
+ case kDriverAvrCtl:
+ return new cDriverAvrCtl(config);
+ case kDriverNetwork:
+ return new cDriverNetwork(config);
+ case kDriverGU126X64D_K610A4:
+ return new cDriverGU126X64D_K610A4(config);
+ case kDriverSerDisp:
+ return new cDriverSerDisp(config);
+ case kDriverG15daemon:
+ return new cDriverG15daemon(config);
+ case kDriverUnknown:
+ default:
+ return NULL;
+ }
+}
+
+} // end of namespace
diff --git a/glcddrivers/drivers.h b/glcddrivers/drivers.h
new file mode 100644
index 0000000..f51ea1d
--- /dev/null
+++ b/glcddrivers/drivers.h
@@ -0,0 +1,58 @@
+/*
+ * GraphLCD driver library
+ *
+ * drivers.h - global driver constants and functions
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_DRIVERS_H_
+#define _GLCDDRIVERS_DRIVERS_H_
+
+#include <string>
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cDriver;
+
+enum eDriver
+{
+ kDriverUnknown = 0,
+ kDriverSimLCD = 1,
+ kDriverGU140X32F = 2,
+ kDriverGU256X64_372 = 3,
+ kDriverGU256X64_3900 = 4,
+ kDriverHD61830 = 5,
+ kDriverKS0108 = 6,
+ kDriverSED1330 = 7,
+ kDriverSED1520 = 8,
+ kDriverT6963C = 9,
+ kDriverFramebuffer = 10,
+ kDriverImage = 11,
+ kDriverNoritake800 = 12,
+ kDriverAvrCtl = 13,
+ kDriverNetwork = 14,
+ kDriverGU126X64D_K610A4 = 15,
+ kDriverSerDisp = 100,
+ kDriverG15daemon = 200
+};
+
+struct tDriver
+{
+ std::string name;
+ eDriver id;
+};
+
+tDriver * GetAvailableDrivers(int & count);
+int GetDriverID(const std::string & driver);
+cDriver * CreateDriver(int driverID, cDriverConfig * config);
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/framebuffer.c b/glcddrivers/framebuffer.c
new file mode 100644
index 0000000..f9666fa
--- /dev/null
+++ b/glcddrivers/framebuffer.c
@@ -0,0 +1,249 @@
+/*
+ * GraphLCD driver library
+ *
+ * framebuffer.h - framebuffer device
+ * Output goes to a framebuffer device
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2004 Stephan Skrodzki
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "config.h"
+#include "framebuffer.h"
+
+
+namespace GLCD
+{
+
+cDriverFramebuffer::cDriverFramebuffer(cDriverConfig * config)
+: config(config),
+ offbuff(0),
+ fbfd(-1)
+{
+ oldConfig = new cDriverConfig(*config);
+}
+
+cDriverFramebuffer::~cDriverFramebuffer()
+{
+ delete oldConfig;
+}
+
+int cDriverFramebuffer::Init()
+{
+ // default values
+ width = config->width;
+ if (width <= 0)
+ width = 320;
+ height = config->height;
+ if (height <= 0)
+ height = 240;
+ zoom = 1;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "Zoom")
+ {
+ int z = atoi(config->options[i].value.c_str());
+ if (z == 0 || z == 1)
+ zoom = z;
+ else
+ syslog(LOG_ERR, "%s error: zoom %d not supported, using default (%d)!\n",
+ config->name.c_str(), z, zoom);
+ }
+ }
+
+ // Open the file for reading and writing
+ fbfd = open("/dev/fb0", O_RDWR);
+ if (1 == fbfd)
+ {
+ syslog(LOG_ERR, "%s: cannot open framebuffer device.\n", config->name.c_str());
+ return -1;
+ }
+ syslog(LOG_INFO, "%s: The framebuffer device was opened successfully.\n", config->name.c_str());
+
+ // Get fixed screen information
+ if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
+ {
+ syslog(LOG_ERR, "%s: Error reading fixed information.\n", config->name.c_str());
+ return -1;
+ }
+
+ // Get variable screen information
+ if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
+ {
+ syslog(LOG_ERR, "%s: Error reading variable information.\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);
+
+ // reserve another memory to draw into
+ offbuff = new char[screensize];
+ if (!offbuff)
+ {
+ syslog(LOG_ERR, "%s: failed to alloc memory for framebuffer device.\n", config->name.c_str());
+ return -1;
+ }
+
+ // Map the device to memory
+ fbp = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
+ if (fbp == MAP_FAILED)
+ {
+ syslog(LOG_ERR, "%s: failed to map framebuffer device to memory.\n", config->name.c_str());
+ return -1;
+ }
+ syslog(LOG_INFO, "%s: The framebuffer device was mapped to memory successfully.\n", config->name.c_str());
+
+ *oldConfig = *config;
+
+ // clear display
+ Refresh(true);
+
+ syslog(LOG_INFO, "%s: Framebuffer initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverFramebuffer::DeInit()
+{
+ if (offbuff)
+ delete[] offbuff;
+ munmap(fbp, screensize);
+ if (-1 != fbfd)
+ close(fbfd);
+ return 0;
+}
+
+int cDriverFramebuffer::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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 cDriverFramebuffer::SetPixel(int x, int y)
+{
+ int location;
+ int outcol;
+
+ if (x >= width || y >= height)
+ return;
+
+ if (config->upsideDown)
+ {
+ x = width - 1 - x;
+ 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;
+ }
+
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+}
+
+void cDriverFramebuffer::Clear()
+{
+ memset(offbuff, 0, screensize);
+}
+
+void cDriverFramebuffer::Set8Pixels(int x, int y, unsigned char data)
+{
+ int n;
+
+ x &= 0xFFF8;
+
+ for (n = 0; n < 8; ++n)
+ {
+ if (data & (0x80 >> n)) // if bit is set
+ SetPixel(x + n, y);
+ }
+}
+
+void cDriverFramebuffer::Refresh(bool refreshAll)
+{
+ memcpy(fbp, offbuff, screensize);
+}
+
+} // end of namespace
diff --git a/glcddrivers/framebuffer.h b/glcddrivers/framebuffer.h
new file mode 100644
index 0000000..79d1d77
--- /dev/null
+++ b/glcddrivers/framebuffer.h
@@ -0,0 +1,56 @@
+/*
+ * GraphLCD driver library
+ *
+ * framebuffer.h - framebuffer device
+ * Output goes to a framebuffer device
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2004 Stephan Skrodzki
+ */
+
+#ifndef _GLCDDRIVERS_FRAMEBUFFER_H_
+#define _GLCDDRIVERS_FRAMEBUFFER_H_
+
+#include "driver.h"
+#include <linux/fb.h>
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+
+class cDriverFramebuffer : public cDriver
+{
+private:
+ unsigned char ** LCD;
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ char *offbuff;
+ int fbfd;
+ struct fb_var_screeninfo vinfo;
+ struct fb_fix_screeninfo finfo;
+ long int screensize;
+ void *fbp;
+ int zoom;
+
+ int CheckSetup();
+ void SetPixel(int x, int y);
+
+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 Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/g15daemon.c b/glcddrivers/g15daemon.c
new file mode 100644
index 0000000..f041b29
--- /dev/null
+++ b/glcddrivers/g15daemon.c
@@ -0,0 +1,219 @@
+/*
+* GraphLCD driver library
+*
+* g15daemon.c - pseudo device for the g15daemon meta driver
+* Output goes to the g15daemon which then displays it
+*
+* This file is released under the GNU General Public License. Refer
+* to the COPYING file distributed with this package.
+*
+*/
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "config.h"
+
+#include "g15daemon.h"
+
+#define G15SERVER_PORT 15550
+#define G15SERVER_ADDR "127.0.0.1"
+
+#define G15_WIDTH 160
+#define G15_HEIGHT 43
+
+
+static int g15_send(int sock, char *buf, int len)
+{
+ int total = 0;
+ int retval = 0;
+ int bytesleft = len;
+
+ while (total < len) {
+ retval = send(sock, buf+total, bytesleft, 0);
+ if (retval == -1) {
+ break;
+ }
+ bytesleft -= retval;
+ total += retval;
+ }
+ return retval==-1?-1:0;
+}
+
+static int g15_recv(int sock, char *buf, int len)
+{
+ int total = 0;
+ int retval = 0;
+ int bytesleft = len;
+
+ while (total < len) {
+ retval = recv(sock, buf+total, bytesleft, 0);
+ if (retval < 1) {
+ break;
+ }
+ total += retval;
+ bytesleft -= retval;
+ }
+ return total;
+}
+
+static int open_g15_daemon()
+{
+ int g15screen_fd;
+ struct sockaddr_in serv_addr;
+
+ char buffer[256];
+
+ g15screen_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (g15screen_fd < 0)
+ return -1;
+
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ inet_aton (G15SERVER_ADDR, &serv_addr.sin_addr);
+ serv_addr.sin_port = htons(G15SERVER_PORT);
+
+ if (connect(g15screen_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
+ return -1;
+
+ memset(buffer,0,256);
+ if (g15_recv(g15screen_fd, buffer, 16)<0)
+ return -1;
+
+ /* here we check that we're really talking to the g15daemon */
+ if (strcmp(buffer,"G15 daemon HELLO") != 0)
+ return -1;
+
+ /* we want to use a pixelbuffer */
+ g15_send(g15screen_fd,"GBUF",4);
+
+ return g15screen_fd;
+}
+
+
+namespace GLCD
+{
+
+cDriverG15daemon::cDriverG15daemon(cDriverConfig * config)
+: config(config),
+ offbuff(0),
+ sockfd(-1)
+{
+ oldConfig = new cDriverConfig(*config);
+}
+
+cDriverG15daemon::~cDriverG15daemon()
+{
+ delete oldConfig;
+}
+
+int cDriverG15daemon::Init()
+{
+ // default values
+ width = config->width;
+ if (width !=G15_WIDTH)
+ width = G15_WIDTH;
+ height = config->height;
+ if (height !=G15_HEIGHT)
+ height = G15_HEIGHT;
+
+ for (unsigned int i = 0; i < config->options.size(); i++) {
+ if (config->options[i].name == "") {
+ }
+ }
+
+ screensize = 6880;
+
+ if ((sockfd = open_g15_daemon())<0)
+ return -1;
+ // reserve memory to draw into
+ offbuff = new char[6880];
+
+ *oldConfig = *config;
+
+ // clear display
+ Refresh(true);
+
+ syslog(LOG_INFO, "%s: g15daemon initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverG15daemon::DeInit()
+{
+ if (offbuff);
+ delete[] offbuff;
+ if (-1 != sockfd)
+ close(sockfd);
+
+ return 0;
+}
+
+int cDriverG15daemon::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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 cDriverG15daemon::SetPixel(int x, int y)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (config->upsideDown)
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ }
+
+ offbuff[x + (width * y)] = 1;
+}
+
+void cDriverG15daemon::Clear()
+{
+ memset(offbuff, 0, screensize);
+}
+
+void cDriverG15daemon::Set8Pixels(int x, int y, unsigned char data)
+{
+ int n;
+
+ x &= 0xFFF8;
+
+ for (n = 0; n < 8; ++n)
+ {
+ if (data & (0x80 >> n)) // if bit is set
+ SetPixel(x + n, y);
+ }
+}
+
+void cDriverG15daemon::Refresh(bool refreshAll)
+{
+ g15_send(sockfd, offbuff, screensize);
+}
+
+} // end of namespace
diff --git a/glcddrivers/g15daemon.h b/glcddrivers/g15daemon.h
new file mode 100644
index 0000000..c91ef17
--- /dev/null
+++ b/glcddrivers/g15daemon.h
@@ -0,0 +1,49 @@
+/*
+ * GraphLCD driver library
+ *
+ * g15daemon.h - pseudo device for the g15daemon
+ * Output goes to the g15daemon which then displays it
+ *
+ */
+
+#ifndef _GLCDDRIVERS_G15DAEMON_H_
+#define _GLCDDRIVERS_G15DAEMON_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+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 Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/gu126x64D-K610A4.c b/glcddrivers/gu126x64D-K610A4.c
new file mode 100644
index 0000000..e927f49
--- /dev/null
+++ b/glcddrivers/gu126x64D-K610A4.c
@@ -0,0 +1,967 @@
+/*
+ * GraphLCD driver library
+ *
+ * gu126x64D-K610A4.c - 8-bit driver module for Noritake GU126x64D-K610A4 VFD
+ * displays. The VFD is operating in its 8 bit-mode
+ * connected to a single PC parallel port.
+ *
+ * based on:
+ * gu256x64-372 driver module for graphlcd
+ * (c) 2004 Andreas 'randy' Weinberger (randy AT smue.org)
+ * gu256x64-3900 driver module for graphlcd
+ * (c) 2004 Ralf Mueller (ralf AT bj-ig.de)
+ * gu140x32f driver module for graphlcd
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
+ * ks0108 driver module for graphlcd
+ * (c) 2004 Andreas 'randy' Weinberger (randy AT smue.org)
+ *
+ * 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)
+ */
+
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "config.h"
+#include "gu126x64D-K610A4.h"
+#include "port.h"
+
+namespace GLCD
+{
+//----- commands to the display -----------------------------------------------
+static const unsigned char CMD_RUN_MACRO_01 = 0x01; // run macro 1
+static const unsigned char CMD_RUN_MACRO_02 = 0x02; // run macro 2
+static const unsigned char CMD_RUN_MACRO_03 = 0x03; // run macro 3
+static const unsigned char CMD_RUN_MACRO_04 = 0x04; // run macro 4
+static const unsigned char CMD_RUN_MACRO_05 = 0x05; // run macro 5
+static const unsigned char CMD_RUN_MACRO_06 = 0x06; // run macro 6
+static const unsigned char CMD_RUN_MACRO_07 = 0x07; // run macro 7
+
+static const unsigned char CMD_CURSOR_POS = 0x10; // Set cursor position
+static const unsigned char CMD_BOX_SET = 0x11; // Set area
+static const unsigned char CMD_BOX_CLEAR = 0x12; // Clear area
+static const unsigned char CMD_BOX_INVERT = 0x13; // Invert area
+static const unsigned char CMD_RECT_SET = 0x14; // Set outline
+static const unsigned char CMD_RECT_CLEAR = 0x15; // Clear outline
+
+static const unsigned char CMD_PIXEL_SET = 0x16; // Set pixel at current pos
+static const unsigned char CMD_PIXEL_CLEAR = 0x17; // Clear pixel at current pos
+
+static const unsigned char CMD_GRAPHIC_WRITE = 0x18; // Write graphics data (args: len, data)
+static const unsigned char CMD_RESET = 0x19; // Reset display
+static const unsigned char CMD_WRITE_MODE = 0x1A; // Write mode
+static const unsigned char CMD_INTRO = 0x1B; // Intro for other commands (see CMA_*)
+static const unsigned char CMD_FONT_PROP_SML = 0x1C; // Select font: proportional mini
+static const unsigned char CMD_FONT_FIX_MED = 0x1D; // Select font: fixed spaced 5x7
+static const unsigned char CMD_FONT_FIX_BIG = 0x1E; // Select font: fixed spaced 10x14
+
+static const unsigned char CMA_MACROS_ERASE = 0x4D; // Erase Macros (usage: CMD_INTRO + this)
+static const unsigned char CMA_EPROM_LOCK = 0x4C; // Lock EEPROM (usage: CMD_INTRO + this)
+static const unsigned char CMA_EPROM_UNLOCK = 0x55; // Unlock EEPROM (usage: CMD_INTRO + this)
+
+static const unsigned char CMA_POWER_OFF = 0x46; // Power off (usage: CMD_INTRO + this)
+static const unsigned char CMA_POWER_ON = 0x50; // Power on (usage: CMD_INTRO + this)
+
+//----- signal lines ----------------------------------------------------------
+static const unsigned char OUT_EN_HI = kAutoLow ;
+static const unsigned char OUT_EN_LO = kAutoHigh;
+static const unsigned char OUT_EN_MASK = OUT_EN_HI;
+
+static const unsigned char IN_MB_HI = 0x40;
+static const unsigned char IN_MB_LO = 0x00;
+static const unsigned char IN_MB_MASK = IN_MB_HI;
+
+//----- log flags -------------------------------------------------------------
+static const unsigned int LL_REFRESH_START = 0x0001; // 1
+static const unsigned int LL_REFRESH_END = 0x0002; // 2
+static const unsigned int LL_REFRESH_MED = 0x0004; // 4
+static const unsigned int LL_VFD_CMD = 0x0008; // 8
+static const unsigned int LL_MAX_WAIT = 0x0010; // 16
+
+//----- mixed consts ----------------------------------------------------------
+static const long ADJUST_FACTOR = 100; // used to adjust timing
+
+//-----------------------------------------------------------------------------
+cDriverGU126X64D_K610A4::cDriverGU126X64D_K610A4(cDriverConfig * config)
+ : port (0)
+ , config (config)
+ , oldConfig (0)
+ , myNumRows (0)
+ , myDrawMem (0)
+ , myVFDMem (0)
+ , myUseSleepInit (false)
+ , myPortDelayNS (0)
+ , myDelay125NS (0)
+ , myRefreshCounter (0)
+ , myClaimCounter (0)
+ , 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()
+{
+ width = config->width;
+ if (width <= 0 || width > 256) // don't allow unreasonable big sizes from config
+ {
+ width = 126;
+ } // if
+
+ height = config->height;
+ if (height <= 0 || height > 256) // don't allow unreasonable big sizes from config
+ {
+ height = 64;
+ } // if
+
+ //----- parse config -----
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "Debug")
+ {
+ myLogFlags = atoi(config->options[i].value.c_str());
+ } // if
+ } // for
+
+ myNumRows = ((height + 7) / 8);
+ port = new cParallelPort();
+
+ // setup drawing memory
+ myDrawMem = new unsigned char *[width];
+ for (int x = 0; x < width; x++)
+ {
+ myDrawMem[x] = new unsigned char[myNumRows];
+ memset(myDrawMem[x], 0, myNumRows);
+ } // for
+
+ // setup vfd memory
+ myVFDMem = new unsigned char *[width];
+ for (int x = 0; x < width; x++)
+ {
+ myVFDMem[x] = new unsigned char[myNumRows];
+ memset(myVFDMem[x], 0, myNumRows);
+ } // for
+
+ if (initParallelPort() < 0)
+ {
+ return -1;
+ } // if
+
+ initDisplay();
+
+ *oldConfig = *config;
+
+ // Set Display SetBrightness
+ SetBrightness(config->brightness);
+
+ // clear display
+ Clear();
+ clearVFDMem();
+
+ syslog( LOG_INFO, "%s: initialized (width: %d height: %d)"
+ , config->name.c_str(), width, height
+ );
+
+ return 0;
+} // cDriverGU126X64D_K610A4::Init()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::DeInit()
+{
+ if (myVFDMem)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ delete[] myVFDMem[x];
+ } // for
+ delete[] myVFDMem;
+ myVFDMem = 0;
+ } // if
+
+ if (myDrawMem)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ delete[] myDrawMem[x];
+ } // for
+ delete[] myDrawMem;
+ myDrawMem = 0;
+ } // if
+
+ if (port)
+ {
+ // claim port to avoid msg when closing the port
+ port->Claim();
+ if (port->Close() != 0)
+ {
+ return -1;
+ } // if
+ delete port;
+ port = 0;
+ } // if
+
+ return 0;
+} // cDriverGU126X64D_K610A4::DeInit()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::checkSetup()
+{
+ if ( config->device != oldConfig->device
+ || config->port != oldConfig->port
+ || config->width != oldConfig->width
+ || config->height != oldConfig->height
+ )
+ {
+ DeInit();
+ Init();
+ return 0;
+ } // if
+
+ if (config->brightness != oldConfig->brightness)
+ {
+ oldConfig->brightness = config->brightness;
+ SetBrightness(config->brightness);
+ } // if
+
+ if ( config->upsideDown != oldConfig->upsideDown
+ || config->invert != oldConfig->invert
+ )
+ {
+ oldConfig->upsideDown = config->upsideDown;
+ oldConfig->invert = config->invert;
+
+ return 1;
+ } // if
+
+ return 0;
+} // cDriverGU126X64D_K610A4::checkSetup()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::initParallelPort()
+{
+ struct timeval tv1, tv2;
+
+ if (config->device == "")
+ {
+ // use DirectIO
+ if (port->Open(config->port) != 0)
+ {
+ syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!", config->name.c_str());
+ return -1;
+ } // if
+ syslog(LOG_INFO, "%s: using direct IO!", config->name.c_str());
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (port->Open(config->device.c_str()) != 0)
+ {
+ syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!", config->name.c_str());
+ return -1;
+ } // if
+ syslog(LOG_INFO, "%s: using ppdev!", config->name.c_str());
+ } // if
+
+ if (nSleepInit() != 0)
+ {
+ syslog(LOG_ERR, "%s: INFO: cannot change wait parameters Err: %s (cDriver::Init)", config->name.c_str(), strerror(errno));
+ myUseSleepInit = false;
+ }
+ else
+ {
+ myUseSleepInit = true;
+ } // if
+
+ //----- measure the time to write to the port -----
+ syslog(LOG_DEBUG, "%s: benchmark started.", config->name.c_str());
+ gettimeofday(&tv1, 0);
+
+ const int aBenchCount = 1000; // don't change this!
+ for (int x = 0; x < aBenchCount; x++)
+ {
+ port->WriteData(x % 0x100);
+ } // for
+
+ gettimeofday(&tv2, 0);
+
+ // release the port, which was implicitely claimed by open
+ port->Release();
+
+ if (myUseSleepInit) nSleepDeInit();
+
+ myPortDelayNS = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec);
+
+ myDelay125NS = std::max(125 + (ADJUST_FACTOR * config->adjustTiming) - myPortDelayNS, 0L);
+
+ syslog( LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns, delay: %ldns"
+ , config->name.c_str(), myPortDelayNS, myDelay125NS
+ );
+
+ return 0;
+} // cDriverGU126X64D_K610A4::initParallelPort()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::initDisplay()
+{
+ claimPort();
+ cmdReset();
+ releasePort();
+} // cDriverGU126X64D_K610A4::initDisplay()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::clearVFDMem()
+{
+ for (int x = 0; x < width; x++)
+ {
+ memset(myVFDMem[x], 0, myNumRows);
+ } // for
+} // cDriverGU126X64D_K610A4::clearVFDMem()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::Clear()
+{
+ for (int x = 0; x < width; x++)
+ {
+ memset(myDrawMem[x], 0, myNumRows);
+ } // for
+} // cDriverGU126X64D_K610A4::Clear()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::SetBrightness(unsigned int percent)
+{
+ claimPort();
+ cmdSetBrightness(percent);
+ releasePort();
+} // cDriverGU126X64D_K610A4::SetBrightness()
+
+//-----------------------------------------------------------------------------
+bool cDriverGU126X64D_K610A4::waitForStatus(unsigned char theMask, unsigned char theValue, int theMaxWait)
+{
+ theValue = theValue & theMask;
+
+ int status = port->ReadStatus();
+
+ if ((status & theMask) != theValue)
+ {
+ // wait some time for MB go HI/LO but not forever
+ int i = 0;
+ for(i = 0; ((status & theMask) != theValue) && i < theMaxWait; i++)
+ {
+ status = port->ReadStatus();
+ } // for
+
+ if (isLogEnabled(LL_MAX_WAIT) && i >= theMaxWait)
+ {
+ syslog( LOG_INFO, "%s: slept for %5d times while waiting for MB = %d"
+ , config->name.c_str(), i, ((theMask & theValue) == 0 ? 0 : 1)
+ );
+ } //
+ } // if
+
+ return ((status & theMask) == theValue);
+} // cDriverGU126X64D_K610A4::waitForStatus()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::writeParallel(unsigned char data)
+{
+ if (myUseSleepInit) nSleepInit();
+
+ waitForStatus(IN_MB_MASK, IN_MB_LO, 500); // wait for MB == LO
+
+ port->WriteData(data); // write data
+ nSleep(myDelay125NS); // - sleep
+
+ port->WriteControl(OUT_EN_LO & OUT_EN_MASK); // set ENABLE to LO
+ nSleep(myDelay125NS); // - sleep
+
+ port->WriteControl(OUT_EN_HI & OUT_EN_MASK); // set ENABLE to HI
+
+ waitForStatus(IN_MB_MASK, IN_MB_HI, 50); // wait for MB == HI
+
+// the other drivers don't do this neither
+// if (myUseSleepInit) nSleepDeInit();
+} // cDriverGU126X64D_K610A4::writeParallel()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::write(unsigned char data)
+{
+ int b = 0;
+
+ writeParallel(data);
+ ++b;
+
+ // if data == 0x60 -> send 0x60 twice
+ // (0x60 switches to hex-mode)
+ if (data == 0x60)
+ {
+ writeParallel(data);
+ ++b;
+ } // if
+
+ return b;
+} // cDriverGU126X64D_K610A4::write()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::setPixel(int x, int y)
+{
+ if (!myDrawMem ) return;
+ if (x >= width || x < 0) return;
+ if (y >= height || y < 0) return;
+
+ if (config->upsideDown)
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ } // if
+
+ unsigned char c = 0x80 >> (y % 8);
+
+ myDrawMem[x][y/8] = myDrawMem[x][y/8] | c;
+} // cDriverGU126X64D_K610A4::setPixel()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::Set8Pixels(int x, int y, unsigned char data)
+{
+ // x - pos isn't maybe align to 8
+ x &= 0xFFF8;
+
+ for (int n = 0; n < 8; ++n)
+ {
+ if ((data & (0x80 >> n)) != 0) // if bit is set
+ {
+ setPixel(x + n, y);
+ } // if
+ } // for
+} // cDriverGU126X64D_K610A4::Set8Pixels()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::Refresh(bool refreshAll)
+{
+ // no mem present -> return
+ if (!myVFDMem || !myDrawMem)
+ {
+ return;
+ } // if
+
+ // create log
+ if (isLogEnabled(LL_REFRESH_START))
+ {
+ syslog( LOG_INFO, "%s: > Refresh() all = %d RefreshDisplay = %d RefreshCtr = %d Delay = %ld"
+ , config->name.c_str()
+ , refreshAll
+ , config->refreshDisplay
+ , myRefreshCounter
+ , myDelay125NS
+ );
+ } // if
+
+ // setup changed -> refresh all
+ if (checkSetup() > 0)
+ {
+ syslog(LOG_DEBUG, "%s: Refresh() checkSetup() returned != 0 -> refreshAll = true", config->name.c_str());
+ refreshAll = true;
+ } // if
+
+ // refresh-counter exceeded -> refresh all
+ if (!refreshAll && config->refreshDisplay != 0)
+ {
+ myRefreshCounter = (myRefreshCounter + 1) % config->refreshDisplay;
+ refreshAll = myRefreshCounter == 0;
+
+ if (refreshAll && isLogEnabled(LL_REFRESH_START))
+ {
+ syslog(LOG_DEBUG, "%s: Refresh() refresh-count reached -> refreshAll = true", config->name.c_str());
+ } // if
+ } // if
+
+ if (isLogEnabled(LL_REFRESH_START))
+ {
+ syslog( LOG_INFO, "%s: Refresh() all = %d RefreshDisplay = %d RefreshCtr = %d Delay = %ld"
+ , config->name.c_str()
+ , refreshAll
+ , config->refreshDisplay
+ , myRefreshCounter
+ , myDelay125NS
+ );
+ } // if
+
+ // time for logs
+ struct timeval tv1, tv2;
+ gettimeofday(&tv1, 0);
+
+ claimPort();
+
+ int chunk = 128; // displays with more than 128 pixels width are written in chunks
+ // note: this driver isn't really prepared to handle displays
+ // with other dimensions than 126x64
+ int xb = 0;
+ int yb = 0;
+ long bc = 0;
+
+ for (yb = 0; yb < myNumRows; ++yb)
+ {
+ int minX = width;
+ int maxX = 0;
+
+ //----- if !refreshAll -> check modified bytes
+ if (!refreshAll)
+ {
+ for (xb = 0; xb < width; ++xb)
+ {
+ if (myVFDMem[xb][yb] != myDrawMem[xb][yb])
+ {
+ minX = std::min(minX, xb);
+ maxX = std::max(maxX, xb);
+ } // if
+ } // for
+ }
+ else
+ {
+ minX = 0;
+ maxX = width - 1;
+ } // if
+
+ // create log
+ if (isLogEnabled(LL_REFRESH_MED))
+ {
+ if (minX <= maxX)
+ {
+ syslog( LOG_INFO, "%s: Row[%d] %3d - %3d : %3d"
+ , config->name.c_str(), yb
+ , minX, maxX
+ , maxX - minX + 1
+ );
+ }
+ else
+ {
+ syslog( LOG_INFO, "%s: Row[%d] --- - --- : ---"
+ , config->name.c_str(), yb
+ );
+ } // if
+ } // if
+
+ // perform refresh
+ if (minX <= maxX)
+ {
+ bc += cmdSetCursorPos(minX, yb * 8);
+
+ for (xb = minX; xb <= maxX; ++xb)
+ {
+ if ((xb - minX) % chunk == 0)
+ {
+ bc += cmdGraphicWrite(std::min((maxX - xb + 1), chunk));
+ } // if
+
+ bc += cmdGraphicData(myDrawMem[xb][yb]);
+ myVFDMem[xb][yb] = myDrawMem[xb][yb];
+ } // for
+ } // if
+ } // for
+
+ releasePort();
+
+ // create log
+ if (isLogEnabled(LL_REFRESH_END))
+ {
+ gettimeofday(&tv2, 0);
+
+ long duration_ms = ((tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec))
+ / 1000 /* us -> ms */
+ ;
+
+ syslog( LOG_INFO, "%s: < Refresh() all = %d took %3ld ms %5ld bytes = %5ld bytes/sec = %5ld ns/byte"
+ , config->name.c_str()
+ , refreshAll
+ , duration_ms
+ , bc
+ , duration_ms == 0 ? -1 : bc * 1000 / duration_ms
+ , bc == 0 ? -1 : duration_ms * 1000000 / bc
+ );
+ } // if
+} // cDriverGU126X64D_K610A4::Refresh()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdReset()
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog(LOG_INFO, "- 1B: CMD_RESET : 0x%02X ", int(CMD_RESET));
+ } // if
+
+ b += write(CMD_RESET);
+
+ unsigned char aMode = 1 << 7 // data orientation : 0: horizontal, 1: vertical , default: 0
+ | 0 << 6 // cursor movement : 0: horizontal, 1: vertical , default: 0
+ | 0 << 5 // cursor direction : 0: forwards , 1: backwards, default: 0
+ | 0 << 4 // underscore cursor: 0: off , 1: on , default: 0
+ | 0 << 3 // underscore cursor: 0: static , 1: flash , default: 0
+ | 0 << 2 // not in documentation
+ | 0 << 0 // pen type: 0: overwrite, 1: AND, 2: OR, 3: XOR , default: 0
+ ;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog(LOG_INFO, "- 2B: CMD_WRITE_MODE : 0x%02X 0x%02X", int(CMD_RESET), int(aMode));
+ } // if
+
+ b += write(CMD_WRITE_MODE);
+ b += write(aMode);
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdReset()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdPower(bool fOn)
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog( LOG_INFO, "- 2B: CMD_POWER : 0x%02X 0x%02X"
+ , int(CMD_INTRO), int(fOn ? CMA_POWER_ON : CMA_POWER_OFF)
+ );
+ } // if
+
+ b += write(CMD_INTRO);
+ b += write(fOn ? CMA_POWER_ON : CMA_POWER_OFF);
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdPower()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdLock(bool fLock)
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog( LOG_INFO, "- 2B: CMD_LOCK : 0x%02X 0x%02X"
+ , int(CMD_INTRO), int(fLock ? CMA_EPROM_LOCK : CMA_EPROM_UNLOCK)
+ );
+ } // if
+
+ b += write(CMD_INTRO);
+ b += write(fLock ? CMA_EPROM_LOCK : CMA_EPROM_UNLOCK);
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdPower()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdSetCursorPos(unsigned char x, unsigned char y)
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog( LOG_INFO, "- 3B: CMD_CURSOR_POS : 0x%02X 0x%02X 0x%02X (x = %3d, y = %3d)"
+ , int(CMD_CURSOR_POS), int(x), int(y), int(x), int(y)
+ );
+ } // if
+
+ b += write(CMD_CURSOR_POS); // cmd
+ b += write(x ); // xpos
+ b += write(y ); // ypos
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdSetCursorPos();
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdGraphicWrite(unsigned char count)
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog( LOG_INFO, "- 2B: CMD_GRAPHIC_WRITE: 0x%02X 0x%02X (%d bytes)"
+ , int(CMD_GRAPHIC_WRITE), int(count), int(count)
+ );
+ } // if
+
+ b += write(CMD_GRAPHIC_WRITE); // cmd
+ b += write(count ); // len
+
+ myDataPendingCounter = count;
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdGraphicWrite()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdGraphicData(unsigned char data)
+{
+ int b = 0;
+
+ myDataPendingCounter--;
+ if (myDataPendingCounter < 0)
+ {
+ syslog( LOG_WARNING, "%s error: more graphic data written than announced -> ignored"
+ , config->name.c_str()
+ );
+ }
+ else
+ {
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog( LOG_INFO, "- 1B: CMD_GRAPHIC_DATA : 0x%02X (expecting another %d bytes)"
+ , int(data), myDataPendingCounter
+ );
+ } // if
+
+ b += write(data ^ (config->invert ? 0xFF : 0x00));
+ } // if
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdGraphicData()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdSetBrightness(unsigned int percent)
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ unsigned char bright = 0;
+ if (percent >= 85) bright = 0xFF;
+ else if (percent >= 71) bright = 0xFE;
+ else if (percent >= 57) bright = 0xFD;
+ else if (percent >= 43) bright = 0xFC;
+ else if (percent >= 29) bright = 0xFB;
+ else if (percent >= 15) bright = 0xFA;
+ else if (percent >= 1) bright = 0xF9;
+ else bright = 0xF8;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog( LOG_INFO, "- 2B: CMD_INTRO : 0x%02X 0x%02X = set brightness"
+ , int(CMD_INTRO), int(bright)
+ );
+ } // if
+
+ b += write(CMD_INTRO);
+ b += write(bright);
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdSetBrightness()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdSetFont(FontType theFont)
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ unsigned char aCmd = 0;
+ switch (theFont)
+ {
+ case FONT_PROP_SML: aCmd = CMD_FONT_PROP_SML; break;
+ case FONT_FIX_BIG : aCmd = CMD_FONT_FIX_BIG ; break;
+ case FONT_FIX_MED :
+ default : aCmd = CMD_FONT_FIX_MED ; break;
+ } // switch
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog(LOG_INFO, "- 1B: CMD_SET_FONT : 0x%02X", int(aCmd));
+ } // if
+
+ b += write(aCmd);
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdSetFont()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdWriteText(const char *theText)
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog(LOG_INFO, "-%2dB: WRITE_TEXT : '%s'", strlen(theText), theText);
+ } // if
+
+ for (const char *p = theText; *p != '\0'; ++p)
+ {
+ b += write(*p);
+ } // for
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdWriteText()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdDrawRect(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2)
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog( LOG_INFO, "- 5B: CMD_SET_OUTLINE : 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X (x1 = %3d, y1 = %3d, x2 = %3d, y2 = %3d)"
+ , int(CMD_CURSOR_POS)
+ , int(x1), int(y1), int(x2), int(y2)
+ , int(x1), int(y1), int(x2), int(y2)
+ );
+ } // if
+
+ b += write(CMD_RECT_SET );
+ b += write(x1 );
+ b += write(y1 );
+ b += write(x2 );
+ b += write(y2 );
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdDrawRect()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdSetMacro(unsigned char theMacroNum, unsigned char theCountBytes)
+{
+ if (theMacroNum > 7)
+ {
+ return 0;
+ } // if
+
+ ensureNotInGraphics();
+ int b = 0;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog( LOG_INFO, "- 3B: CMD_INTRO : 0x%02X 0x%02X 0x%02X (define macro %d with length %d)"
+ , int(CMD_INTRO)
+ , int(theMacroNum), int(theCountBytes)
+ , int(theMacroNum), int(theCountBytes)
+ );
+ } // if
+
+ b += write(CMD_INTRO );
+ b += write(theMacroNum );
+ b += write(theCountBytes );
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdSetMacro()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdSetPixel(bool fSet)
+{
+ int b = 0;
+
+ if (fSet)
+ {
+ ensureNotInGraphics();
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog(LOG_INFO, "- 1B: SET_PIXEL : 0x%02X", 0x16);
+ } // if
+
+ b += write(CMD_PIXEL_SET);
+ }
+ else
+ {
+ b = cmdClrPixel();
+ } // if
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdSetPixel()
+
+//-----------------------------------------------------------------------------
+int cDriverGU126X64D_K610A4::cmdClrPixel()
+{
+ ensureNotInGraphics();
+ int b = 0;
+
+ if (isLogEnabled(LL_VFD_CMD))
+ {
+ syslog(LOG_INFO, "- 1B: CLR_PIXEL : 0x%02X", 0x17);
+ } // if
+
+ b += write(CMD_PIXEL_CLEAR);
+
+ return b;
+} // cDriverGU126X64D_K610A4::cmdClrPixel()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::ensureNotInGraphics()
+{
+ if (myClaimCounter <= 0)
+ {
+ syslog(LOG_ERR, "%s: ERROR: port not claimed (%d)", config->name.c_str(), myClaimCounter);
+ } // if
+
+ if (myDataPendingCounter > 0)
+ {
+ syslog( LOG_WARNING, "%s error: expected another %d bytes graphic data, filling with 0x00"
+ , config->name.c_str(), myDataPendingCounter
+ );
+ } // if
+ while (myDataPendingCounter > 0)
+ {
+ cmdGraphicData(0);
+ } // while
+} // cDriverGU126X64D_K610A4::ensureNotInGraphics()
+
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::claimPort()
+{
+ if (myClaimCounter == 0)
+ {
+ port->Claim();
+ } // if
+
+ myClaimCounter++;
+
+ if (myClaimCounter > 1)
+ {
+ syslog( LOG_WARNING, "%s: port claimed more than once (%d)"
+ , config->name.c_str(), myClaimCounter
+ );
+ } // if
+
+} // cDriverGU126X64D_K610A4::claimPort()
+
+//-----------------------------------------------------------------------------
+void cDriverGU126X64D_K610A4::releasePort()
+{
+ if (myClaimCounter == 1)
+ {
+ port->Release();
+ } // if
+
+ myClaimCounter--;
+
+ if (myClaimCounter < 0)
+ {
+ syslog( LOG_WARNING, "%s: port released more often than claimed"
+ , config->name.c_str()
+ );
+ myClaimCounter = 0;
+ } // if
+
+} // cDriverGU126X64D_K610A4::releasePort()
+
+//-----------------------------------------------------------------------------
+bool cDriverGU126X64D_K610A4::isLogEnabled(int theLevel) const
+{
+ return (theLevel & myLogFlags) != 0;
+} // cDriverGU126X64D_K610A4::isLogEnabled()
+
+//-----------------------------------------------------------------------------
+} // end of namespace
+
diff --git a/glcddrivers/gu126x64D-K610A4.h b/glcddrivers/gu126x64D-K610A4.h
new file mode 100644
index 0000000..3d6c29c
--- /dev/null
+++ b/glcddrivers/gu126x64D-K610A4.h
@@ -0,0 +1,130 @@
+/*
+ * GraphLCD driver library
+ *
+ * gu126x64D-K610A4.h - 8-bit driver module for Noritake GU126x64D-K610A4 VFD
+ * displays. The VFD is operating in its 8 bit-mode
+ * connected to a single PC parallel port.
+ *
+ * based on:
+ * gu256x64-372 driver module for graphlcd
+ * (c) 2004 Andreas 'randy' Weinberger (randy AT smue.org)
+ * gu256x64-3900 driver module for graphlcd
+ * (c) 2004 Ralf Mueller (ralf AT bj-ig.de)
+ * gu140x32f driver module for graphlcd
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
+ * ks0108 driver module for graphlcd
+ * (c) 2004 Andreas 'randy' Weinberger (randy AT smue.org)
+ *
+ * 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)
+ */
+
+#ifndef _GLCDDRIVERS_GU126X64D_K610A4_H_
+#define _GLCDDRIVERS_GU126X64D_K610A4_H_
+
+#include "driver.h"
+
+//===============================================================================
+// namespace GLCD
+//===============================================================================
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+//===============================================================================
+// class cDriverGU126X64D_K610A4
+//===============================================================================
+class cDriverGU126X64D_K610A4 : public cDriver
+{
+public:
+ //---------------------------------------------------------------------------
+ // constructor/destructor
+ //---------------------------------------------------------------------------
+ cDriverGU126X64D_K610A4(cDriverConfig * config);
+ virtual ~cDriverGU126X64D_K610A4();
+
+ //---------------------------------------------------------------------------
+ // from cDriver
+ //---------------------------------------------------------------------------
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ virtual void Set8Pixels(int x, int y, unsigned char data);
+ virtual void Refresh(bool refreshAll = false);
+ virtual void SetBrightness(unsigned int percent);
+
+ //---------------------------------------------------------------------------
+ // display-specific enums/methods/etc.
+ //---------------------------------------------------------------------------
+ enum FontType
+ {
+ FONT_PROP_SML
+ , FONT_FIX_MED
+ , FONT_FIX_BIG
+ };
+
+ void setPixel (int x, int y);
+
+ int cmdReset ();
+ int cmdPower (bool fOn);
+ int cmdLock (bool fLock);
+ int cmdSetCursorPos (unsigned char x, unsigned char y);
+ int cmdGraphicWrite (unsigned char count);
+ int cmdGraphicData (unsigned char data);
+ int cmdSetBrightness(unsigned int percent);
+ int cmdSetFont (FontType);
+ int cmdWriteText (const char *theText);
+ int cmdDrawRect (unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2);
+ int cmdSetMacro (unsigned char theMacroNum, unsigned char theCountBytes);
+ int cmdSetPixel (bool fSet = true);
+ int cmdClrPixel ();
+
+ void claimPort();
+ void releasePort();
+
+private:
+ //---------------------------------------------------------------------------
+ // helper methods
+ //---------------------------------------------------------------------------
+ void clearVFDMem();
+ int checkSetup();
+ int initParallelPort();
+ void initDisplay();
+
+ bool waitForStatus(unsigned char theMask, unsigned char theValue, int theMaxWait);
+ void writeParallel(unsigned char data);
+ int write(unsigned char data);
+
+ void ensureNotInGraphics();
+ bool isLogEnabled(int theLevel) const;
+
+ //---------------------------------------------------------------------------
+ // attributes
+ //---------------------------------------------------------------------------
+ cParallelPort *port;
+
+ cDriverConfig *config;
+ cDriverConfig *oldConfig;
+
+ int myNumRows;
+ unsigned char **myDrawMem;
+ unsigned char **myVFDMem;
+
+ bool myUseSleepInit;
+ long myPortDelayNS;
+ long myDelay125NS;
+ int myRefreshCounter;
+ int myClaimCounter;
+ int myDataPendingCounter;
+ unsigned int myLogFlags;
+
+}; // class cDriverGU126X64D_K610A4
+
+} // namespace GLCD
+
+#endif
diff --git a/glcddrivers/gu140x32f.c b/glcddrivers/gu140x32f.c
new file mode 100644
index 0000000..212b381
--- /dev/null
+++ b/glcddrivers/gu140x32f.c
@@ -0,0 +1,443 @@
+/*
+ * GraphLCD driver library
+ *
+ * gu140x32f.c - 8-bit driver module for Noritake GU140x32-F7806 VFD
+ * displays. The VFD is operating in its 8 bit-mode
+ * connected to a single PC parallel port.
+ *
+ * based on:
+ * HD61830 device
+ * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
+ * lcdproc 0.4 driver hd44780-ext8bit
+ * (c) 1999, 1995 Benjamin Tse <blt AT Comports com>
+ *
+ * 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>
+ */
+
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "config.h"
+#include "gu140x32f.h"
+#include "port.h"
+
+
+namespace GLCD
+{
+
+// Defines for hd44780 Displays
+#define RS_DAT 0x00
+#define RS_CMD 0x01
+
+#define CLEAR 0x01
+
+#define HOMECURSOR 0x02
+
+#define ENTRYMODE 0x04
+#define E_MOVERIGHT 0x02
+#define E_MOVELEFT 0x00
+#define EDGESCROLL 0x01
+#define NOSCROLL 0x00
+
+#define ONOFFCTRL 0x08
+#define DISPON 0x04
+#define DISPOFF 0x00
+#define CURSORON 0x02
+#define CURSOROFF 0x00
+#define CURSORBLINK 0x01
+#define CURSORNOBLINK 0x00
+
+#define CURSORSHIFT 0x10
+#define SCROLLDISP 0x08
+#define MOVECURSOR 0x00
+#define MOVERIGHT 0x04
+#define MOVELEFT 0x00
+
+#define FUNCSET 0x20
+#define IF_8BIT 0x10
+#define IF_4BIT 0x00
+
+// Control output lines
+// Write to baseaddress+2
+#define nSTRB 0x01 // pin 1; negative logic
+#define nLF 0x02 // pin 14
+#define nINIT 0x04 // pin 16; the only positive logic output line
+#define nSEL 0x08 // pin 17
+#define ENIRQ 0x10 // Enable IRQ via ACK line (don't enable this withouT
+ // setting up interrupt stuff too)
+#define ENBI 0x20 // Enable bi-directional port (is nice to play with!
+ // I first didn't know a SPP could do this)
+
+#define OUTMASK 0x0B // SEL, LF and STRB are hardware inverted
+ // Use this mask only for the control output lines
+ // XOR with this mask ( ^ OUTMASK )
+
+static const std::string kWiringStandard = "Standard";
+static const std::string kWiringWindows = "Windows";
+
+// standard wiring
+// #define RS nSTRB
+// #define RW nLF
+// #define EN1 nINIT
+// #define BL nSEL
+
+// windows wiring
+// #define RS nINIT
+// #define RW nLF
+// #define EN1 nSTRB
+// #define BL nSEL
+
+
+cDriverGU140X32F::cDriverGU140X32F(cDriverConfig * config)
+: config(config),
+ m_pDrawMem(0),
+ m_pVFDMem(0)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ port = new cParallelPort();
+
+ m_nRefreshCounter = 0;
+}
+
+cDriverGU140X32F::~cDriverGU140X32F()
+{
+ delete port;
+ delete oldConfig;
+}
+
+int cDriverGU140X32F::Init()
+{
+ int x;
+ struct timeval tv1, tv2;
+
+ // default values
+ width = config->width;
+ if (width <= 0)
+ width = 140;
+ height = config->height;
+ if (height <= 0)
+ height = 32;
+ m_iSizeYb = ((height + 7) / 8); // 4
+ m_WiringRS = nSTRB;
+ m_WiringEN1 = nINIT;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "Wiring")
+ {
+ if (config->options[i].value == kWiringStandard)
+ {
+ m_WiringRS = nSTRB;
+ m_WiringEN1 = nINIT;
+ }
+ else if (config->options[i].value == kWiringWindows)
+ {
+ m_WiringRS = nINIT;
+ m_WiringEN1 = nSTRB;
+ }
+ else
+ syslog(LOG_ERR, "%s error: wiring %s not supported, using default (Standard)!\n",
+ config->name.c_str(), config->options[i].value.c_str());
+ }
+ }
+
+ // setup the memory array for the drawing array gu140x32f
+ m_pDrawMem = new unsigned char[width * m_iSizeYb];
+ Clear();
+
+ // setup the memory array for the display array gu140x32f
+ m_pVFDMem = new unsigned char[width * m_iSizeYb];
+ ClearVFDMem();
+
+ if (config->device == "")
+ {
+ // use DirectIO
+ if (port->Open(config->port) != 0)
+ return -1;
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (port->Open(config->device.c_str()) != 0)
+ return -1;
+ }
+
+ if (nSleepInit() != 0)
+ {
+ syslog(LOG_ERR, "%s: INFO: cannot change wait parameters Err: %s (cDriver::Init)\n", config->name.c_str(), strerror(errno));
+ m_bSleepIsInit = false;
+ }
+ else
+ {
+ m_bSleepIsInit = true;
+ }
+
+ syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
+ gettimeofday(&tv1, 0);
+ for (x = 0; x < 10000; x++)
+ {
+ port->WriteData(x % 0x100);
+ }
+ gettimeofday(&tv2, 0);
+ nSleepDeInit();
+ m_nTimingAdjustCmd = ((tv2.tv_sec - tv1.tv_sec) * 10000 + (tv2.tv_usec - tv1.tv_usec)) / 1000;
+ syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), m_nTimingAdjustCmd);
+
+
+ // setup the lcd in 8 bit mode
+ Write(RS_CMD, FUNCSET | IF_8BIT, 4100);
+ Write(RS_CMD, FUNCSET | IF_8BIT, 100);
+ Write(RS_CMD, FUNCSET | IF_8BIT, 40);
+
+ Write(RS_CMD, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK, 40);
+ Write(RS_CMD, CLEAR, 1600);
+ Write(RS_CMD, HOMECURSOR, 1600);
+
+ port->Release();
+
+ *oldConfig = *config;
+
+ // Set Display SetBrightness
+ SetBrightness(config->brightness);
+ // clear display
+ ClearVFDMem();
+ Clear();
+
+ syslog(LOG_INFO, "%s: gu140x32f initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverGU140X32F::DeInit()
+{
+ if (m_pVFDMem)
+ delete[] m_pVFDMem;
+ if (m_pDrawMem)
+ delete[] m_pDrawMem;
+
+ if (port->Close() != 0)
+ return -1;
+ return 0;
+}
+
+int cDriverGU140X32F::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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 cDriverGU140X32F::ClearVFDMem()
+{
+ for (int n = 0; m_pVFDMem && n < (width * m_iSizeYb); n++)
+ m_pVFDMem[n] = 0x00;
+}
+
+void cDriverGU140X32F::Clear()
+{
+ for (int n = 0; m_pDrawMem && n < (width * m_iSizeYb); n++)
+ m_pDrawMem[n] = 0x00;
+}
+
+void cDriverGU140X32F::SetBrightness(unsigned int percent)
+{
+ port->Claim();
+
+ unsigned char level;
+ if (percent > 100)
+ percent = 100;
+ level = percent / 25;
+ if (level < 1)
+ level = 1;
+ level = (4 - level) & 0x03;
+ // Set Brightness
+ // 00 - 100%
+ // 01 - 75%
+ // 02 - 50%
+ // 03 - 25%
+ Write(RS_CMD, FUNCSET | IF_8BIT, 40);
+ Write(RS_DAT, level, 40);
+
+ port->Release();
+}
+
+void cDriverGU140X32F::Write(unsigned char nFlags, unsigned char bData, unsigned int nMicroSecBusyTime)
+{
+ if (m_bSleepIsInit)
+ nSleepInit();
+
+ unsigned char enableLines = 0, portControl;
+
+ // Only one controller is supported
+ enableLines = m_WiringEN1;
+
+ if (nFlags == RS_CMD)
+ portControl = 0;
+ else // if (nFlags == RS_DAT)
+ portControl = m_WiringRS;
+
+ // portControl |= m_WiringBL;
+
+ port->WriteControl(portControl ^ OUTMASK); //Reset controlbits
+ port->WriteData(bData); //Set data
+ port->WriteControl((enableLines | portControl) ^ OUTMASK); //Set controlbits
+
+ // How long hold the data active
+ if (m_bSleepIsInit && (25 + (100 * config->adjustTiming) - m_nTimingAdjustCmd > 0))
+ {
+ // Wait 50ns
+ nSleep(std::max(25L, 50 + (100 * config->adjustTiming) - m_nTimingAdjustCmd));
+ }
+
+ port->WriteControl(portControl ^ OUTMASK); //Reset controlbits
+
+ nSleep((nMicroSecBusyTime * 1000) + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
+
+ if (m_bSleepIsInit)
+ nSleepDeInit();
+}
+
+void cDriverGU140X32F::SetPixel(int x, int y)
+{
+ unsigned char c;
+ int n;
+
+ if (!m_pDrawMem)
+ 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) * width);
+ c = 0x80 >> (y % 8);
+
+ m_pDrawMem[n] |= c;
+}
+
+void cDriverGU140X32F::Set8Pixels(int x, int y, unsigned char data)
+{
+ int n;
+
+ // x - pos is'nt mayby align to 8
+ x &= 0xFFF8;
+
+ for (n = 0; n < 8; ++n)
+ {
+ if (data & (0x80 >> n)) // if bit is set
+ SetPixel(x + n, y);
+ }
+}
+
+void cDriverGU140X32F::Refresh(bool refreshAll)
+{
+ int n, x, yb;
+
+ if (!m_pVFDMem || !m_pDrawMem)
+ return;
+
+ bool doRefresh = false;
+ int minX = width;
+ int maxX = 0;
+ int minYb = m_iSizeYb;
+ int maxYb = 0;
+
+ if (CheckSetup() > 0)
+ refreshAll = true;
+
+ for (yb = 0; yb < m_iSizeYb; ++yb)
+ for (x = 0; x < width; ++x)
+ {
+ n = x + (yb * width);
+ if (m_pVFDMem[n] != m_pDrawMem[n])
+ {
+ m_pVFDMem[n] = m_pDrawMem[n];
+ minX = std::min(minX, x);
+ maxX = std::max(maxX, x);
+ minYb = std::min(minYb, yb);
+ maxYb = std::max(maxYb, yb + 1);
+ doRefresh = true;
+ }
+ }
+
+ m_nRefreshCounter = (m_nRefreshCounter + 1) % config->refreshDisplay;
+
+ if (!refreshAll && !m_nRefreshCounter)
+ refreshAll = true;
+
+ if (refreshAll || doRefresh)
+ {
+ if (refreshAll)
+ {
+ minX = 0;
+ maxX = width;
+ minYb = 0;
+ maxYb = m_iSizeYb;
+ // and reset RefreshCounter
+ m_nRefreshCounter = 0;
+ }
+
+ minX = std::max(minX, 0);
+ maxX = std::min(maxX, width - 1);
+ minYb = std::max(minYb, 0);
+ maxYb = std::min(maxYb, m_iSizeYb);
+
+ port->Claim();
+ // send lcd data to display, controller
+ Write(RS_CMD, 0xF1, 40);
+ Write(RS_DAT, minX, 40);
+ Write(RS_DAT, (minYb * 8) & 0xFFF8, 40);
+ Write(RS_DAT, maxX, 40);
+ Write(RS_DAT, (maxYb * 8), 40);
+
+ Write(RS_DAT, 'v', 500);
+
+ for (yb = minYb; yb <= maxYb; ++yb)
+ for (x = minX; x <= maxX; ++x)
+ {
+ n = x + (yb * width);
+
+ if (n >= (width * m_iSizeYb))
+ break;
+ Write(RS_DAT, (m_pVFDMem[n]) ^ (config->invert ? 0xff : 0x00), 40);
+ }
+ port->Release();
+ }
+}
+
+} // end of namespace
diff --git a/glcddrivers/gu140x32f.h b/glcddrivers/gu140x32f.h
new file mode 100644
index 0000000..c0b87f2
--- /dev/null
+++ b/glcddrivers/gu140x32f.h
@@ -0,0 +1,73 @@
+/*
+ * GraphLCD driver library
+ *
+ * gu140x32f.h - 8-bit driver module for Noritake GU140x32-F7806 VFD
+ * displays. The VFD is operating in its 8 bit-mode
+ * connected to a single PC parallel port.
+ *
+ * based on:
+ * HD61830 device
+ * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
+ * lcdproc 0.4 driver hd44780-ext8bit
+ * (c) 1999, 1995 Benjamin Tse <blt AT Comports com>
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_GU140X32F_H_
+#define _GLCDDRIVERS_GU140X32F_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+
+class cDriverGU140X32F : public cDriver
+{
+ unsigned char m_WiringRS;
+ unsigned char m_WiringEN1;
+
+ cParallelPort * port;
+
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+
+ int m_iSizeYb;
+ int m_nRefreshCounter;
+ unsigned char *m_pDrawMem; // the draw "memory"
+ unsigned char *m_pVFDMem; // the double buffed display "memory"
+ long m_nTimingAdjustCmd;
+ bool m_bSleepIsInit;
+
+ int CheckSetup();
+
+protected:
+ void ClearVFDMem();
+ void SetPixel(int x, int y);
+ void Write(unsigned char nFlags, unsigned char bData, unsigned int nMicroSecBusyTime);
+
+public:
+ cDriverGU140X32F(cDriverConfig * config);
+ virtual ~cDriverGU140X32F();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ 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/gu256x64-372.c b/glcddrivers/gu256x64-372.c
new file mode 100644
index 0000000..6eb2a4c
--- /dev/null
+++ b/glcddrivers/gu256x64-372.c
@@ -0,0 +1,408 @@
+/*
+ * GraphLCD driver library
+ *
+ * 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.
+ *
+ * based on:
+ * gu256x32f driver module for graphlcd
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
+ * HD61830 device
+ * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
+ * lcdproc 0.4 driver hd44780-ext8bit
+ * (c) 1999, 1995 Benjamin Tse <blt AT comports.com>
+ *
+ * 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)
+ */
+
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "config.h"
+#include "gu256x64-372.h"
+#include "port.h"
+
+
+namespace GLCD
+{
+
+#define SCREENSOFF 0x00 // both screens are off
+#define SCREEN1ON 0x01 // only screen #1 is on (graphic screen)
+#define SCREEN2ON 0x02 // only screen #2 is on (graphic/character screen)
+#define SCREENSON 0x03 // both screens are on
+
+#define CURS_AUTOINC 0x04 // cursor increments automatically
+#define CURS_HOLD 0x05 // cursor holds
+
+#define SCREEN2CHAR 0x06 // screen #2 sets to "character" display
+#define SCREEN2GRAPH 0x07 // screen #2 sets to "graphic" display
+
+#define DATA_WRITE 0x08 // data write mode
+#define DATA_READ 0x09 // data read mode
+
+#define DISP_LOSTA1 0x0A // lower addr. of display start of screen #1
+#define DISP_HISTA1 0x0B // upper addr. of display start of screen #1
+#define DISP_LOSTA2 0x0C // lower addr. of display start of screen #2
+#define DISP_HISTA2 0x0D // upper addr. of display start of screen #2
+#define CURS_LOADDR 0x0E // lower addr. of cursor of screen #1 & #2
+#define CURS_HIADDR 0x0F // upper addr. of cursor start of screen #1 & #2
+
+#define DISP_OR 0x10 // or display of screen #1 & #2
+#define DISP_EXOR 0x11 // ex-or display of screen #1 & #2
+#define DISP_AND 0x12 // and display of screen #1 & #2
+
+#define BRIGHT_1 0x18 // luminance level 1 100.0%
+#define BRIGHT_2 0x19 // luminance level 2 87.5%
+#define BRIGHT_3 0x1A // luminance level 3 75.0%
+#define BRIGHT_4 0x1B // luminance level 4 62.5%
+
+#define WRHI 0x04 // INIT
+#define WRLO 0x00
+#define CDHI 0x00 // nSEL
+#define CDLO 0x08
+
+
+cDriverGU256X64_372::cDriverGU256X64_372(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ port = new cParallelPort();
+
+ m_nRefreshCounter = 0;
+}
+
+cDriverGU256X64_372::~cDriverGU256X64_372()
+{
+ delete oldConfig;
+ delete port;
+}
+
+int cDriverGU256X64_372::Init()
+{
+ int x;
+ struct timeval tv1, tv2;
+
+ width = config->width;
+ if (width <= 0)
+ width = 256;
+ height = config->height;
+ if (height <= 0)
+ height = 64;
+ m_iSizeYb = (height + 7) / 8;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "")
+ {
+ }
+ }
+
+ // setup linear lcd array
+ m_pDrawMem = new unsigned char *[width];
+ if (m_pDrawMem)
+ {
+ for (x = 0; x < width; x++)
+ {
+ m_pDrawMem[x] = new unsigned char[m_iSizeYb];
+ memset(m_pDrawMem[x], 0, m_iSizeYb);
+ }
+ }
+ Clear();
+
+ // setup the lcd array for the "vertical" mem
+ m_pVFDMem = new unsigned char *[width];
+ if (m_pVFDMem)
+ {
+ for (x = 0; x < width; x++)
+ {
+ m_pVFDMem[x] = new unsigned char[m_iSizeYb];
+ memset(m_pVFDMem[x], 0, m_iSizeYb);
+ }
+ }
+ ClearVFDMem();
+
+ if (config->device == "")
+ {
+ // use DirectIO
+ if (port->Open(config->port) != 0)
+ return -1;
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (port->Open(config->device.c_str()) != 0)
+ return -1;
+ }
+
+ if (nSleepInit() != 0)
+ {
+ syslog(LOG_ERR, "%s: INFO: cannot change wait parameters Err: %s (cDriver::Init)\n", config->name.c_str(), strerror(errno));
+ m_bSleepIsInit = false;
+ }
+ else
+ {
+ m_bSleepIsInit = true;
+ }
+
+ syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
+ gettimeofday(&tv1, 0);
+ for (x = 0; x < 10000; x++)
+ {
+ port->WriteData(x % 0x100);
+ }
+ gettimeofday(&tv2, 0);
+ nSleepDeInit();
+ m_nTimingAdjustCmd = ((tv2.tv_sec - tv1.tv_sec) * 10000 + (tv2.tv_usec - tv1.tv_usec)) / 1000;
+ syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), m_nTimingAdjustCmd);
+
+ GU256X64Cmd(SCREEN1ON);
+ GU256X64Cmd(CURS_AUTOINC);
+ GU256X64Cmd(SCREEN2CHAR);
+
+ GU256X64Cmd(DISP_LOSTA1); GU256X64Data(0x00);
+ GU256X64Cmd(DISP_HISTA1); GU256X64Data(0x00);
+ GU256X64Cmd(DISP_LOSTA2); GU256X64Data(0x00);
+ GU256X64Cmd(DISP_HISTA2); GU256X64Data(0x10);
+ GU256X64Cmd(CURS_LOADDR); GU256X64Data(0x00);
+ GU256X64Cmd(CURS_HIADDR); GU256X64Data(0x00);
+
+ GU256X64Cmd(DISP_OR);
+
+ port->Release();
+
+ *oldConfig = *config;
+
+ // Set Display SetBrightness
+ SetBrightness(config->brightness);
+ // clear display
+ Clear();
+ ClearVFDMem();
+
+ syslog(LOG_INFO, "%s: gu256x64-372 initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverGU256X64_372::DeInit()
+{
+ int x;
+
+ if (m_pVFDMem)
+ for (x = 0; x < width; x++)
+ {
+ delete[] m_pVFDMem[x];
+ }
+ delete[] m_pVFDMem;
+
+ if (m_pDrawMem)
+ for (x = 0; x < width; x++)
+ {
+ delete[] m_pDrawMem[x];
+ }
+ delete[] m_pDrawMem;
+
+ if (port->Close() != 0)
+ return -1;
+ return 0;
+}
+
+int cDriverGU256X64_372::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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 cDriverGU256X64_372::ClearVFDMem()
+{
+ for (int x = 0; x < width; x++)
+ memset(m_pVFDMem[x], 0, m_iSizeYb);
+}
+
+void cDriverGU256X64_372::Clear()
+{
+ for (int x = 0; x < width; x++)
+ memset(m_pDrawMem[x], 0, m_iSizeYb);
+}
+
+void cDriverGU256X64_372::SetBrightness(unsigned int percent)
+{
+ port->Claim();
+
+ if (percent > 88) {
+ GU256X64Cmd(BRIGHT_1);
+ } else if (percent > 75) {
+ GU256X64Cmd(BRIGHT_2);
+ } else if (percent > 66) {
+ GU256X64Cmd(BRIGHT_3);
+ } else if (percent > 0 ) {
+ GU256X64Cmd(BRIGHT_4);
+ } else {
+ GU256X64Cmd(SCREENSOFF);
+ }
+ port->Release();
+}
+
+void cDriverGU256X64_372::GU256X64Cmd(unsigned char data)
+{
+ if (m_bSleepIsInit)
+ nSleepInit();
+
+ port->WriteControl(CDHI | WRHI);
+ port->WriteData(data);
+ nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
+ port->WriteControl(CDHI | WRLO);
+ nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
+ port->WriteControl(CDHI | WRHI);
+ nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
+}
+
+void cDriverGU256X64_372::GU256X64Data(unsigned char data)
+{
+ if (m_bSleepIsInit)
+ nSleepInit();
+
+ port->WriteControl(CDLO | WRHI);
+ port->WriteData(data);
+ nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
+ port->WriteControl(CDLO | WRLO);
+ nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
+ port->WriteControl(CDLO | WRHI);
+ nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
+}
+
+void cDriverGU256X64_372::SetPixel(int x, int y)
+{
+ unsigned char c;
+
+ if (!m_pDrawMem)
+ return;
+
+ if (x >= width || x < 0)
+ return;
+ if (y >= height || y < 0)
+ return;
+
+ if (config->upsideDown)
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ }
+
+ c = 0x80 >> (y % 8);
+
+ m_pDrawMem[x][y/8] = m_pDrawMem[x][y/8] | c;
+}
+
+void cDriverGU256X64_372::Set8Pixels(int x, int y, unsigned char data)
+{
+ int n;
+
+ // x - pos is'nt mayby align to 8
+ x &= 0xFFF8;
+
+ for (n = 0; n < 8; ++n)
+ {
+ if (data & (0x80 >> n)) // if bit is set
+ SetPixel(x + n, y);
+ }
+}
+
+void cDriverGU256X64_372::Refresh(bool refreshAll)
+{
+ int xb, yb;
+
+ if (!m_pVFDMem || !m_pDrawMem)
+ return;
+
+ bool doRefresh = false;
+ int minX = width;
+ int maxX = 0;
+ int minYb = m_iSizeYb;
+ int maxYb = 0;
+
+ if (CheckSetup() > 0)
+ refreshAll = true;
+
+ for (xb = 0; xb < width; ++xb)
+ {
+ for (yb = 0; yb < m_iSizeYb; ++yb)
+ {
+ if (m_pVFDMem[xb][yb] != m_pDrawMem[xb][yb])
+ {
+ m_pVFDMem[xb][yb] = m_pDrawMem[xb][yb];
+ minX = std::min(minX, xb);
+ maxX = std::max(maxX, xb);
+ minYb = std::min(minYb, yb);
+ maxYb = std::max(maxYb, yb + 1);
+ doRefresh = true;
+ }
+ }
+ }
+
+ m_nRefreshCounter = (m_nRefreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !m_nRefreshCounter)
+ refreshAll = true;
+
+ if (refreshAll || doRefresh)
+ {
+ if (refreshAll) {
+ minX = 0;
+ maxX = width;
+ minYb = 0;
+ maxYb = m_iSizeYb;
+ // and reset RefreshCounter
+ m_nRefreshCounter = 0;
+ }
+
+ minX = std::max(minX, 0);
+ maxX = std::min(maxX, width - 1);
+ minYb = std::max(minYb, 0);
+ maxYb = std::min(maxYb, m_iSizeYb);
+
+ port->Claim();
+
+ GU256X64Cmd(CURS_LOADDR); GU256X64Data(0x00);
+ GU256X64Cmd(CURS_HIADDR); GU256X64Data(0x00);
+ GU256X64Cmd(DATA_WRITE);
+
+ for (xb = 0; xb < width; xb++)
+ {
+ for (yb = 0; yb < m_iSizeYb; yb++)
+ {
+ GU256X64Data((m_pVFDMem[xb][yb]) ^ (config->invert ? 0xff : 0x00));
+ }
+ }
+ port->Release();
+ }
+}
+
+} // end of namespace
diff --git a/glcddrivers/gu256x64-372.h b/glcddrivers/gu256x64-372.h
new file mode 100644
index 0000000..f685f7d
--- /dev/null
+++ b/glcddrivers/gu256x64-372.h
@@ -0,0 +1,73 @@
+/*
+ * GraphLCD driver library
+ *
+ * gu256x64-372.h - 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.
+ *
+ * based on:
+ * gu256x32f driver module for graphlcd
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
+ * HD61830 device
+ * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
+ * lcdproc 0.4 driver hd44780-ext8bit
+ * (c) 1999, 1995 Benjamin Tse <blt AT comports.com>
+ *
+ * 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)
+ */
+
+#ifndef _GLCDDRIVERS_GU256X64_372_H_
+#define _GLCDDRIVERS_GU256X64_372_H_
+
+#include "driver.h"
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+class cDriverGU256X64_372 : public cDriver
+{
+ cParallelPort * port;
+
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+
+ int m_iSizeYb;
+ int m_nRefreshCounter;
+
+ unsigned char ** m_pDrawMem; // the draw "memory"
+ unsigned char ** m_pVFDMem; // the double buffed display "memory"
+
+ long m_nTimingAdjustCmd;
+ bool m_bSleepIsInit;
+
+ int CheckSetup();
+
+protected:
+ void ClearVFDMem();
+ void SetPixel(int x, int y);
+ void GU256X64Cmd(unsigned char data);
+ void GU256X64Data(unsigned char data);
+
+public:
+ cDriverGU256X64_372(cDriverConfig * config);
+ virtual ~cDriverGU256X64_372();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ 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/gu256x64-3900.c b/glcddrivers/gu256x64-3900.c
new file mode 100644
index 0000000..8b4560b
--- /dev/null
+++ b/glcddrivers/gu256x64-3900.c
@@ -0,0 +1,651 @@
+/*
+ * GraphLCD driver library
+ *
+ * gu256x64-3900.c - 8-bit driver module for Noritake GU256X64x-3900
+ * VFD displays. The VFD is either operating in
+ * 8-bit mode connected to a single PC parallel
+ * port or in serial mode connected to a single PC
+ * serial port.
+ *
+ * based on:
+ * gu256x64-372 driver module for graphlcd
+ * (c) 2004 Andreas 'randy' Weinberger <randy AT smue.org>
+ * gu256x32f driver module for graphlcd
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
+ * HD61830 device
+ * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
+ * lcdproc 0.4 driver hd44780-ext8bit
+ * (c) 1999, 1995 Benjamin Tse <blt AT comports.com>
+ *
+ * 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)
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "config.h"
+#include "gu256x64-3900.h"
+#include "port.h"
+
+
+namespace GLCD
+{
+
+static const unsigned char dSETSTART0 = 0x02; // Set display start address (CMD prefix)
+static const unsigned char dSETSTART1 = 0x44; // Set display start address (CMD)
+static const unsigned char dSETSTART2 = 0x00; // Set display start address
+static const unsigned char dSETSTART3 = 0x53; // Set display start address
+
+static const unsigned char nINITDISPLAY0 = 0x1b; // Initialize display (CMD prefix)
+static const unsigned char nINITDISPLAY1 = 0x40; // Initialize display (CMD)
+
+static const unsigned char nPOWER0 = 0x1f; // Power on/off
+static const unsigned char nPOWER1 = 0x28; // Power on/off
+static const unsigned char nPOWER2 = 0x61; // Power on/off
+static const unsigned char nPOWER3 = 0x40; // Power on/off
+
+static const unsigned char nSETBRIGHT0 = 0x1f; // Set brightness (CMD prefix)
+static const unsigned char nSETBRIGHT1 = 0x58; // Set brightness (CMD)
+
+static const unsigned char dSETBRIGHT0 = 0x02; // Set brightness (CMD prefix)
+static const unsigned char dSETBRIGHT1 = 0x44; // Set brightness (CMD)
+static const unsigned char dSETBRIGHT2 = 0x00; // Set brightness
+static const unsigned char dSETBRIGHT3 = 0x58; // Set brightness
+
+static const unsigned char BRIGHT_000 = 0x10; // Brightness 0%
+static const unsigned char BRIGHT_012 = 0x11; // Brightness 12.5%
+static const unsigned char BRIGHT_025 = 0x12; // Brightness 25%
+static const unsigned char BRIGHT_037 = 0x13; // Brightness 37.5%
+static const unsigned char BRIGHT_050 = 0x14; // Brightness 50%
+static const unsigned char BRIGHT_062 = 0x15; // Brightness 62.5%
+static const unsigned char BRIGHT_075 = 0x16; // Brightness 75%
+static const unsigned char BRIGHT_087 = 0x17; // Brightness 87.5%
+static const unsigned char BRIGHT_100 = 0x18; // Brightness 100%
+
+static const unsigned char nSETCURSOR0 = 0x1f; // Set cursor (CMD prefix)
+static const unsigned char nSETCURSOR1 = 0x24; // Set cursor (CMD)
+
+static const unsigned char nDISPLAYCURSOR0 = 0x1f; // display cursor
+static const unsigned char nDISPLAYCURSOR1 = 0x43; // display cursor
+
+static const unsigned char nBLITIMAGE0 = 0x1f; // Display image
+static const unsigned char nBLITIMAGE1 = 0x28; // Display image
+static const unsigned char nBLITIMAGE2 = 0x66; // Display image
+static const unsigned char nBLITIMAGE3 = 0x11; // Display image
+
+static const unsigned char dBLITIMAGE0 = 0x02; // Image write
+static const unsigned char dBLITIMAGE1 = 0x44; // Image write
+static const unsigned char dBLITIMAGE2 = 0x00; // Image write
+static const unsigned char dBLITIMAGE3 = 0x46; // Image write
+
+
+static const unsigned char WRHI = 0x0f; // any control pin to high
+static const unsigned char WRLO = 0x00;
+static const unsigned char RDYHI = 0x40; // RDY
+static const unsigned char RDYHIALT = 0x80; // RDY satyr wiring
+static const unsigned char RDYLO = 0x00;
+
+static const std::string kWiringStandard = "Standard";
+static const std::string kWiringSatyr = "Satyr";
+
+static const int kInterfaceParallel = 0; // parallel mode
+static const int kInterfaceSerial = 1; // serial mode
+
+
+cDriverGU256X64_3900::cDriverGU256X64_3900(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ portFd = -1;
+ m_nRefreshCounter = 0;
+}
+
+cDriverGU256X64_3900::~cDriverGU256X64_3900()
+{
+ delete oldConfig;
+}
+
+int cDriverGU256X64_3900::Init()
+{
+ int x;
+
+ width = config->width;
+ if (width <= 0)
+ width = 256;
+ height = config->height;
+ if (height <= 0)
+ height = 64;
+ m_iSizeYb = ((height + 7) / 8);
+
+ // default values
+ readyMask = RDYHI;
+ readyHi = RDYHI;
+ interface = kInterfaceParallel;
+ useDMA = true;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "Wiring")
+ {
+ if (config->options[i].value == kWiringStandard)
+ {
+ readyMask = RDYHI;
+ readyHi = RDYHI;
+ }
+ else if (config->options[i].value == kWiringSatyr)
+ {
+ readyMask = RDYHIALT;
+ readyHi = RDYLO;
+ }
+ else
+ syslog(LOG_ERR, "%s error: wiring %s not supported, using default (Standard)!\n",
+ config->name.c_str(), config->options[i].value.c_str());
+ }
+ if (config->options[i].name == "Interface")
+ {
+ if (config->options[i].value == "Parallel")
+ interface = kInterfaceParallel;
+ else if (config->options[i].value == "Serial")
+ interface = kInterfaceSerial;
+ else
+ syslog(LOG_ERR, "%s error: interface %s not supported, using default (Parallel)!\n",
+ config->name.c_str(), config->options[i].value.c_str());
+ }
+ else if (config->options[i].name == "DMA")
+ {
+ if (config->options[i].value == "yes")
+ useDMA = true;
+ else if (config->options[i].value == "no")
+ useDMA = false;
+ else
+ syslog(LOG_ERR, "%s error: unknown DMA setting %s, using default (%s)!\n",
+ config->name.c_str(), config->options[i].value.c_str(), useDMA ? "yes" : "no");
+ }
+ }
+
+ if (interface == kInterfaceParallel)
+ port = new cParallelPort();
+ else
+ port = NULL;
+
+ // setup linear lcd array
+ m_pDrawMem = new unsigned char *[width];
+ if (m_pDrawMem)
+ {
+ for (x = 0; x < width; x++)
+ {
+ m_pDrawMem[x] = new unsigned char[m_iSizeYb];
+ memset(m_pDrawMem[x], 0, m_iSizeYb);
+ }
+ }
+ Clear();
+
+ // setup the lcd array for the "vertical" mem
+ m_pVFDMem = new unsigned char *[width];
+ if (m_pVFDMem)
+ {
+ for (x = 0; x < width; x++)
+ {
+ m_pVFDMem[x] = new unsigned char[m_iSizeYb];
+ memset(m_pVFDMem[x], 0, m_iSizeYb);
+ }
+ }
+ ClearVFDMem();
+
+ if (interface == kInterfaceSerial)
+ {
+ if (InitSerialPort() < 0)
+ return -1;
+ }
+ else
+ {
+ if (InitParallelPort() < 0)
+ return -1;
+ }
+
+ if (useDMA)
+ InitDMADisplay();
+ else
+ InitNormalDisplay();
+
+ if (interface == kInterfaceParallel)
+ {
+ // claim is in InitParallelPort
+ port->Release();
+ }
+
+ *oldConfig = *config;
+
+ // Set Display SetBrightness
+ SetBrightness(config->brightness);
+ // clear display
+ Clear();
+ ClearVFDMem();
+
+ syslog(LOG_INFO, "%s: gu256x64-3900 initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverGU256X64_3900::DeInit()
+{
+ int x;
+
+ if (m_pVFDMem)
+ {
+ for (x = 0; x < width; x++)
+ {
+ delete[] m_pVFDMem[x];
+ }
+ delete[] m_pVFDMem;
+ }
+ if (m_pDrawMem)
+ {
+ for (x = 0; x < width; x++)
+ {
+ delete[] m_pDrawMem[x];
+ }
+ delete[] m_pDrawMem;
+ }
+
+ if (interface == kInterfaceSerial)
+ {
+ if (portFd >= 0)
+ {
+ close(portFd);
+ portFd =- 1;
+ }
+ }
+ if (port)
+ {
+ if (port->Close() != 0)
+ {
+ return -1;
+ }
+ delete port;
+ port = NULL;
+ }
+ return 0;
+}
+
+int cDriverGU256X64_3900::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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;
+}
+
+int cDriverGU256X64_3900::InitSerialPort()
+{
+ if (config->device == "")
+ {
+ syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!\n", config->name.c_str());
+ return -1;
+ }
+
+ portFd = open(config->device.c_str(), O_RDWR | O_NOCTTY);
+ if (portFd >= 0)
+ {
+ struct termios options;
+ tcgetattr(portFd, &options);
+ cfsetispeed(&options, B38400);
+ cfsetospeed(&options, B38400);
+ options.c_cflag &= ~CSIZE;
+ options.c_cflag &= ~PARENB;
+ options.c_cflag &= ~CSTOPB;
+ options.c_cflag |= CS8;
+ tcsetattr(portFd, TCSANOW, &options);
+ }
+ else
+ {
+ syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!\n", config->name.c_str());
+ return -1;
+ }
+ return 0;
+}
+
+int cDriverGU256X64_3900::InitParallelPort()
+{
+ struct timeval tv1, tv2;
+
+ if (config->device == "")
+ {
+ // use DirectIO
+ if (port->Open(config->port) != 0)
+ {
+ syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!\n", config->name.c_str());
+ return -1;
+ }
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (port->Open(config->device.c_str()) != 0)
+ {
+ syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!\n", config->name.c_str());
+ return -1;
+ }
+ }
+
+ if (nSleepInit() != 0)
+ {
+ syslog(LOG_ERR, "%s: INFO: cannot change wait parameters Err: %s (cDriver::Init)\n", config->name.c_str(), strerror(errno));
+ m_bSleepIsInit = false;
+ }
+ else
+ {
+ m_bSleepIsInit = true;
+ }
+
+ port->Claim();
+
+ syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
+ gettimeofday(&tv1, 0);
+ for (int x = 0; x < 1000; x++)
+ {
+ port->WriteData(x % 0x100);
+ }
+ gettimeofday(&tv2, 0);
+ nSleepDeInit();
+ m_nTimingAdjustCmd = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec);
+ syslog(LOG_INFO, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), m_nTimingAdjustCmd);
+
+ return 0;
+}
+
+void cDriverGU256X64_3900::InitNormalDisplay()
+{
+ Write(nPOWER0);
+ Write(nPOWER1);
+ Write(nPOWER2);
+ Write(nPOWER3);
+ Write(1); // power on
+
+ Write(nINITDISPLAY0);
+ Write(nINITDISPLAY1);
+
+ Write(nDISPLAYCURSOR0);
+ Write(nDISPLAYCURSOR1);
+ Write(0); // off
+
+ Write(nSETCURSOR0);
+ Write(nSETCURSOR1);
+ Write(0); // low byte x
+ Write(0); // high byte x
+ Write(0); // low byte y
+ Write(0); // high byte y
+}
+
+void cDriverGU256X64_3900::InitDMADisplay()
+{
+ Write(dSETSTART0);
+ Write(dSETSTART1);
+ Write(dSETSTART2);
+ Write(dSETSTART3);
+ Write(0);
+ Write(0);
+}
+
+void cDriverGU256X64_3900::ClearVFDMem()
+{
+ for (int x = 0; x < width; x++)
+ memset(m_pVFDMem[x], 0, m_iSizeYb);
+}
+
+void cDriverGU256X64_3900::Clear()
+{
+ for (int x = 0; x < width; x++)
+ memset(m_pDrawMem[x], 0, m_iSizeYb);
+}
+
+void cDriverGU256X64_3900::SetBrightness(unsigned int percent)
+{
+ if (interface == kInterfaceParallel)
+ port->Claim();
+
+ if (interface == kInterfaceParallel && useDMA)
+ {
+ Write(dSETBRIGHT0);
+ Write(dSETBRIGHT1);
+ Write(dSETBRIGHT2);
+ Write(dSETBRIGHT3);
+ }
+ else
+ {
+ Write(nSETBRIGHT0);
+ Write(nSETBRIGHT1);
+ }
+ if (percent > 87) {
+ Write(BRIGHT_100);
+ } else if (percent > 75) {
+ Write(BRIGHT_087);
+ } else if (percent > 62) {
+ Write(BRIGHT_075);
+ } else if (percent > 50) {
+ Write(BRIGHT_062);
+ } else if (percent > 37) {
+ Write(BRIGHT_050);
+ } else if (percent > 25) {
+ Write(BRIGHT_037);
+ } else if (percent > 12) {
+ Write(BRIGHT_025);
+ } else if (percent > 1) {
+ Write(BRIGHT_012);
+ } else {
+ Write(BRIGHT_000);
+ }
+ if (interface == kInterfaceParallel)
+ port->Release();
+}
+
+void cDriverGU256X64_3900::WriteParallel(unsigned char data)
+{
+ if (m_bSleepIsInit)
+ nSleepInit();
+ if ((port->ReadStatus() & readyMask) != readyHi)
+ {
+ int i = 0;
+ int status = port->ReadStatus();
+ for (; ((status&readyMask) != readyHi) && i < 1000; i++)
+ {
+ // wait until display ack's write but not forever
+ status=port->ReadStatus();
+ }
+ }
+
+ port->WriteControl(WRLO);
+ port->WriteData(data);
+ nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
+ port->WriteControl(WRHI);
+ nSleep(500 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
+}
+
+void cDriverGU256X64_3900::WriteSerial(unsigned char data)
+{
+ write(portFd, &data, 1);
+}
+
+void cDriverGU256X64_3900::Write(unsigned char data)
+{
+ if (interface == kInterfaceSerial)
+ WriteSerial(data);
+ else
+ WriteParallel(data);
+}
+
+void cDriverGU256X64_3900::SetPixel(int x, int y)
+{
+ unsigned char c;
+
+ if (!m_pDrawMem)
+ return;
+
+ if (x >= width || x < 0)
+ return;
+ if (y >= height || y < 0)
+ return;
+
+ if (config->upsideDown)
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ }
+
+ c = 0x80 >> (y % 8);
+
+ m_pDrawMem[x][y/8] = m_pDrawMem[x][y/8] | c;
+}
+
+void cDriverGU256X64_3900::Set8Pixels(int x, int y, unsigned char data)
+{
+ int n;
+
+ // x - pos is'nt maybe align to 8
+ x &= 0xFFF8;
+
+ for (n = 0; n < 8; ++n)
+ {
+ if (data & (0x80 >> n)) // if bit is set
+ SetPixel(x + n, y);
+ }
+}
+
+void cDriverGU256X64_3900::Refresh(bool refreshAll)
+{
+ int xb, yb;
+
+ if (!m_pVFDMem || !m_pDrawMem)
+ return;
+
+ bool doRefresh = false;
+ int minX = width;
+ int maxX = 0;
+ int minYb = m_iSizeYb;
+ int maxYb = 0;
+
+ if (CheckSetup() > 0)
+ refreshAll = true;
+
+ for (xb = 0; xb < width; ++xb)
+ {
+ for (yb = 0; yb < m_iSizeYb; ++yb)
+ {
+ if (m_pVFDMem[xb][yb] != m_pDrawMem[xb][yb])
+ {
+ m_pVFDMem[xb][yb] = m_pDrawMem[xb][yb];
+ minX = std::min(minX, xb);
+ maxX = std::max(maxX, xb);
+ minYb = std::min(minYb, yb);
+ maxYb = std::max(maxYb, yb + 1);
+ doRefresh = true;
+ }
+ }
+ }
+
+ if (config->refreshDisplay > 0)
+ {
+ m_nRefreshCounter = (m_nRefreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !m_nRefreshCounter)
+ refreshAll = true;
+ }
+
+ if (refreshAll || doRefresh)
+ {
+ if (refreshAll)
+ {
+ minX = 0;
+ maxX = width;
+ minYb = 0;
+ maxYb = m_iSizeYb;
+ // and reset RefreshCounter
+ m_nRefreshCounter = 0;
+ }
+
+ minX = std::max(minX, 0);
+ maxX = std::min(maxX, width - 1);
+ minYb = std::max(minYb, 0);
+ maxYb = std::min(maxYb, m_iSizeYb);
+
+ if (interface == kInterfaceParallel)
+ port->Claim();
+
+ if (interface == kInterfaceParallel && useDMA)
+ {
+ Write(dBLITIMAGE0);
+ Write(dBLITIMAGE1);
+ Write(dBLITIMAGE2);
+ Write(dBLITIMAGE3);
+ Write(0); // low byte address
+ Write(0); // high byte address
+ Write((m_iSizeYb*width)&0xff); // low byte size
+ Write((m_iSizeYb*width)>>8); // high byte size
+ }
+ else
+ {
+ Write(nSETCURSOR0);
+ Write(nSETCURSOR1);
+ Write(0); // low byte x
+ Write(0); // high byte x
+ Write(0); // low byte y
+ Write(0); // high byte y
+
+ Write(nBLITIMAGE0);
+ Write(nBLITIMAGE1);
+ Write(nBLITIMAGE2);
+ Write(nBLITIMAGE3);
+ Write(width&0xff); // low byte width
+ Write(width>>8); // high byte width
+ Write(m_iSizeYb); // low byte height
+ Write(0); // high byte height
+ Write(1); // end header
+ }
+
+ for (xb = 0; xb < width; xb++)
+ {
+ for (yb = 0; yb < m_iSizeYb; yb++)
+ {
+ Write((m_pVFDMem[xb][yb]) ^ (config->invert ? 0xff : 0x00));
+ }
+ // parallel port writing is busy waiting - with realtime priority you
+ // can lock the system - so don't be so greedy ;)
+ if ((xb % 32) == 31)
+ {
+ uSleep(1000);
+ }
+ }
+
+ if (interface == kInterfaceParallel)
+ port->Release();
+ }
+}
+
+} // end of namespace
diff --git a/glcddrivers/gu256x64-3900.h b/glcddrivers/gu256x64-3900.h
new file mode 100644
index 0000000..2201417
--- /dev/null
+++ b/glcddrivers/gu256x64-3900.h
@@ -0,0 +1,87 @@
+/*
+ * GraphLCD driver library
+ *
+ * gu256x64-3900.h - 8-bit driver module for Noritake GU256X64x-3900
+ * VFD displays. The VFD is either operating in
+ * 8-bit mode connected to a single PC parallel
+ * port or in serial mode connected to a single PC
+ * serial port.
+ *
+ * based on:
+ * gu256x64-372 driver module for graphlcd
+ * (c) 2004 Andreas 'randy' Weinberger <randy AT smue.org>
+ * gu140x32f driver module for graphlcd
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
+ * HD61830 device
+ * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
+ * lcdproc 0.4 driver hd44780-ext8bit
+ * (c) 1999, 1995 Benjamin Tse <blt AT comports.com>
+ *
+ * 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)
+ */
+
+#ifndef _GLCDDRIVERS_GU256X64_3900_H_
+#define _GLCDDRIVERS_GU256X64_3900_H_
+
+#include "driver.h"
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+class cDriverGU256X64_3900 : public cDriver
+{
+ cParallelPort * port;
+ int portFd;
+
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+
+ int m_iSizeYb;
+ int m_nRefreshCounter;
+ int interface;
+ bool useDMA;
+ unsigned char readyMask;
+ unsigned char readyHi;
+
+ unsigned char ** m_pDrawMem; // the draw "memory"
+ unsigned char ** m_pVFDMem; // the double buffed display "memory"
+
+ long m_nTimingAdjustCmd;
+ bool m_bSleepIsInit;
+
+ int CheckSetup();
+
+protected:
+ void ClearVFDMem();
+ void SetPixel(int x, int y);
+ int InitSerialPort();
+ int InitParallelPort();
+ void InitNormalDisplay();
+ void InitDMADisplay();
+
+ void WriteSerial(unsigned char data);
+ void WriteParallel(unsigned char data);
+ 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 Refresh(bool refreshAll = false);
+
+ virtual void SetBrightness(unsigned int percent);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/hd61830.c b/glcddrivers/hd61830.c
new file mode 100644
index 0000000..6bc225d
--- /dev/null
+++ b/glcddrivers/hd61830.c
@@ -0,0 +1,391 @@
+/*
+ * GraphLCD driver library
+ *
+ * hd61830.c - HD61830 driver class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ */
+
+#include <syslog.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "config.h"
+#include "hd61830.h"
+#include "port.h"
+
+
+namespace GLCD
+{
+
+// commands
+#define MCNT 0x00
+#define CPIT 0x01
+#define NOCH 0x02
+#define NOTD 0x03
+#define CPOS 0x04
+
+#define DSAL 0x08
+#define DSAH 0x09
+#define CACL 0x0A
+#define CACH 0x0B
+
+#define WDDI 0x0C
+#define RDDI 0x0D
+
+#define CBIT 0x0E
+#define SBIT 0x0F
+
+// control bits for DirectIO
+#define EN 0x01
+#define ENHI 0x00
+#define ENLO 0x01
+
+#define RW 0x02
+#define RWHI 0x00
+#define RWLO 0x02
+
+#define RS 0x04
+#define RSHI 0x04
+#define RSLO 0x00
+
+
+cDriverHD61830::cDriverHD61830(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ port = new cParallelPort();
+
+ useSleepInit = false;
+
+ refreshCounter = 0;
+ timeForPortCmdInNs = 0;
+}
+
+cDriverHD61830::~cDriverHD61830()
+{
+ delete port;
+ delete oldConfig;
+}
+
+int cDriverHD61830::Init()
+{
+ int i;
+ int x;
+ struct timeval tv1, tv2;
+
+ width = config->width;
+ if (width <= 0)
+ width = 240;
+ height = config->height;
+ if (height <= 0)
+ height = 128;
+
+ 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 + 7) / 8];
+ if (newLCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ newLCD[x] = new unsigned char[height];
+ memset(newLCD[x], 0, height);
+ }
+ }
+ // setup lcd array (current state)
+ oldLCD = new unsigned char*[(width + 7) / 8];
+ if (oldLCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ oldLCD[x] = new unsigned char[height];
+ memset(oldLCD[x], 0, height);
+ }
+ }
+
+ if (config->device == "")
+ {
+ // use DirectIO
+ if (port->Open(config->port) != 0)
+ return -1;
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (port->Open(config->device.c_str()) != 0)
+ return -1;
+ }
+
+ if (nSleepInit() != 0)
+ {
+ syslog(LOG_DEBUG, "%s: INFO: cannot change wait parameters (cDriver::Init)\n", config->name.c_str());
+ useSleepInit = false;
+ }
+ else
+ {
+ useSleepInit = true;
+ }
+
+ syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
+ gettimeofday(&tv1, 0);
+ for (i = 0; i < 1000; i++)
+ {
+ port->WriteData(1 % 0x100);
+ }
+ gettimeofday(&tv2, 0);
+ if (useSleepInit)
+ nSleepDeInit();
+ timeForPortCmdInNs = (tv2.tv_sec-tv1.tv_sec) * 1000000 + (tv2.tv_usec-tv1.tv_usec);
+ syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), timeForPortCmdInNs);
+
+ // initialize graphic mode
+ InitGraphic();
+
+ port->Release();
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ syslog(LOG_INFO, "%s: HD61830 initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverHD61830::DeInit()
+{
+ int x;
+
+ // free lcd array (wanted state)
+ if (newLCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ delete[] newLCD[x];
+ }
+ delete[] newLCD;
+ }
+ // free lcd array (current state)
+ if (oldLCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ delete[] oldLCD[x];
+ }
+ delete[] oldLCD;
+ }
+ if (port->Close() != 0)
+ return -1;
+ return 0;
+}
+
+int cDriverHD61830::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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;
+}
+
+int cDriverHD61830::InitGraphic()
+{
+ Write(MCNT, 0x32); // set Mode Control Register
+ // DISP ON, MASTER ON, BLINK OFF, CURSOR OFF, GRAPHIC-Mode, int.Clock
+ Write(CPIT, 0x07); // set Character Pitch Register
+ // 8 pixels per byte
+ Write(NOCH, std::max(1, (width + 7) / 8 - 1)); // set Number-Of-Characters Register
+ // (width - 1) / 8 bytes per line horizontally
+ Write(NOTD, std::max(1, height - 1)); // set Number-Of-Time-Divisions Register
+ // height - 1
+ Write(CPOS, 0x00); // set Cursor Position Register
+ // optional, because we havn't enabled a cursor
+ Write(DSAL, 0x00); // set Display Start Address Register (Low Order Byte)
+ Write(DSAH, 0x00); // set Display Start Address Register (High Order Byte)
+ Write(CACL, 0x00); // set Cursor Address Counter Register (Low Order Byte)
+ Write(CACH, 0x00); // set Cursor Address Counter Register (High Order Byte)
+
+ return 0;
+}
+
+void cDriverHD61830::Write(unsigned char cmd, unsigned char data)
+{
+ if (useSleepInit)
+ nSleepInit();
+
+ // set RS high (instruction), RW low (write) and E low
+ port->WriteControl(RSHI | RWLO | ENLO);
+ nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+
+ // Output the actual command
+ port->WriteData(cmd);
+
+ // set E high
+ port->WriteControl(RSHI | RWLO | ENHI);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+
+ // set E low
+ port->WriteControl(RSHI | RWLO | ENLO);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+
+
+ // set RS low (data), RW low (write) and E low
+ port->WriteControl(RSLO | RWLO | ENLO);
+ nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+
+ // Output the actual data
+ port->WriteData(data);
+
+ // set E high
+ port->WriteControl(RSLO | RWLO | ENHI);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+
+ // set E low
+ port->WriteControl(RSLO | RWLO | ENLO);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+
+ switch (cmd)
+ {
+ case MCNT:
+ case CPIT:
+ case NOCH:
+ case NOTD:
+ case CPOS:
+ case DSAL:
+ case DSAH:
+ case CACL:
+ case CACH:
+ nSleep(4000 - std::max(450l, timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ case WDDI:
+ case RDDI:
+ nSleep(6000 - std::max(450l, timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ case CBIT:
+ case SBIT:
+ nSleep(36000 - std::max(450l, timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ }
+ if (useSleepInit)
+ nSleepDeInit();
+}
+
+void cDriverHD61830::Clear()
+{
+ for (int x = 0; x < (width + 7) / 8; x++)
+ memset(newLCD[x], 0, height);
+}
+
+void cDriverHD61830::Set8Pixels(int x, int y, unsigned char data)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (!config->upsideDown)
+ {
+ // normal orientation
+ newLCD[x / 8][y] = newLCD[x / 8][y] | ReverseBits(data);
+ }
+ else
+ {
+ // upside down orientation
+ x = width - 1 - x;
+ y = height - 1 - y;
+ newLCD[x / 8][y] = newLCD[x / 8][y] | data;
+ }
+}
+
+void cDriverHD61830::Refresh(bool refreshAll)
+{
+ int x;
+ int y;
+ int pos = 0;
+
+ if (CheckSetup() > 0)
+ refreshAll = true;
+
+ if (config->refreshDisplay > 0)
+ {
+ refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !refreshCounter)
+ refreshAll = true;
+ }
+
+ port->Claim();
+
+ if (refreshAll)
+ {
+ // draw all
+
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ // (re-setting the cursor position
+ // might be removed, when the graphic glitches are solved)
+ Write(CACL, (pos % 0x100));
+ Write(CACH, (pos / 0x100));
+ Write(WDDI, (newLCD[x][y]) ^ (config->invert ? 0xff : 0x00));
+ oldLCD[x][y] = newLCD[x][y];
+ pos++;
+ }
+ }
+ // and reset RefreshCounter
+ refreshCounter = 0;
+ }
+ else
+ {
+ // draw only the changed bytes
+
+ bool cs = false;
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ if (newLCD[x][y] != oldLCD[x][y])
+ {
+ if (!cs)
+ {
+ Write(CACL, (pos % 0x100));
+ Write(CACH, (pos / 0x100));
+ cs = true;
+ }
+ Write(WDDI, (newLCD[x][y]) ^ (config->invert ? 0xff : 0x00));
+ oldLCD[x][y] = newLCD[x][y];
+ }
+ else
+ {
+ cs = false;
+ }
+ pos++;
+ }
+ }
+ }
+ port->Release();
+}
+
+} // end of namespace
diff --git a/glcddrivers/hd61830.h b/glcddrivers/hd61830.h
new file mode 100644
index 0000000..50f3b26
--- /dev/null
+++ b/glcddrivers/hd61830.h
@@ -0,0 +1,54 @@
+/*
+ * GraphLCD driver library
+ *
+ * hd61830.h - HD61830 driver class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ */
+
+#ifndef _GLCDDRIVERS_HD61830_H_
+#define _GLCDDRIVERS_HD61830_H_
+
+#include "driver.h"
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+class cDriverHD61830 : public cDriver
+{
+private:
+ cParallelPort * port;
+
+ unsigned char ** newLCD; // wanted state
+ unsigned char ** oldLCD; // current state
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ int refreshCounter;
+ long timeForPortCmdInNs;
+ bool useSleepInit;
+
+ int CheckSetup();
+ int InitGraphic();
+ void Write(unsigned char cmd, unsigned char data);
+
+public:
+ cDriverHD61830(cDriverConfig * config);
+ virtual ~cDriverHD61830();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ virtual void Set8Pixels(int x, int y, unsigned char data);
+ virtual void Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/image.c b/glcddrivers/image.c
new file mode 100644
index 0000000..4d11cbd
--- /dev/null
+++ b/glcddrivers/image.c
@@ -0,0 +1,167 @@
+/*
+ * GraphLCD driver library
+ *
+ * image.c - Image output device
+ * Output goes to a image file instead of LCD.
+ *
+ * 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>
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include "common.h"
+#include "config.h"
+#include "image.h"
+
+
+namespace GLCD
+{
+
+cDriverImage::cDriverImage(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+}
+
+cDriverImage::~cDriverImage()
+{
+ delete oldConfig;
+}
+
+int cDriverImage::Init()
+{
+ width = config->width;
+ if (width <= 0)
+ width = 240;
+ height = config->height;
+ if (height <= 0)
+ height = 128;
+ lineSize = (width + 7) / 8;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "")
+ {
+ }
+ }
+
+ newLCD = new unsigned char[lineSize * height];
+ if (newLCD)
+ memset(newLCD, 0, lineSize * height);
+ oldLCD = new unsigned char[lineSize * height];
+ if (oldLCD)
+ memset(oldLCD, 0, lineSize * height);
+
+ counter = 0;
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ syslog(LOG_INFO, "%s: image driver initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverImage::DeInit()
+{
+ if (newLCD)
+ delete[] newLCD;
+ if (oldLCD)
+ delete[] oldLCD;
+ return 0;
+}
+
+int cDriverImage::CheckSetup()
+{
+ if (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 cDriverImage::Clear()
+{
+ memset(newLCD, 0, lineSize * height);
+}
+
+void cDriverImage::Set8Pixels(int x, int y, unsigned char data)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (!config->upsideDown)
+ {
+ // normal orientation
+ newLCD[lineSize * y + x / 8] |= data;
+ }
+ else
+ {
+ // upside down orientation
+ x = width - 1 - x;
+ y = height - 1 - y;
+ newLCD[lineSize * y + x / 8] |= ReverseBits(data);
+ }
+}
+
+void cDriverImage::Refresh(bool refreshAll)
+{
+ int i;
+ bool refresh;
+ char fileName[256];
+ char str[32];
+ FILE * fp;
+ unsigned char c;
+
+ refresh = false;
+ if (CheckSetup() > 0)
+ refresh = true;
+
+ for (i = 0; i < lineSize * height; i++)
+ {
+ if (newLCD[i] != oldLCD[i])
+ {
+ refresh = true;
+ break;
+ }
+ }
+
+ if (refresh)
+ {
+ sprintf(fileName, "%s/%s%05d.%s", "/tmp", "lcd", counter, "pbm");
+ fp = fopen(fileName, "wb");
+ if (fp)
+ {
+ sprintf(str, "P4\n%d %d\n", width, height);
+ fwrite(str, strlen(str), 1, fp);
+ for (i = 0; i < lineSize * height; i++)
+ {
+ c = newLCD[i] ^ (config->invert ? 0xff : 0x00);
+ fwrite(&c, 1, 1, fp);
+ oldLCD[i] = newLCD[i];
+ }
+ fclose(fp);
+ }
+ counter++;
+ if (counter > 99999)
+ counter = 0;
+ }
+}
+
+} // end of namespace
diff --git a/glcddrivers/image.h b/glcddrivers/image.h
new file mode 100644
index 0000000..3e39e3f
--- /dev/null
+++ b/glcddrivers/image.h
@@ -0,0 +1,50 @@
+/*
+ * GraphLCD driver library
+ *
+ * image.h - Image output device
+ * Output goes to a image file instead of LCD.
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_IMAGE_H_
+#define _GLCDDRIVERS_IMAGE_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+
+class cDriverImage : public cDriver
+{
+private:
+ unsigned char * newLCD;
+ unsigned char * oldLCD;
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ int lineSize;
+ int counter;
+
+ int CheckSetup();
+
+public:
+ cDriverImage(cDriverConfig * config);
+ virtual ~cDriverImage();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ virtual void Set8Pixels(int x, int y, unsigned char data);
+ virtual void Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/ks0108.c b/glcddrivers/ks0108.c
new file mode 100644
index 0000000..0c607bb
--- /dev/null
+++ b/glcddrivers/ks0108.c
@@ -0,0 +1,593 @@
+/*
+ * GraphLCD driver library
+ *
+ * ks0108.c - KS0108 driver class
+ *
+ * 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>
+ */
+
+#include <syslog.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "config.h"
+#include "ks0108.h"
+#include "port.h"
+
+
+namespace GLCD
+{
+
+// commands
+const unsigned char kSEAD = 0x40; // Set (X) Address
+const unsigned char kSEPA = 0xb8; // Set (Y) Page
+const unsigned char kSEDS = 0xc0; // Set Display Start Line
+const unsigned char kDIOF = 0x3e; // Display off
+const unsigned char kDION = 0x3f; // Display on
+
+const unsigned char kCEHI = 0x01; // Chip Enable on
+const unsigned char kCELO = 0x00;
+const unsigned char kCDHI = 0x08; // Command/Data Register Select
+const unsigned char kCDLO = 0x00;
+
+const unsigned char kCS1HI = 0x02; // ChipSelect 1
+const unsigned char kCS1LO = 0x00;
+const unsigned char kCS2HI = 0x00; // ChipSelect 2
+const unsigned char kCS2LO = 0x04;
+
+
+cDriverKS0108::cDriverKS0108(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ port = new cParallelPort();
+
+ refreshCounter = 0;
+ timeForLCDInNs = 50;
+ control = 1;
+}
+
+cDriverKS0108::~cDriverKS0108()
+{
+ delete port;
+ delete oldConfig;
+}
+
+int cDriverKS0108::Init()
+{
+ int x;
+ int i;
+ struct timeval tv1, tv2;
+
+ if (config->width <= 128) {
+ width = 128;
+ } else if (config->width > 192) {
+ width = 256;
+ } else if (config->width > 128) {
+ width = 192;
+ }
+
+ if (config->height <= 64) {
+ height = 64;
+ } else if (config->height > 64) {
+ height = 128;
+ width = 128; // force 2* 128x64 display
+ }
+
+ if (width == 128 && height == 64) {
+ CS1 = kCS2HI | kCS1LO;
+ CS2 = kCS2LO | kCS1HI;
+ CS3 = -1; // invalid
+ CS4 = -1;
+ } else { // multiplexed via 74LS42
+ CS1 = kCS2HI | kCS1HI;
+ CS2 = kCS2HI | kCS1LO;
+ CS3 = kCS2LO | kCS1HI;
+ CS4 = kCS2LO | kCS1LO;
+ }
+
+ SEAD = kSEAD;
+ SEPA = kSEPA;
+ SEDS = kSEDS;
+ DIOF = kDIOF;
+ DION = kDION;
+
+ CEHI = kCEHI;
+ CELO = kCELO;
+ CDHI = kCDHI;
+ CDLO = kCDLO;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "Control")
+ {
+ if (config->options[i].value == "0")
+ control = 0;
+ else if (config->options[i].value == "1")
+ control = 1;
+ else
+ syslog(LOG_ERR, "%s error: unknown control setting %s, using default (%d)!\n",
+ config->name.c_str(), config->options[i].value.c_str(), control);
+ }
+ }
+
+ // setup linear lcd array
+ LCD = new unsigned char *[(width + 7) / 8];
+ if (LCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ LCD[x] = new unsigned char[height];
+ memset(LCD[x], 0, height);
+ }
+ }
+ // setup the lcd array for the paged ks0108
+ LCD_page = new unsigned char *[width];
+ if (LCD_page)
+ {
+ for (x = 0; x < width; x++)
+ {
+ LCD_page[x] = new unsigned char[(height + 7) / 8];
+ memset(LCD_page[x], 0, (height + 7) / 8);
+ }
+ }
+
+ if (config->device == "")
+ {
+ // use DirectIO
+ if (port->Open(config->port) != 0)
+ return -1;
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (port->Open(config->device.c_str()) != 0)
+ return -1;
+ }
+
+ if (nSleepInit() != 0)
+ {
+ syslog(LOG_DEBUG, "%s: INFO: cannot change wait parameters (cDriver::Init)\n", config->name.c_str());
+ useSleepInit = false;
+ }
+ else
+ {
+ useSleepInit = true;
+ }
+
+ syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
+ gettimeofday(&tv1, 0);
+ for (i = 0; i < 1000; i++)
+ {
+ port->WriteData(i % 0x100);
+ }
+ gettimeofday(&tv2, 0);
+ if (useSleepInit)
+ nSleepDeInit();
+ timeForPortCmdInNs = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec);
+ syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Command: %ldns\n", config->name.c_str(), timeForPortCmdInNs);
+
+ // initialize graphic mode
+ InitGraphic();
+
+ port->Release();
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ syslog(LOG_INFO, "%s: KS0108 initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverKS0108::DeInit()
+{
+ int x;
+
+ // free linear lcd array
+ if (LCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ delete[] LCD[x];
+ }
+ delete[] LCD;
+ }
+ // free paged lcd array
+ if (LCD_page)
+ {
+ for (x = 0; x < width; x++)
+ {
+ delete[] LCD_page[x];
+ }
+ delete[] LCD_page;
+ }
+ if (port->Close() != 0)
+ return -1;
+ return 0;
+}
+
+int cDriverKS0108::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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;
+}
+
+int cDriverKS0108::InitGraphic()
+{
+ // init controllers
+ if (CS1 > -1) {
+ KS0108Cmd(SEDS, 1);
+ KS0108Cmd(SEPA, 1);
+ KS0108Cmd(SEAD, 1);
+ KS0108Cmd(DION, 1);
+ }
+ if (CS2 > -1) {
+ KS0108Cmd(SEDS, 2);
+ KS0108Cmd(SEPA, 2);
+ KS0108Cmd(SEAD, 2);
+ KS0108Cmd(DION, 2);
+ }
+ if (CS3 > -1) {
+ KS0108Cmd(SEDS, 3);
+ KS0108Cmd(SEPA, 3);
+ KS0108Cmd(SEAD, 3);
+ KS0108Cmd(DION, 3);
+ }
+ if (CS4 > -1) {
+ KS0108Cmd(SEDS, 4);
+ KS0108Cmd(SEPA, 4);
+ KS0108Cmd(SEAD, 4);
+ KS0108Cmd(DION, 4);
+ }
+ return 0;
+}
+
+void cDriverKS0108::KS0108Cmd(unsigned char data, int cs)
+{
+ if (useSleepInit)
+ nSleepInit();
+ switch (cs) {
+ case 1:
+ if (control == 1)
+ port->WriteControl(CDHI | CS1 | CELO);
+ else
+ port->WriteControl(CDHI | CS1 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ if (control == 1)
+ {
+ port->WriteControl(CDHI | CS1 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ }
+ port->WriteControl(CDHI | CS1 | CELO);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ case 2:
+ if (control == 1)
+ port->WriteControl(CDHI | CS2 | CELO);
+ else
+ port->WriteControl(CDHI | CS2 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ if (control == 1)
+ {
+ port->WriteControl(CDHI | CS2 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ }
+ port->WriteControl(CDHI | CS2 | CELO);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ case 3:
+ if (control == 1)
+ port->WriteControl(CDHI | CS3 | CELO);
+ else
+ port->WriteControl(CDHI | CS3 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ if (control == 1)
+ {
+ port->WriteControl(CDHI | CS3 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ }
+ port->WriteControl(CDHI | CS3 | CELO);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ case 4:
+ if (control == 1)
+ port->WriteControl(CDHI | CS4 | CELO);
+ else
+ port->WriteControl(CDHI | CS4 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ if (control == 1)
+ {
+ port->WriteControl(CDHI | CS4 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ }
+ port->WriteControl(CDHI | CS4 | CELO);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ }
+ if (useSleepInit)
+ nSleepDeInit();
+}
+
+void cDriverKS0108::KS0108Data(unsigned char data, int cs)
+{
+ if (useSleepInit)
+ nSleepInit();
+ switch (cs) {
+ case 1:
+ if (control == 1)
+ port->WriteControl(CDLO | CS1 | CELO);
+ else
+ port->WriteControl(CDLO | CS1 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ if (control == 1)
+ {
+ port->WriteControl(CDLO | CS1 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ }
+ port->WriteControl(CDLO | CS1 | CELO);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ case 2:
+ if (control == 1)
+ port->WriteControl(CDLO | CS2 | CELO);
+ else
+ port->WriteControl(CDLO | CS2 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ if (control == 1)
+ {
+ port->WriteControl(CDLO | CS2 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ }
+ port->WriteControl(CDLO | CS2 | CELO);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ case 3:
+ if (control == 1)
+ port->WriteControl(CDLO | CS3 | CELO);
+ else
+ port->WriteControl(CDLO | CS3 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ if (control == 1)
+ {
+ port->WriteControl(CDLO | CS3 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ }
+ port->WriteControl(CDLO | CS3 | CELO);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ case 4:
+ if (control == 1)
+ port->WriteControl(CDLO | CS4 | CELO);
+ else
+ port->WriteControl(CDLO | CS4 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ if (control == 1)
+ {
+ port->WriteControl(CDLO | CS4 | CEHI);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ }
+ port->WriteControl(CDLO | CS4 | CELO);
+ nSleep((timeForLCDInNs + timeForPortCmdInNs) + 100 * config->adjustTiming);
+ break;
+ }
+ if (useSleepInit)
+ nSleepDeInit();
+}
+
+void cDriverKS0108::Clear()
+{
+ for (int x = 0; x < (width + 7) / 8; x++)
+ memset(LCD[x], 0, height);
+}
+
+void cDriverKS0108::Set8Pixels(int x, int y, unsigned char data)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (!config->upsideDown)
+ {
+ // normal orientation
+ LCD[x / 8][y] = LCD[x / 8][y] | data;
+ }
+ else
+ {
+ // upside down orientation
+ x = width - 1 - x;
+ y = height - 1 - y;
+ LCD[x / 8][y] = LCD[x / 8][y] | ReverseBits(data);
+ }
+}
+
+void cDriverKS0108::Refresh(bool refreshAll)
+{
+ int x,y;
+ int xx,yy;
+ unsigned char dByte, oneBlock[8];
+
+ if (CheckSetup() > 0)
+ refreshAll = true;
+
+ if (config->refreshDisplay > 0)
+ {
+ refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !refreshCounter)
+ refreshAll=true;
+ }
+
+ refreshAll = true; // differential update is not yet supported
+
+ if (refreshAll)
+ {
+ // draw all
+
+ // convert the linear lcd array to the paged array for the display
+ for (y = 0; y < (height + 7) / 8; y++)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ for (yy = 0; yy < 8; yy++)
+ {
+ oneBlock[yy] = LCD[x][yy + (y * 8)] ^ (config->invert ? 0xff : 0x00);
+ }
+ for (xx = 0; xx < 8; xx++)
+ {
+ dByte = 0;
+ for (yy = 0; yy < 8; yy++)
+ {
+ if (oneBlock[yy] & bitmask[xx])
+ {
+ dByte += (1 << yy);
+ }
+ }
+ LCD_page[x * 8 + xx][y] = dByte;
+ }
+ }
+ }
+
+ port->Claim();
+
+ if (width == 128 && height == 64) {
+ for (y = 0; y < 64/8; y++) {
+ KS0108Cmd(SEPA + y, 1);
+ KS0108Cmd(SEAD, 1);
+
+ for (x = 0; x < 64; x++) {
+ KS0108Data(LCD_page[x][y], 1);
+ }
+ }
+
+ for (y = 0; y < 64/8; y++) {
+ KS0108Cmd(SEPA + y, 2);
+ KS0108Cmd(SEAD, 2);
+
+ for (x = 64; x < 128; x++) {
+ KS0108Data(LCD_page[x][y], 2);
+ }
+ }
+ }
+
+ if (width > 128 && height == 64) {
+ for (y = 0; y < 64/8; y++) {
+ KS0108Cmd(SEPA + y, 1);
+ KS0108Cmd(SEAD, 1);
+
+ for (x = 0; x < 64; x++) {
+ KS0108Data(LCD_page[x][y], 1);
+ }
+ }
+
+ for (y = 0; y < 64/8; y++) {
+ KS0108Cmd(SEPA + y, 2);
+ KS0108Cmd(SEAD, 2);
+ for (x = 64; x < 128; x++) {
+ KS0108Data(LCD_page[x][y], 2);
+ }
+ }
+
+ for (y = 0; y < 64/8; y++) {
+ KS0108Cmd(SEPA + y, 3);
+ KS0108Cmd(SEAD, 3);
+
+ for (x = 128; x < 192; x++) {
+ KS0108Data(LCD_page[x][y], 3);
+ }
+ }
+
+ for (y = 0; y < 64/8; y++) {
+ if (width > 192) {
+ KS0108Cmd(SEPA + y, 4);
+ KS0108Cmd(SEAD, 4);
+ for (x = 192; x < 256; x++) {
+ KS0108Data(LCD_page[x][y], 4);
+ }
+ }
+ }
+ }
+
+ if (width == 128 && height == 128) {
+ for (y = 0; y < 64/8; y++) {
+ KS0108Cmd(SEPA + y, 1);
+ KS0108Cmd(SEAD, 1);
+
+ for (x = 0; x < 64; x++) {
+ KS0108Data(LCD_page[x][y], 1);
+ }
+ }
+
+ for (y = 0; y < 64/8; y++) {
+ KS0108Cmd(SEPA + y, 2);
+ KS0108Cmd(SEAD, 2);
+
+ for (x = 64; x < 128; x++) {
+ KS0108Data(LCD_page[x][y], 2);
+ }
+ }
+
+ for (y = 0; y < 64/8; y++) {
+ KS0108Cmd(SEPA + y, 3);
+ KS0108Cmd(SEAD, 3);
+
+ for (x = 0; x < 64; x++) {
+ KS0108Data(LCD_page[x][y+8], 3);
+ }
+ }
+
+ for (y = 0; y < 64/8; y++) {
+ KS0108Cmd(SEPA + y, 4);
+ KS0108Cmd(SEAD, 4);
+
+ for (x = 64; x < 128; x++) {
+ KS0108Data(LCD_page[x][y+8], 4);
+ }
+ }
+ }
+ port->WriteData(0);
+ port->Release();
+ }
+ else
+ {
+ // draw only the changed bytes
+ }
+}
+
+} // end of namespace
diff --git a/glcddrivers/ks0108.h b/glcddrivers/ks0108.h
new file mode 100644
index 0000000..66ac425
--- /dev/null
+++ b/glcddrivers/ks0108.h
@@ -0,0 +1,78 @@
+/*
+ * GraphLCD driver library
+ *
+ * ks0108.h - KS0108 driver class
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_KS0108_H_
+#define _GLCDDRIVERS_KS0108_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+class cDriverKS0108 : public cDriver
+{
+private:
+ cParallelPort * port;
+ unsigned char ** LCD; // linear lcd display "memory"
+ unsigned char ** LCD_page; // paged lcd display "memory"
+ int refreshCounter;
+ long timeForPortCmdInNs;
+ long timeForLCDInNs;
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ bool useSleepInit;
+
+ int CheckSetup();
+ int InitGraphic();
+ void KS0108Cmd(unsigned char data, int cs);
+ void KS0108Data(unsigned char data, int cs);
+
+ int SEAD;
+ int SEPA;
+ int SEDS;
+ int DIOF;
+ int DION;
+
+ int CEHI;
+ int CELO;
+ int CDHI;
+ int CDLO;
+ int CS1HI;
+ int CS1LO;
+ int CS2HI;
+ int CS2LO;
+
+ int CS1;
+ int CS2;
+ int CS3;
+ int CS4;
+
+ unsigned char control;
+
+public:
+ cDriverKS0108(cDriverConfig * config);
+ virtual ~cDriverKS0108();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ virtual void Set8Pixels(int x, int y, unsigned char data);
+ virtual void Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/network.c b/glcddrivers/network.c
new file mode 100644
index 0000000..9820f3b
--- /dev/null
+++ b/glcddrivers/network.c
@@ -0,0 +1,267 @@
+/*
+ * GraphLCD driver library
+ *
+ * network.c - Network output device
+ * Output goes to a network client.
+ *
+ * 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>
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "common.h"
+#include "config.h"
+#include "network.h"
+
+
+namespace GLCD
+{
+
+cDriverNetwork::cDriverNetwork(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+ childTid = 0;
+ running = false;
+ clientConnected = false;
+}
+
+cDriverNetwork::~cDriverNetwork()
+{
+ delete oldConfig;
+}
+
+int cDriverNetwork::Init()
+{
+ width = config->width;
+ if (width <= 0)
+ width = 240;
+ height = config->height;
+ if (height <= 0)
+ height = 128;
+ lineSize = (width + 7) / 8;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "")
+ {
+ }
+ }
+
+ newLCD = new unsigned char[lineSize * height];
+ if (newLCD)
+ memset(newLCD, 0, lineSize * height);
+ oldLCD = new unsigned char[lineSize * height];
+ if (oldLCD)
+ memset(oldLCD, 0, lineSize * height);
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ running = true;
+ if (pthread_create(&childTid, NULL, (void *(*) (void *)) &ServerThread, (void *)this) != 0)
+ {
+ syslog(LOG_ERR, "%s: error creating server thread.\n", config->name.c_str());
+ running = false;
+ return 1;
+ }
+ syslog(LOG_INFO, "%s: network driver initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverNetwork::DeInit()
+{
+ // stop server thread
+ running = false;
+ usleep(3000000); // wait 3 seconds
+ pthread_cancel(childTid);
+ childTid = 0;
+
+ if (newLCD)
+ delete[] newLCD;
+ if (oldLCD)
+ delete[] oldLCD;
+ return 0;
+}
+
+int cDriverNetwork::CheckSetup()
+{
+ if (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 cDriverNetwork::Clear()
+{
+ memset(newLCD, 0, lineSize * height);
+}
+
+void cDriverNetwork::Set8Pixels(int x, int y, unsigned char data)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (!config->upsideDown)
+ {
+ // normal orientation
+ newLCD[lineSize * y + x / 8] |= data;
+ }
+ else
+ {
+ // upside down orientation
+ x = width - 1 - x;
+ y = height - 1 - y;
+ newLCD[lineSize * y + x / 8] |= ReverseBits(data);
+ }
+}
+
+void cDriverNetwork::Refresh(bool refreshAll)
+{
+ int i;
+ bool refresh;
+
+ refresh = false;
+ if (CheckSetup() > 0)
+ refresh = true;
+
+ for (i = 0; i < lineSize * height; i++)
+ {
+ if (newLCD[i] != oldLCD[i])
+ {
+ refresh = true;
+ break;
+ }
+ }
+
+ if (refresh && clientConnected)
+ {
+ char msg[1024];
+ int x;
+ int y;
+ int sent;
+
+ sprintf(msg, "update begin %d %d\r\n", width, height);
+ sent = send(clientSocket, msg, strlen(msg), 0);
+ if (sent == -1)
+ {
+ syslog(LOG_ERR, "%s: error sending message: %s.\n", config->name.c_str(), strerror(errno));
+ clientConnected = false;
+ return;
+ }
+ for (y = 0; y < height; y++)
+ {
+ sprintf(msg, "update line %d ", y);
+ for (x = 0; x < lineSize; x++)
+ {
+ char tmp[3];
+ sprintf(tmp, "%02X", newLCD[y * lineSize + x]);
+ strcat(msg, tmp);
+ oldLCD[i] = newLCD[i];
+ }
+ strcat(msg, "\r\n");
+ sent = send(clientSocket, msg, strlen(msg), 0);
+ if (sent == -1)
+ {
+ syslog(LOG_ERR, "%s: error sending message: %s.\n", config->name.c_str(), strerror(errno));
+ clientConnected = false;
+ return;
+ }
+ }
+ sprintf(msg, "update end\r\n");
+ sent = send(clientSocket, msg, strlen(msg), 0);
+ if (sent == -1)
+ {
+ syslog(LOG_ERR, "%s: error sending message: %s.\n", config->name.c_str(), strerror(errno));
+ clientConnected = false;
+ return;
+ }
+ }
+}
+
+void * cDriverNetwork::ServerThread(cDriverNetwork * Driver)
+{
+ int serverSocket;
+ struct sockaddr_in address;
+ socklen_t addrlen;
+ int clientSocket;
+ fd_set set;
+ fd_set setsave;
+ struct timeval timeout;
+
+ serverSocket = socket(AF_INET, SOCK_STREAM, 0);
+ if (serverSocket == -1)
+ {
+ syslog(LOG_ERR, "%s: error creating server socket.\n", Driver->config->name.c_str());
+ return NULL;
+ }
+
+ int y = 1;
+ setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(int));
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(2003);
+ if (bind(serverSocket, (struct sockaddr *) &address, sizeof(address)) != 0)
+ {
+ syslog(LOG_ERR, "%s: error port %d is already used.\n", Driver->config->name.c_str(), 2003);
+ return NULL;
+ }
+
+ listen(serverSocket, 1);
+ addrlen = sizeof(struct sockaddr_in);
+
+ FD_ZERO(&set);
+ FD_SET(serverSocket, &set);
+ setsave = set;
+
+ while (Driver->running)
+ {
+ set = setsave;
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) < 0)
+ {
+ syslog(LOG_ERR, "%s: error during select.\n", Driver->config->name.c_str());
+ break;
+ }
+
+ if (FD_ISSET(serverSocket, &set))
+ {
+ clientSocket = accept(serverSocket, (struct sockaddr *) &address, &addrlen);
+ if (clientSocket > 0)
+ {
+ Driver->clientSocket = clientSocket;
+ Driver->clientConnected = true;
+ }
+ }
+ }
+ close(serverSocket);
+ return NULL;
+}
+
+} // end of namespace
diff --git a/glcddrivers/network.h b/glcddrivers/network.h
new file mode 100644
index 0000000..4664f4c
--- /dev/null
+++ b/glcddrivers/network.h
@@ -0,0 +1,56 @@
+/*
+ * GraphLCD driver library
+ *
+ * network.h - Network output device
+ * Output goes to a network client.
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_NETWORK_H_
+#define _GLCDDRIVERS_NETWORK_H_
+
+#include <pthread.h>
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+
+class cDriverNetwork : public cDriver
+{
+private:
+ unsigned char * newLCD;
+ unsigned char * oldLCD;
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ int lineSize;
+ bool running;
+ pthread_t childTid;
+ int clientSocket;
+ bool clientConnected;
+
+ int CheckSetup();
+ static void * ServerThread(cDriverNetwork * Driver);
+
+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 Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/noritake800.c b/glcddrivers/noritake800.c
new file mode 100644
index 0000000..fe7bc72
--- /dev/null
+++ b/glcddrivers/noritake800.c
@@ -0,0 +1,537 @@
+/*
+ * GraphLCD driver library
+ *
+ * noritake800.c - Noritake 800(A) series VFD graphlcd driver,
+ * different "Medium 0.6 dot" sizes should work,
+ * see http://www.noritake-itron.com:
+ * - GU128X64-800A,
+ * - GU256X32-800A,
+ * - GU128X32-800A,
+ * - GU160X16-800A,
+ * - GU160X32-800A,
+ * - GU192X16-800A.
+ *
+ * based on:
+ * ideas and HW-command related stuff from the open source project
+ * "lcdplugin for Winamp":
+ * (c) 1999 - 2003 Markus Zehnder <lcdplugin AT markuszehnder.ch>
+ * GU256x64-372 driver module for graphlcd
+ * (c) 20040410 Andreas 'Randy' Weinberger <randy AT smue.org>
+ * gu140x32f driver module for graphlcd
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab de>
+ * HD61830 device
+ * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
+ * lcdproc 0.4 driver hd44780-ext8bit
+ * (c) 1999, 1995 Benjamin Tse <blt AT Comports.com>
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2004 Lucian Muresan <lucianm AT users.sourceforge.net>
+ */
+
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "config.h"
+#include "noritake800.h"
+#include "port.h"
+
+namespace GLCD
+{
+
+/* LPT Control Port lines */
+#define LPT_CTL_HI_DIR 0x20
+#define LPT_CTL_HI_IRQEN 0x10
+#define LPT_CTL_LO_STROBE 0x01
+#define LPT_CTL_LO_LFEED 0x02
+#define LPT_CTL_LO_INIT 0x04
+#define LPT_CTL_LO_SELECT 0x08
+
+/* Noritake 800(A) VFD control signals bit masks*/
+#define VFDSGN_CD 0x01
+#define VFDSGN_WR 0x02
+#define VFDSGN_RD 0x04
+#define VFDSGN_CSS 0x08
+
+//wirings
+#define WIRING_LIQUIDMP3 0
+static const std::string kWiringLiquidmp3 = "LiquidMp3";
+#define WIRING_MZ 1
+static const std::string kWiringMZ = "MZ";
+// ... other wirings may follow
+
+/* Command set for this display */
+#define ANDCNTL 0x03
+#define ORCNTL 0x01
+#define XORCNTL 0x02
+#define Init800A 0x5F /* initialization code sequence 5f */
+#define Init800B 0x62
+#define Init800C 0x00+n
+#define Init800D 0xFF
+#define CLEARSCREENS 0x5e /* clear all screens (layers) */
+#define LAYER0ON 0x24 /* screen0 both on */
+#define LAYER1ON 0x28 /* screen1 both on */
+#define LAYERSON 0x2c /* both screens both on */
+#define LAYERSOFF 0x20 /* screens both off */
+#define ORON 0x40 /* OR screens */
+#define ANDON 0x48 /* AND screens */
+#define XORON 0x44 /* XOR screens */
+#define SETX 0x64 /* set X position */
+#define SETY 0x60 /* set Y position */
+#define HSHIFT 0x70 /* set horizontal shift */
+#define VSHIFT 0xB0
+#define AUTOINCOFF 0x80 /* address auto increment off */
+#define SETPOSITION 0xff
+
+
+cDriverNoritake800::cDriverNoritake800(cDriverConfig * config)
+{
+ int x = 0;
+ m_bGraphScreen0_On = true;
+ m_bGraphScreen1_On = false;
+ // 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
+ if (width <= 0)
+ width = 128;
+ height = m_Config->height; // 64
+ if (height <= 0)
+ height = 64;
+ m_iSizeYb = (height + 7)/8; // 8
+
+ //
+ // initialize wiring
+ //
+ for (unsigned int i = 0; i < m_Config->options.size(); i++)
+ {
+ if (m_Config->options[i].name == "Wiring")
+ {
+ if (m_Config->options[i].value == kWiringLiquidmp3)
+ {
+ m_nWiring = WIRING_LIQUIDMP3;
+ }
+ else if (m_Config->options[i].value == kWiringMZ)
+ {
+ m_nWiring = WIRING_MZ;
+ }
+ else
+ syslog(LOG_ERR, "%s error: wiring %s not supported, using default wiring(%s)!\n",
+ config->name.c_str(), config->options[i].value.c_str(), kWiringLiquidmp3.c_str());
+ }
+ }
+ // fill the wiring mask cache for all the 16 possibilities
+ m_pWiringMaskCache = new unsigned char[16];
+ for (unsigned int i = 0; i < 16; i++)
+ {
+ m_pWiringMaskCache[i] = N800LptWiringMask(i);
+ }
+
+ // setup linear lcd array
+ m_pDrawMem = new unsigned char*[width];
+ if (m_pDrawMem)
+ {
+ for (x = 0; x < width; x++)
+ {
+ m_pDrawMem[x] = new unsigned char[m_iSizeYb];
+ memset(m_pDrawMem[x], 0, m_iSizeYb);
+ }
+ }
+ Clear();
+
+ // setup the lcd array for the "vertikal" mem
+ m_pVFDMem = new unsigned char*[width];
+ if (m_pVFDMem)
+ {
+ for (x = 0; x < width; x++)
+ {
+ m_pVFDMem[x] = new unsigned char[m_iSizeYb];
+ memset(m_pVFDMem[x], 0, m_iSizeYb);
+ }
+ }
+ ClearVFDMem();
+}
+
+cDriverNoritake800::~cDriverNoritake800()
+{
+ int x;
+
+ if (m_pVFDMem)
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ delete[] m_pVFDMem[x];
+ }
+ delete[] m_pVFDMem;
+ if (m_pDrawMem)
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ delete[] m_pDrawMem[x];
+ }
+ delete[] m_pDrawMem;
+ delete[] m_pWiringMaskCache;
+ delete m_oldConfig;
+ delete m_pport;
+}
+
+void cDriverNoritake800::Clear()
+{
+ for (int x = 0; x < width; x++)
+ {
+ memset(m_pDrawMem[x], 0, m_iSizeYb);
+ }
+}
+
+void cDriverNoritake800::ClearVFDMem()
+{
+ for (int x = 0; x < width; x++)
+ {
+ memset(m_pVFDMem[x], 0, m_iSizeYb);
+ }
+}
+
+int cDriverNoritake800::DeInit()
+{
+ if (m_pport->Close() != 0)
+ return -1;
+ return 0;
+}
+
+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)
+ {
+ DeInit();
+ Init();
+ return 0;
+ }
+
+ if (m_Config->brightness != m_oldConfig->brightness)
+ {
+ m_oldConfig->brightness = m_Config->brightness;
+ SetBrightness(m_Config->brightness);
+ }
+
+ if (m_Config->upsideDown != m_oldConfig->upsideDown ||
+ m_Config->invert != m_oldConfig->invert)
+ {
+ m_oldConfig->upsideDown = m_Config->upsideDown;
+ m_oldConfig->invert = m_Config->invert;
+ return 1;
+ }
+ return 0;
+}
+
+int cDriverNoritake800::Init()
+{
+ int x;
+ struct timeval tv1, tv2;
+
+ if (m_Config->device == "")
+ {
+ // use DirectIO
+ if (m_pport->Open(m_Config->port) != 0)
+ return -1;
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (m_pport->Open(m_Config->device.c_str()) != 0)
+ return -1;
+ }
+
+ if (nSleepInit() != 0)
+ {
+ syslog(LOG_ERR, "%s: INFO: cannot change wait parameters Err: %s (cDriver::Init)\n", m_Config->name.c_str(), strerror(errno));
+ m_bSleepIsInit = false;
+ }
+ else
+ {
+ m_bSleepIsInit = true;
+ }
+
+ // benchmark port access
+ m_pport->Claim();
+ syslog(LOG_DEBUG, "%s: benchmark started.\n", m_Config->name.c_str());
+ gettimeofday(&tv1, 0);
+ int nBenchFactor = 100000;
+ for (x = 0; x < nBenchFactor; x++)
+ {
+ m_pport->WriteData(x % 0x100);
+ }
+ gettimeofday(&tv2, 0);
+ nSleepDeInit();
+ //m_nTimingAdjustCmd = ((tv2.tv_sec - tv1.tv_sec) * 10000 + (tv2.tv_usec - tv1.tv_usec)) / 1000;
+ m_nTimingAdjustCmd = long(double((tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec)) / double(nBenchFactor));
+ syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", m_Config->name.c_str(), m_nTimingAdjustCmd);
+ m_pport->Release();
+
+
+ // initialize display
+ N800Cmd(Init800A);
+
+ int n;
+ for (n=0; n < 15; n++)
+ {
+ N800Cmd(0x62);
+ nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd);
+ N800Cmd(n);
+ nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd);
+ N800Data(0xff);
+ nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd);
+ }
+ nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd);
+
+
+ N800Cmd(LAYERSOFF | LAYER0ON); // layer 0 of the graphic RAM on
+ N800Cmd(ORON); // OR the layers
+ N800Cmd(HSHIFT); // set horizontal shift
+ N800Cmd(0x00); // no shift
+ N800Cmd(VSHIFT); // Vertical shift =0
+ N800Cmd(AUTOINCOFF); // auto increment off
+ N800Cmd(SETX); // set x coord
+ N800Cmd(0x40); // to 0
+ N800Cmd(SETY); // set y coord
+ N800Cmd(0); // to 0
+
+ m_pport->Release();
+
+ *m_oldConfig = *m_Config;
+
+ // Set Display SetBrightness
+ SetBrightness(m_Config->brightness);
+ // clear display
+ ClearVFDMem();
+ Refresh(true);
+
+ syslog(LOG_INFO, "%s: initialization done.\n", m_Config->name.c_str());
+ return 0;
+}
+
+void cDriverNoritake800::Refresh(bool refreshAll)
+{
+ //
+ // for VFD displays, we can safely ignore refreshAll, as they are "sticky"
+ //
+ int xb, yb;
+
+ if (CheckSetup() > 0)
+ refreshAll = true; // we don't use it
+
+ if (!m_pVFDMem || !m_pDrawMem)
+ return;
+
+// // just refresh if the time needed between refreshes is up
+// m_nRefreshCounter = (m_nRefreshCounter + 1) % m_Config->refreshDisplay;
+// if(!m_nRefreshCounter)
+// {
+ m_pport->Claim();
+ for (xb = 0; xb < width; ++xb)
+ {
+ for (yb = 0; yb < m_iSizeYb; ++yb)
+ {
+ if (m_pVFDMem[xb][yb] != m_pDrawMem[xb][yb])
+ {
+ m_pVFDMem[xb][yb] = m_pDrawMem[xb][yb];
+ // reset RefreshCounter
+ m_nRefreshCounter = 0;
+ // actually write to display
+ N800WriteByte(
+ (m_pVFDMem[xb][yb]) ^ ((m_Config->invert != 0) ? 0xff : 0x00),
+ xb,
+ yb,
+ 0);
+ }
+ }
+ }
+ m_pport->Release();
+// }
+}
+
+void cDriverNoritake800::N800Cmd(unsigned char data)
+{
+ if (m_bSleepIsInit)
+ nSleepInit();
+
+ // set direction to "port_output" & C/D to C
+ m_pport->WriteControl(m_pWiringMaskCache[0x00]);
+ // write to data port
+ m_pport->WriteData(data);
+ //nSleep(100 + (100 * m_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);
+ // reset /WR on the control port
+ m_pport->WriteControl(m_pWiringMaskCache[0x00]);
+ //nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd);
+ // set direction to "port_input"
+ m_pport->WriteControl(LPT_CTL_HI_DIR | m_pWiringMaskCache[0x00]);
+}
+
+void cDriverNoritake800::N800Data(unsigned char data)
+{
+ if (m_bSleepIsInit)
+ nSleepInit();
+
+ // set direction to "port_output" & C/D to C
+ m_pport->WriteControl(m_pWiringMaskCache[VFDSGN_CD]);
+ // write to data port
+ m_pport->WriteData(data);
+ //nSleep(100 + (100 * m_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);
+ // reset /WR on the control port
+ m_pport->WriteControl(m_pWiringMaskCache[VFDSGN_CD]);
+ //nSleep(100 + (100 * m_Config->adjustTiming) - m_nTimingAdjustCmd);
+ // set direction to "port_input"
+ m_pport->WriteControl(LPT_CTL_HI_DIR | m_pWiringMaskCache[0x00]);
+}
+
+void cDriverNoritake800::SetPixel(int x, int y)
+{
+ unsigned char c;
+
+ if (!m_pDrawMem)
+ return;
+
+ if (x >= width || x < 0)
+ return;
+ if (y >= height || y < 0)
+ return;
+
+ if (m_Config->upsideDown)
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ }
+
+ c = 0x80 >> (y % 8);
+
+ m_pDrawMem[x][y/8] |= c;
+}
+
+void cDriverNoritake800::Set8Pixels(int x, int y, unsigned char data)
+{
+ int n;
+
+ // x - pos is'nt mayby align to 8
+ x &= 0xFFF8;
+
+ for (n = 0; n < 8; ++n)
+ {
+ if (data & (0x80 >> n)) // if bit is set
+ SetPixel(x + n, y);
+ }
+}
+
+void cDriverNoritake800::SetBrightness(unsigned int percent)
+{
+ // display can do 16 brightness levels,
+ // 0 = light
+ // 15 = dark
+
+ // convert from "light percentage" into darkness values from 0 to 15
+ if (percent > 100)
+ {
+ percent = 100;
+ }
+ unsigned int darkness = 16 - (unsigned int)((double)percent * 16.0 / 100.0);
+
+ m_pport->Claim();
+ N800Cmd(0x40 + (darkness & 0xf));
+ m_pport->Release();
+}
+
+unsigned char cDriverNoritake800::N800LptWiringMask(unsigned char ctrl_bits)
+{
+ unsigned char newstatus = 0x0;
+
+ if (m_nWiring == WIRING_LIQUIDMP3)
+ {
+ if (ctrl_bits & VFDSGN_CSS)
+ newstatus |= LPT_CTL_LO_STROBE;
+ else
+ newstatus &= ~LPT_CTL_LO_STROBE;
+
+ if (ctrl_bits & VFDSGN_RD)
+ newstatus |= LPT_CTL_LO_LFEED;
+ else
+ newstatus &= ~LPT_CTL_LO_LFEED;
+
+ if (ctrl_bits & VFDSGN_WR)
+ newstatus |= LPT_CTL_LO_INIT;
+ else
+ newstatus &= ~LPT_CTL_LO_INIT;
+
+ if (ctrl_bits & VFDSGN_CD)
+ newstatus |= LPT_CTL_LO_SELECT;
+ else
+ newstatus &= ~LPT_CTL_LO_SELECT;
+
+ // control commands are XOR-ed with 0x5
+ // to account for active lows and highs
+ newstatus ^= 0x5;
+ }
+ else if (m_nWiring == WIRING_MZ)
+ {
+ if (ctrl_bits & VFDSGN_CSS)
+ newstatus |= LPT_CTL_LO_INIT;
+ else
+ newstatus &= ~LPT_CTL_LO_INIT;
+
+ if (ctrl_bits & VFDSGN_RD)
+ newstatus |= LPT_CTL_LO_LFEED;
+ else
+ newstatus &= ~LPT_CTL_LO_LFEED;
+
+ if (ctrl_bits & VFDSGN_WR)
+ newstatus |= LPT_CTL_LO_STROBE;
+ else
+ newstatus &= ~LPT_CTL_LO_STROBE;
+
+ if (ctrl_bits & VFDSGN_CD)
+ newstatus |= LPT_CTL_LO_SELECT;
+ else
+ newstatus &= ~LPT_CTL_LO_SELECT;
+ }
+ return newstatus;
+}
+
+void cDriverNoritake800::N800WriteByte(unsigned char data, int nCol, int nRow, int layer)
+{
+ /* set cursor to desired address */
+ N800Cmd(SETX); /* set upper cursor address */
+ N800Cmd(nCol);
+
+ if (layer==0)
+ {
+ N800Cmd(SETY); /* set lower cursor address */
+ N800Cmd(nRow); /*layer0 */
+ }
+ else if (layer==1)
+ {
+ N800Cmd(SETY); /* set lower cursor address */
+ N800Cmd(nRow+8); /* layer 1 */
+ }
+
+ N800Data(ReverseBits(data));
+}
+
+} // end of namespace
+
diff --git a/glcddrivers/noritake800.h b/glcddrivers/noritake800.h
new file mode 100644
index 0000000..cb2dfb0
--- /dev/null
+++ b/glcddrivers/noritake800.h
@@ -0,0 +1,92 @@
+/*
+ * GraphLCD driver library
+ *
+ * noritake800.h - Noritake 800(A) series VFD graphlcd driver,
+ * different "Medium 0.6 dot" sizes should work,
+ * see http://www.noritake-itron.com:
+ * - GU128X64-800A,
+ * - GU256X32-800A,
+ * - GU128X32-800A,
+ * - GU160X16-800A,
+ * - GU160X32-800A,
+ * - GU192X16-800A.
+ *
+ * based on:
+ * ideas and HW-command related stuff from the open source project
+ * "lcdplugin for Winamp":
+ * (c) 1999 - 2003 Markus Zehnder <lcdplugin AT markuszehnder.ch>
+ * GU256x64-372 driver module for graphlcd
+ * (c) 20040410 Andreas 'Randy' Weinberger <randy AT smue.org>
+ * gu140x32f driver module for graphlcd
+ * (c) 2003 Andreas Brachold <vdr04 AT deltab de>
+ * HD61830 device
+ * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
+ * lcdproc 0.4 driver hd44780-ext8bit
+ * (c) 1999, 1995 Benjamin Tse <blt AT Comports.com>
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2004 Lucian Muresan <lucianm AT users.sourceforge.net>
+ */
+
+#ifndef _GLCDDRIVERS_NORITAKE800_H_
+#define _GLCDDRIVERS_NORITAKE800_H_
+
+#include "driver.h"
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+class cDriverNoritake800 : public cDriver
+{
+ cParallelPort * m_pport;
+
+ cDriverConfig * m_Config;
+ cDriverConfig * m_oldConfig;
+
+ int m_iSizeYb;
+ int m_nRefreshCounter;
+ int m_nWiring;
+
+ unsigned char ** m_pDrawMem; /* the draw "memory" */
+ unsigned char ** m_pVFDMem; /* the double buffed display "memory" */
+
+ long m_nTimingAdjustCmd;
+ bool m_bSleepIsInit;
+
+ // internal graphics layers
+ bool m_bGraphScreen0_On;
+ bool m_bGraphScreen1_On;
+
+ unsigned char * m_pWiringMaskCache;
+
+protected:
+ void ClearVFDMem();
+ void N800Cmd(unsigned char data);
+ void N800Data(unsigned char data);
+ int CheckSetup();
+ unsigned char N800LptWiringMask(unsigned char ctrl_bits);
+ void N800WriteByte(unsigned char data, int nCol, int nRow, int layer);
+
+public:
+ cDriverNoritake800(cDriverConfig * config);
+ virtual ~cDriverNoritake800();
+
+ virtual int Init();
+ 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 Refresh(bool refreshAll = false);
+
+ virtual void SetBrightness(unsigned int percent);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/port.c b/glcddrivers/port.c
new file mode 100644
index 0000000..d6e8e34
--- /dev/null
+++ b/glcddrivers/port.c
@@ -0,0 +1,350 @@
+/*
+ * GraphLCD driver library
+ *
+ * port.c - parallel port class with low level routines
+ *
+ * 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>
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/io.h>
+#include <sys/ioctl.h>
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+
+
+
+#include "port.h"
+
+namespace GLCD
+{
+
+static inline int port_in(int port)
+{
+ unsigned char value;
+ __asm__ volatile ("inb %1,%0"
+ : "=a" (value)
+ : "d" ((unsigned short) port));
+ return value;
+}
+
+static inline void port_out(unsigned short int port, unsigned char val)
+{
+ __asm__ volatile ("outb %0,%1\n"
+ :
+ : "a" (val), "d" (port));
+}
+
+cParallelPort::cParallelPort()
+: fd(-1),
+ port(0),
+ usePPDev(false)
+{
+}
+
+cParallelPort::~cParallelPort()
+{
+}
+
+int cParallelPort::Open(int portIO)
+{
+ usePPDev = false;
+ port = portIO;
+
+ if (port < 0x400)
+ {
+ if (ioperm(port, 3, 255) == -1)
+ {
+ syslog(LOG_ERR, "glcd drivers: ERROR ioperm(0x%X) failed! Err:%s (cParallelPort::Open)\n",
+ port, strerror(errno));
+ return -1;
+ }
+ }
+ else
+ {
+ if (iopl(3) == -1)
+ {
+ syslog(LOG_ERR, "glcd drivers: ERROR iopl failed! Err:%s (cParallelPort::Init)\n",
+ strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int cParallelPort::Open(const char * device)
+{
+ usePPDev = true;
+
+ fd = open(device, O_RDWR);
+ if (fd == -1)
+ {
+ syslog(LOG_ERR, "glcd drivers: ERROR cannot open %s. Err:%s (cParallelPort::Init)\n",
+ device, strerror(errno));
+ return -1;
+ }
+
+ if (ioctl(fd, PPCLAIM, NULL) == -1)
+ {
+ syslog(LOG_ERR, "glcd drivers: ERROR cannot claim %s. Err:%s (cParallelPort::Init)\n",
+ device, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ int mode = PARPORT_MODE_PCSPP;
+ if (ioctl(fd, PPSETMODE, &mode) == -1)
+ {
+ syslog(LOG_ERR, "glcd drivers: ERROR cannot setmode %s. Err:%s (cParallelPort::Init)\n",
+ device, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+int cParallelPort::Close()
+{
+ if (usePPDev)
+ {
+ if (fd != -1)
+ {
+ ioctl(fd, PPRELEASE);
+ close(fd);
+ fd = -1;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ if (port < 0x400)
+ {
+ if (ioperm(port, 3, 0) == -1)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ if (iopl(0) == -1)
+ {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+void cParallelPort::Claim()
+{
+ if (usePPDev)
+ ioctl(fd, PPCLAIM);
+}
+
+void cParallelPort::Release()
+{
+ if (usePPDev)
+ ioctl(fd, PPRELEASE);
+}
+
+void cParallelPort::SetDirection(int direction)
+{
+ if (usePPDev)
+ {
+ if (ioctl(fd, PPDATADIR, &direction) == -1)
+ {
+ perror("ioctl(PPDATADIR)");
+ //exit(1);
+ }
+ }
+ else
+ {
+ if (direction == kForward)
+ port_out(port + 2, port_in(port + 2) & 0xdf);
+ else
+ port_out(port + 2, port_in(port + 2) | 0x20);
+ }
+}
+
+unsigned char cParallelPort::ReadControl()
+{
+ unsigned char value;
+
+ if (usePPDev)
+ {
+ if (ioctl(fd, PPRCONTROL, &value) == -1)
+ {
+ perror("ioctl(PPRCONTROL)");
+ //exit(1);
+ }
+ }
+ else
+ {
+ value = port_in(port + 2);
+ }
+
+ return value;
+}
+
+void cParallelPort::WriteControl(unsigned char value)
+{
+ if (usePPDev)
+ {
+ if (ioctl(fd, PPWCONTROL, &value) == -1)
+ {
+ perror("ioctl(PPWCONTROL)");
+ //exit(1);
+ }
+ }
+ else
+ {
+ port_out(port + 2, value);
+ }
+}
+
+unsigned char cParallelPort::ReadStatus()
+{
+ unsigned char value;
+
+ if (usePPDev)
+ {
+ if (ioctl(fd, PPRSTATUS, &value) == -1)
+ {
+ perror("ioctl(PPRSTATUS)");
+ //exit(1);
+ }
+ }
+ else
+ {
+ value = port_in(port + 1);
+ }
+
+ return value;
+}
+
+unsigned char cParallelPort::ReadData()
+{
+ unsigned char data;
+
+ if (usePPDev)
+ {
+ if (ioctl(fd, PPRDATA, &data) == -1)
+ {
+ perror("ioctl(PPRDATA)");
+ //exit(1);
+ }
+ }
+ else
+ {
+ data = port_in(port);
+ }
+
+ return data;
+}
+
+void cParallelPort::WriteData(unsigned char data)
+{
+ if (usePPDev)
+ {
+ if (ioctl(fd, PPWDATA, &data) == -1)
+ {
+ perror("ioctl(PPWDATA)");
+ //exit(1);
+ }
+ }
+ else
+ {
+ port_out(port, data);
+ }
+}
+
+
+
+cSerialPort::cSerialPort()
+: fd(-1)
+{
+}
+
+cSerialPort::~cSerialPort()
+{
+}
+
+int cSerialPort::Open(const char * device)
+{
+ struct termios options;
+
+ fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
+ if (fd == -1)
+ {
+ printf("error opening port\n");
+ return -1;
+ }
+ //fcntl(fd, F_SETFL, FNDELAY);
+ fcntl(fd, F_SETFL, 0);
+
+ tcgetattr(fd, &options);
+
+ cfsetispeed(&options, B921600);
+ cfsetospeed(&options, B921600);
+
+ options.c_cflag &= ~PARENB;
+ options.c_cflag &= ~CSTOPB;
+ options.c_cflag &= ~CSIZE;
+ options.c_cflag |= CS8;
+
+ options.c_cflag &= ~CRTSCTS;
+
+ options.c_cflag |= (CLOCAL | CREAD);
+
+ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+
+ options.c_iflag &= ~(IXON | IXOFF | IXANY);
+
+ options.c_oflag &= ~OPOST;
+
+ tcsetattr(fd, TCSANOW, &options);
+
+ return 0;
+}
+
+int cSerialPort::Close()
+{
+ if (fd == -1)
+ return -1;
+ close(fd);
+ return 0;
+}
+
+int cSerialPort::ReadData(unsigned char * data)
+{
+ if (fd == -1)
+ return 0;
+ return read(fd, data, 1);
+}
+
+void cSerialPort::WriteData(unsigned char data)
+{
+ WriteData(&data, 1);
+}
+
+void cSerialPort::WriteData(unsigned char * data, unsigned short length)
+{
+ if (fd == -1)
+ return;
+ write(fd, data, length);
+}
+
+} // end of namespace
diff --git a/glcddrivers/port.h b/glcddrivers/port.h
new file mode 100644
index 0000000..2920461
--- /dev/null
+++ b/glcddrivers/port.h
@@ -0,0 +1,78 @@
+/*
+ * GraphLCD driver library
+ *
+ * port.h - parallel port class with low level routines
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_PORT_H_
+#define _GLCDDRIVERS_PORT_H_
+
+namespace GLCD
+{
+
+const int kForward = 0;
+const int kReverse = 1;
+
+const unsigned char kStrobeHigh = 0x00; // Pin 1
+const unsigned char kStrobeLow = 0x01;
+const unsigned char kAutoHigh = 0x00; // Pin 14
+const unsigned char kAutoLow = 0x02;
+const unsigned char kInitHigh = 0x04; // Pin 16
+const unsigned char kInitLow = 0x00;
+const unsigned char kSelectHigh = 0x00; // Pin 17
+const unsigned char kSelectLow = 0x08;
+
+class cParallelPort
+{
+private:
+ int fd;
+ int port;
+ bool usePPDev;
+
+public:
+ cParallelPort();
+ ~cParallelPort();
+
+ int Open(int port);
+ int Open(const char * device);
+ int Close();
+
+ bool IsDirectIO() const { return (!usePPDev); }
+ int GetPortHandle() const { return ((usePPDev) ? fd : port); }
+
+ void Claim();
+ void Release();
+
+ void SetDirection(int direction);
+ unsigned char ReadControl();
+ void WriteControl(unsigned char values);
+ unsigned char ReadStatus();
+ unsigned char ReadData();
+ void WriteData(unsigned char data);
+};
+
+class cSerialPort
+{
+private:
+ int fd;
+
+public:
+ cSerialPort();
+ ~cSerialPort();
+
+ int Open(const char * device);
+ int Close();
+
+ int ReadData(unsigned char * data);
+ void WriteData(unsigned char data);
+ void WriteData(unsigned char * data, unsigned short length);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/sed1330.c b/glcddrivers/sed1330.c
new file mode 100644
index 0000000..34b1c74
--- /dev/null
+++ b/glcddrivers/sed1330.c
@@ -0,0 +1,630 @@
+/*
+ * GraphLCD driver library
+ *
+ * sed1330.c - SED1330 driver class
+ *
+ * based on: hd61830.c
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ *
+ * changes for Seiko-Epson displays: Mar 2004
+ * (c) 2004 Heinz Gressenberger <heinz.gressenberger AT stmk.gv.at>
+ *
+ * init sequence taken from Thomas Baumann's LCD-Test program
+ *
+ * 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>
+ */
+
+#include <syslog.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "config.h"
+#include "port.h"
+#include "sed1330.h"
+
+
+namespace GLCD
+{
+
+// SED1330 Commands
+
+// Command Codes, Bytes for Param
+
+#define C_SYSTEMSET 0x40
+#define C_SLEEPIN 0x53
+#define C_DISPON 0x59
+#define C_DISPOFF 0x58
+#define C_SCROLL 0x44
+#define C_CSRFORM 0x5D
+#define C_CGRAMADR 0x5C
+#define C_CSRDIR_R 0x4C
+#define C_CSRDIR_L 0x4D
+#define C_CSRDIR_U 0x4E
+#define C_CSRDIR_D 0x4F
+#define C_HDOTSCR 0x5A
+#define C_OVLAY 0x5B
+#define C_CSRW 0x46
+#define C_CSRR 0x47
+#define C_MWRITE 0x42
+#define C_MREAD 0x43
+
+#define M0 0
+// 0-internal CG ROM, 1-external CG-ROM/RAM
+
+#define M1 0
+// 0 - 32 char CG-RAM, 1 - 64 char
+
+#define M2 0
+// 0 - 8x8, 1 - 8x16 matrix in CG-RAM/ROM
+
+#define FX 8
+// character-with
+#define FY 8
+// character-height
+#define BPC 1
+// byte per character, 1 - FX<=8, 2 - FX=9..16
+
+#define SAD1 0x0000
+// startadress first screen
+
+
+const int kInterface6800 = 0;
+const int kInterface8080 = 1;
+
+const std::string kWiringOriginal = "Original";
+const std::string kWiringPowerLCD = "PowerLCD";
+const std::string kWiringLCDProc = "LCDProc";
+const std::string kWiringTweakers = "Tweakers";
+const std::string kWiringYASEDW = "YASEDW";
+
+const unsigned char kOriginalA0HI = kInitHigh;
+const unsigned char kOriginalA0LO = kInitLow;
+const unsigned char kOriginalRDHI = kStrobeHigh;
+const unsigned char kOriginalRDLO = kStrobeLow;
+const unsigned char kOriginalWRHI = kAutoHigh;
+const unsigned char kOriginalWRLO = kAutoLow;
+const unsigned char kOriginalCSHI = kSelectHigh;
+const unsigned char kOriginalCSLO = kSelectLow;
+
+const unsigned char kPowerLCDA0HI = kInitHigh;
+const unsigned char kPowerLCDA0LO = kInitLow;
+const unsigned char kPowerLCDRDHI = kSelectHigh;
+const unsigned char kPowerLCDRDLO = kSelectLow;
+const unsigned char kPowerLCDWRHI = kStrobeHigh;
+const unsigned char kPowerLCDWRLO = kStrobeLow;
+const unsigned char kPowerLCDCSHI = kAutoHigh;
+const unsigned char kPowerLCDCSLO = kAutoLow;
+
+const unsigned char kLCDProcA0HI = kSelectHigh;
+const unsigned char kLCDProcA0LO = kSelectLow;
+const unsigned char kLCDProcRDHI = kInitHigh;
+const unsigned char kLCDProcRDLO = kInitLow;
+const unsigned char kLCDProcWRHI = kAutoHigh;
+const unsigned char kLCDProcWRLO = kAutoLow;
+const unsigned char kLCDProcCSHI = kStrobeHigh;
+const unsigned char kLCDProcCSLO = kStrobeLow;
+
+const unsigned char kTweakersA0HI = kSelectHigh;
+const unsigned char kTweakersA0LO = kSelectLow;
+const unsigned char kTweakersRDHI = kAutoHigh;
+const unsigned char kTweakersRDLO = kAutoLow;
+const unsigned char kTweakersWRHI = kInitHigh;
+const unsigned char kTweakersWRLO = kInitLow;
+const unsigned char kTweakersCSHI = kStrobeHigh;
+const unsigned char kTweakersCSLO = kStrobeLow;
+
+const unsigned char kYASEDWA0HI = kAutoHigh;
+const unsigned char kYASEDWA0LO = kAutoLow;
+const unsigned char kYASEDWRDHI = kInitHigh;
+const unsigned char kYASEDWRDLO = kInitLow;
+const unsigned char kYASEDWWRHI = kStrobeHigh;
+const unsigned char kYASEDWWRLO = kStrobeLow;
+const unsigned char kYASEDWCSHI = kSelectHigh;
+const unsigned char kYASEDWCSLO = kSelectLow;
+
+
+cDriverSED1330::cDriverSED1330(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ port = new cParallelPort();
+
+ refreshCounter = 0;
+}
+
+cDriverSED1330::~cDriverSED1330()
+{
+ delete port;
+ delete oldConfig;
+}
+
+int cDriverSED1330::Init()
+{
+ int x;
+ struct timeval tv1, tv2;
+
+ width = config->width;
+ if (width <= 0)
+ width = 320;
+ height = config->height;
+ if (height <= 0)
+ height = 240;
+
+ // default values
+ oscillatorFrequency = 9600;
+ interface = kInterface6800;
+ A0HI = kOriginalA0HI;
+ A0LO = kOriginalA0LO;
+ RDHI = kOriginalRDHI;
+ RDLO = kOriginalRDLO;
+ WRHI = kOriginalWRHI;
+ WRLO = kOriginalWRLO;
+ CSHI = kOriginalCSHI;
+ CSLO = kOriginalCSLO;
+ ENHI = RDHI;
+ ENLO = RDLO;
+ RWHI = WRHI;
+ RWLO = WRLO;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "Wiring")
+ {
+ if (config->options[i].value == kWiringOriginal)
+ {
+ A0HI = kOriginalA0HI;
+ A0LO = kOriginalA0LO;
+ RDHI = kOriginalRDHI;
+ RDLO = kOriginalRDLO;
+ WRHI = kOriginalWRHI;
+ WRLO = kOriginalWRLO;
+ CSHI = kOriginalCSHI;
+ CSLO = kOriginalCSLO;
+ }
+ else if (config->options[i].value == kWiringPowerLCD)
+ {
+ A0HI = kPowerLCDA0HI;
+ A0LO = kPowerLCDA0LO;
+ RDHI = kPowerLCDRDHI;
+ RDLO = kPowerLCDRDLO;
+ WRHI = kPowerLCDWRHI;
+ WRLO = kPowerLCDWRLO;
+ CSHI = kPowerLCDCSHI;
+ CSLO = kPowerLCDCSLO;
+ }
+ else if (config->options[i].value == kWiringLCDProc)
+ {
+ A0HI = kLCDProcA0HI;
+ A0LO = kLCDProcA0LO;
+ RDHI = kLCDProcRDHI;
+ RDLO = kLCDProcRDLO;
+ WRHI = kLCDProcWRHI;
+ WRLO = kLCDProcWRLO;
+ CSHI = kLCDProcCSHI;
+ CSLO = kLCDProcCSLO;
+ }
+ else if (config->options[i].value == kWiringTweakers)
+ {
+ A0HI = kTweakersA0HI;
+ A0LO = kTweakersA0LO;
+ RDHI = kTweakersRDHI;
+ RDLO = kTweakersRDLO;
+ WRHI = kTweakersWRHI;
+ WRLO = kTweakersWRLO;
+ CSHI = kTweakersCSHI;
+ CSLO = kTweakersCSLO;
+ }
+ else if (config->options[i].value == kWiringYASEDW)
+ {
+ A0HI = kYASEDWA0HI;
+ A0LO = kYASEDWA0LO;
+ RDHI = kYASEDWRDHI;
+ RDLO = kYASEDWRDLO;
+ WRHI = kYASEDWWRHI;
+ WRLO = kYASEDWWRLO;
+ CSHI = kYASEDWCSHI;
+ CSLO = kYASEDWCSLO;
+ }
+ else
+ {
+ syslog(LOG_ERR, "%s error: wiring %s not supported, using default (Original)!\n",
+ config->name.c_str(), config->options[i].value.c_str());
+ }
+ ENHI = RDHI;
+ ENLO = RDLO;
+ RWHI = WRHI;
+ RWLO = WRLO;
+ }
+ else if (config->options[i].name == "OscillatorFrequency")
+ {
+ int freq = atoi(config->options[i].value.c_str());
+ if (freq > 1000 && freq < 15000)
+ oscillatorFrequency = freq;
+ else
+ syslog(LOG_ERR, "%s error: oscillator frequency %d out of range, using default (%d)!\n",
+ config->name.c_str(), freq, oscillatorFrequency);
+ }
+ if (config->options[i].name == "Interface")
+ {
+ if (config->options[i].value == "6800")
+ interface = kInterface6800;
+ else if (config->options[i].value == "8080")
+ interface = kInterface8080;
+ else
+ syslog(LOG_ERR, "%s error: interface %s not supported, using default (6800)!\n",
+ config->name.c_str(), config->options[i].value.c_str());
+ }
+ }
+
+ // setup lcd array (wanted state)
+ newLCD = new unsigned char *[(width + 7) / 8];
+ if (newLCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ newLCD[x] = new unsigned char[height];
+ memset(newLCD[x], 0, height);
+ }
+ }
+ // setup lcd array (current state)
+ oldLCD = new unsigned char *[(width + 7) / 8];
+ if (oldLCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ oldLCD[x] = new unsigned char[height];
+ memset(oldLCD[x], 0, height);
+ }
+ }
+
+ if (config->device == "")
+ {
+ // use DirectIO
+ if (port->Open(config->port) != 0)
+ return -1;
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (port->Open(config->device.c_str()) != 0)
+ return -1;
+ }
+
+ if (nSleepInit() != 0)
+ {
+ syslog(LOG_DEBUG, "%s: INFO: cannot change wait parameters (cDriver::Init)\n", config->name.c_str());
+ useSleepInit = false;
+ }
+ else
+ {
+ useSleepInit = true;
+ }
+
+ syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
+ gettimeofday(&tv1, 0);
+ for (x = 0; x < 1000; x++)
+ {
+ port->WriteData(x % 0x100);
+ }
+ gettimeofday(&tv2, 0);
+ if (useSleepInit)
+ nSleepDeInit();
+ timeForPortCmdInNs = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec);
+ syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Command: %ldns\n", config->name.c_str(), timeForPortCmdInNs);
+
+ // initialize graphic mode
+ InitGraphic();
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+ // The SED1330 can have up to 64k memory. If there is less memory
+ // it will be overwritten twice or more times.
+ WriteCmd(C_MWRITE);
+ for (x = 0; x < 65536; x++)
+ WriteData(0x00);
+
+ WriteCmd(C_CSRW);
+ WriteData(0x00); // initializing cursor adress, low byte
+ WriteData(0x00); // high byte
+
+ port->Release();
+
+ syslog(LOG_INFO, "%s: SED1330 initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverSED1330::DeInit()
+{
+ int x;
+
+ // free lcd array (wanted state)
+ if (newLCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ delete[] newLCD[x];
+ }
+ delete[] newLCD;
+ }
+ // free lcd array (current state)
+ if (oldLCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ delete[] oldLCD[x];
+ }
+ delete[] oldLCD;
+ }
+
+ if (port->Close() != 0)
+ return -1;
+ return 0;
+}
+
+int cDriverSED1330::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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;
+}
+
+int cDriverSED1330::InitGraphic()
+{
+ // initialize setup with two graphic screens
+ // most parts taken from Thomas Baumann's LCD-Test program
+ int cr;
+ int memGraph;
+ int sad1l, sad1h, sad2l, sad2h;
+
+ cr = (width / FX - 1) * BPC;
+ memGraph = ((cr + 1) * height); // required memory for a graphic layer
+ sad1l = SAD1 & 0xFF;
+ sad1h = SAD1 >> 8 & 0xFF;
+ sad2l = ((SAD1 + memGraph) & 0xFF);
+ sad2h = ((SAD1 + memGraph) >> 8 & 0xFF);
+
+ WriteCmd(C_SYSTEMSET);
+ WriteData(0x30 + M0 + (M1 << 1) + (M2 << 2));
+ WriteData(0x80 + (FX - 1));
+ WriteData(0x00 + (FY - 1));
+ WriteData(cr); // C/R .. display adresses per line
+ WriteData((oscillatorFrequency * 1000 / (70 * height) - 1) / 9); // TC/R .. , fFR=70Hz
+ WriteData(height - 1); // L/F .. display lines per screen
+ WriteData(cr + 1); // adresses per virtual display line, low byte
+ WriteData(0x00); // adresses per virtual display line, high byte
+ // currently we don't use virtual screens greater then the display,
+ // therefore the high byte should always be zero
+
+ WriteCmd(C_SCROLL);
+ WriteData(sad1l); // low-byte startadress first layer
+ WriteData(sad1h); // high-byte startadress first layer
+ WriteData(height); // lines per screen
+ WriteData(sad2l); // low-byte startadress second layer
+ WriteData(sad2h); // high-byte startadress second layer
+ WriteData(height); // lines per screen
+ WriteData(0x00); // low-byte startadress third layer, not used
+ WriteData(0x00); // high-byte startadress third layer, not used
+ WriteData(0x00); // low-byte startadress fourth layer, not used
+ WriteData(0x00); // high-byte startadress fourth layer, not used
+
+ WriteCmd(C_CSRFORM);
+ WriteData(0x00); // cursor with: 1 pixel
+ WriteData(0x86); // cursor height: 7 lines, block mode
+
+ WriteCmd(C_CSRDIR_R); // automatic cursor increment to the right
+
+ WriteCmd(C_OVLAY);
+ WriteData(0x0C); // two layer composition with Priority-OR
+
+ WriteCmd(C_HDOTSCR);
+ WriteData(0x00);
+
+ WriteCmd(C_DISPON); // display ON with
+ WriteData(0x04); // cursor OFF and first layer ON without flashing
+
+ WriteCmd(C_CSRW);
+ WriteData(0x00); // initializing cursor adress, low byte
+ WriteData(0x00); // high byte
+
+ return 0;
+}
+
+void cDriverSED1330::WriteCmd(unsigned char cmd)
+{
+ //if (useSleepInit)
+ // nSleepInit();
+
+ if (interface == kInterface6800)
+ {
+ // set A0 high (instruction), RW low (write) and E low
+ port->WriteControl(A0HI | CSLO | RWLO | ENLO);
+ //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // Output the actual command
+ port->WriteData(cmd);
+ //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // set E high
+ port->WriteControl(A0HI | CSLO | RWLO | ENHI);
+ //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // set E low
+ port->WriteControl(A0HI | CSLO | RWLO | ENLO);
+ //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ }
+ else
+ {
+ // set A0 high (instruction), CS low, RD and WR high
+ port->WriteControl(A0HI | CSLO | RDHI | WRHI);
+ //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // Output the actual command
+ port->WriteData(cmd);
+ //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // set WR low
+ port->WriteControl(A0HI | CSLO | RDHI | WRLO);
+ //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // set WR high
+ port->WriteControl(A0HI | CSLO | RDHI | WRHI);
+ //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ }
+
+ //if (useSleepInit)
+ // nSleepDeInit();
+}
+
+void cDriverSED1330::WriteData(unsigned char data)
+{
+ //if (useSleepInit)
+ // nSleepInit();
+
+ if (interface == kInterface6800)
+ {
+ // set A0 low (data), RW low (write) and E low
+ port->WriteControl(A0LO | CSLO | RWLO | ENLO);
+ //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // Output the actual data
+ port->WriteData(data);
+ //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // set E high
+ port->WriteControl(A0LO | CSLO | RWLO | ENHI);
+ //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // set E low
+ port->WriteControl(A0LO | CSLO | RWLO | ENLO);
+ //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ }
+ else
+ {
+ // set A0 low (data), CS low, RD and WR high
+ port->WriteControl(A0LO | CSLO | RDHI | WRHI);
+ //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // Output the actual data
+ port->WriteData(data);
+ //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // set WR low
+ port->WriteControl(A0LO | CSLO | RDHI | WRLO);
+ //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ // set WR high
+ port->WriteControl(A0LO | CSLO | RDHI | WRHI);
+ //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ }
+
+ //if (useSleepInit)
+ // nSleepDeInit();
+}
+
+void cDriverSED1330::Clear()
+{
+ for (int x = 0; x < (width + 7) / 8; x++)
+ memset(newLCD[x], 0, height);
+}
+
+void cDriverSED1330::Set8Pixels(int x, int y, unsigned char data)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (!config->upsideDown)
+ {
+ // normal orientation
+ newLCD[x / 8][y] = newLCD[x / 8][y] | data;
+ }
+ else
+ {
+ // upside down orientation
+ x = width - 1 - x;
+ y = height - 1 - y;
+ newLCD[x / 8][y] = newLCD[x / 8][y] | ReverseBits(data);
+ }
+}
+
+void cDriverSED1330::Refresh(bool refreshAll)
+{
+ int x;
+ int y;
+ int pos = SAD1;
+
+ if (CheckSetup() > 0)
+ refreshAll = true;
+
+ if (config->refreshDisplay > 0)
+ {
+ refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !refreshCounter)
+ refreshAll = true;
+ }
+
+ port->Claim();
+
+ if (refreshAll)
+ {
+ // draw all
+ // set cursor to startadress
+ WriteCmd(C_CSRW);
+ WriteData(pos & 0xFF);
+ WriteData(pos >> 8);
+
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ WriteCmd(C_MWRITE); // cursor increments automatically
+ WriteData(newLCD[x][y] ^ (config->invert ? 0xff : 0x00));
+ oldLCD[x][y] = newLCD[x][y];
+ pos++;
+ }
+ }
+ // and reset RefreshCounter
+ refreshCounter = 0;
+ }
+ else
+ {
+ // draw only the changed bytes
+ bool cs = false;
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ if (newLCD[x][y] != oldLCD[x][y])
+ {
+ if (!cs)
+ {
+ WriteCmd(C_CSRW);
+ WriteData(pos & 0xFF);
+ WriteData(pos >> 8);
+ WriteCmd(C_MWRITE);
+ cs = true;
+ }
+ WriteData(newLCD[x][y] ^ (config->invert ? 0xff : 0x00));
+ oldLCD[x][y] = newLCD[x][y];
+ }
+ else
+ {
+ cs = false;
+ }
+ pos++;
+ }
+ }
+ }
+ port->Release();
+}
+
+} // end of namespace
diff --git a/glcddrivers/sed1330.h b/glcddrivers/sed1330.h
new file mode 100644
index 0000000..354b853
--- /dev/null
+++ b/glcddrivers/sed1330.h
@@ -0,0 +1,78 @@
+/*
+ * GraphLCD driver library
+ *
+ * sed1330.h - SED1330 driver class
+ *
+ * based on: hd61830.c
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ *
+ * changes for Seiko-Epson displays: Mar 2004
+ * (c) 2004 Heinz Gressenberger <heinz.gressenberger AT stmk.gv.at>
+ *
+ * init sequence taken from Thomas Baumann's LCD-Test program
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_SED1330_H_
+#define _GLCDDRIVERS_SED1330_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+class cDriverSED1330 : public cDriver
+{
+private:
+ cParallelPort * port;
+ unsigned char ** newLCD; // wanted state
+ unsigned char ** oldLCD; // current state
+ int refreshCounter;
+ long timeForPortCmdInNs;
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ bool useSleepInit;
+
+ int oscillatorFrequency;
+ int interface;
+ unsigned char A0HI;
+ unsigned char A0LO;
+ unsigned char RDHI;
+ unsigned char RDLO;
+ unsigned char ENHI;
+ unsigned char ENLO;
+ unsigned char WRHI;
+ unsigned char WRLO;
+ unsigned char RWHI;
+ unsigned char RWLO;
+ unsigned char CSHI;
+ unsigned char CSLO;
+
+ int CheckSetup();
+ int InitGraphic();
+ void WriteCmd(unsigned char cmd);
+ void WriteData(unsigned char data);
+
+public:
+ cDriverSED1330(cDriverConfig * config);
+ virtual ~cDriverSED1330();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ virtual void Set8Pixels(int x, int y, unsigned char data);
+ virtual void Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/sed1520.c b/glcddrivers/sed1520.c
new file mode 100644
index 0000000..67da56d
--- /dev/null
+++ b/glcddrivers/sed1520.c
@@ -0,0 +1,402 @@
+/*
+ * GraphLCD driver library
+ *
+ * sed1520.c - SED1520 driver class
+ *
+ * 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>
+ */
+
+#include <syslog.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "config.h"
+#include "port.h"
+#include "sed1520.h"
+
+
+namespace GLCD
+{
+
+// commands
+const unsigned char kSEAD = 0x00; // Set (X) Column Address
+const unsigned char kSEPA = 0xb8; // Set (Y) Page Address
+const unsigned char kSEDS = 0xc0; // Set Display Start Line
+const unsigned char kDION = 0xaf; // Display on
+const unsigned char kDIOF = 0xae; // Display off
+
+// control bits for DirectIO
+#define CE1 0x01
+#define CE1HI 0x01 // Chip Enable 1 on
+#define CE1LO 0x00 // Chip Enable 1 off
+
+const unsigned char kCS1HI = 0x00; // Chip Select 1
+const unsigned char kCS1LO = 0x01;
+const unsigned char kCS2HI = 0x04; // Chip Select 2
+const unsigned char kCS2LO = 0x00;
+const unsigned char kCDHI = 0x08; // Command/Data Register Select
+const unsigned char kCDLO = 0x00;
+const unsigned char kLEDHI = 0x02; // LED Backlight (not supported currently)
+const unsigned char kLEDLO = 0x00;
+
+
+cDriverSED1520::cDriverSED1520(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ port = new cParallelPort();
+
+ refreshCounter = 0;
+}
+
+cDriverSED1520::~cDriverSED1520()
+{
+ delete port;
+ delete oldConfig;
+}
+
+int cDriverSED1520::Init()
+{
+ int x;
+ int i;
+ struct timeval tv1, tv2;
+
+ if (!(config->width % 8) == 0) {
+ width = config->width + (8 - (config->width % 8));
+ } else {
+ width = config->width;
+ }
+
+ if (!(config->height % 8) == 0) {
+ height = config->height + (8 - (config->height % 8));
+ } else {
+ height = config->height;
+ }
+
+ if (width <= 0)
+ width = 120;
+ if (height <= 0)
+ height = 32;
+
+ SEAD = kSEAD;
+ SEPA = kSEPA;
+ SEDS = kSEDS;
+ DION = kDION;
+ DIOF = kDIOF;
+ LED = kLEDHI;
+ CDHI = kCDHI;
+ CDLO = kCDLO;
+ CS1HI = kCS1HI;
+ CS1LO = kCS1LO;
+ CS2HI = kCS2HI;
+ CS2LO = kCS2LO;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "")
+ {
+ }
+ }
+
+ // setup linear lcd array
+ LCD = new unsigned char *[(width + 7) / 8];
+ if (LCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ LCD[x] = new unsigned char[height];
+ memset(LCD[x], 0, height);
+ }
+ }
+ // setup the lcd array for the paged sed1520
+ LCD_page = new unsigned char *[width];
+ if (LCD_page)
+ {
+ for (x = 0; x < width; x++)
+ {
+ LCD_page[x] = new unsigned char[(height + 7) / 8];
+ memset(LCD_page[x], 0, (height + 7) / 8);
+ }
+ }
+
+ if (config->device == "")
+ {
+ // use DirectIO
+ if (port->Open(config->port) != 0)
+ return -1;
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (port->Open(config->device.c_str()) != 0)
+ return -1;
+ }
+
+ if (nSleepInit() != 0)
+ {
+ syslog(LOG_DEBUG, "%s: INFO: cannot change wait parameters (cDriver::Init)\n", config->name.c_str());
+ useSleepInit = false;
+ }
+ else
+ {
+ useSleepInit = true;
+ }
+
+ syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
+ gettimeofday(&tv1, 0);
+ for (i = 0; i < 1000; i++)
+ {
+ port->WriteData(i % 0x100);
+ }
+ gettimeofday(&tv2, 0);
+ if (useSleepInit)
+ nSleepDeInit();
+ timeForPortCmdInNs = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec);
+ syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Command: %ldns\n", config->name.c_str(), timeForPortCmdInNs);
+
+ // initialize graphic mode
+ InitGraphic();
+
+ port->Release();
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ syslog(LOG_INFO, "%s: SED1520 initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverSED1520::DeInit()
+{
+ int x;
+
+ // free linear lcd array
+ if (LCD)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ delete[] LCD[x];
+ }
+ delete[] LCD;
+ }
+ // free the lcd array for the paged sed1520
+ if (LCD_page)
+ {
+ for (x = 0; x < width; x++)
+ {
+ delete[] LCD_page[x];
+ }
+ delete[] LCD_page;
+ }
+
+ if (port->Close() != 0)
+ return -1;
+ return 0;
+}
+
+int cDriverSED1520::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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;
+}
+
+int cDriverSED1520::InitGraphic()
+{
+ // initialize controller1, set display start 0, set page 0, set y address 0, display on
+ SED1520Cmd(SEDS, 1);
+ SED1520Cmd(SEPA, 1);
+ SED1520Cmd(SEAD, 1);
+ SED1520Cmd(DION, 1);
+
+ // initialize controller2, set display start 0, set page 0, set y address 0, display on
+ SED1520Cmd(SEDS, 2);
+ SED1520Cmd(SEPA, 2);
+ SED1520Cmd(SEAD, 2);
+ SED1520Cmd(DION, 2);
+
+ return 0;
+}
+
+void cDriverSED1520::SED1520Cmd(unsigned char data, int cmdcs)
+{
+ if (useSleepInit)
+ nSleepInit();
+
+ switch (cmdcs)
+ {
+ case 1:
+ port->WriteControl(CDHI | CS1LO | CS2LO | LEDHI);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep(650 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ port->WriteControl(CDHI | CS1HI | CS2LO | LEDHI);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ break;
+ case 2:
+ port->WriteControl(CDHI | CS1LO | CS2LO | LED);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep(650 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ port->WriteControl(CDHI | CS1LO | CS2HI | LED);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ break;
+ }
+ if (useSleepInit)
+ nSleepDeInit();
+}
+
+void cDriverSED1520::SED1520Data(unsigned char data, int datacs)
+{
+ if (useSleepInit)
+ nSleepInit();
+
+ switch (datacs)
+ {
+ case 1:
+ port->WriteControl(CDLO | CS1LO | CS2LO | LEDHI);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep(650 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ port->WriteControl(CDLO | CS1HI | CS2LO | LEDHI);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ break;
+ case 2:
+ port->WriteControl(CDLO | CS1LO | CS2LO | LED);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ port->WriteData(data);
+ nSleep(650 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ port->WriteControl(CDLO | CS1LO | CS2HI | LED);
+ nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
+ break;
+ }
+ if (useSleepInit)
+ nSleepDeInit();
+}
+
+void cDriverSED1520::Clear()
+{
+ for (int x = 0; x < (width + 7) / 8; x++)
+ memset(LCD[x], 0, height);
+}
+
+void cDriverSED1520::Set8Pixels (int x, int y, unsigned char data)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (!config->upsideDown)
+ {
+ // normal orientation
+ LCD[x / 8][y] = LCD[x / 8][y] | data;
+ }
+ else
+ {
+ // upside down orientation
+ x = width - 1 - x;
+ y = height - 1 - y;
+ LCD[x / 8][y] = LCD[x / 8][y] | ReverseBits(data);
+ }
+}
+
+void cDriverSED1520::Refresh(bool refreshAll)
+{
+ int x,y,xx,yy;
+ unsigned char dByte, oneBlock[8];
+
+ if (CheckSetup() > 0)
+ refreshAll = true;
+
+ if (config->refreshDisplay > 0)
+ {
+ refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !refreshCounter)
+ refreshAll = true;
+ }
+
+ refreshAll = true; // differential update is not yet supported
+
+ if (refreshAll)
+ {
+ // draw all
+
+ // convert the linear lcd array to the paged array for the display
+ for (y = 0; y < (height + 7) / 8; y++)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ for (yy = 0; yy < 8; yy++)
+ {
+ oneBlock[yy] = LCD[x][yy + (y * 8)] ^ (config->invert ? 0xff : 0x00);
+ }
+ for (xx = 0; xx < 8; xx++)
+ {
+ dByte = 0;
+ for (yy = 0; yy < 8; yy++)
+ {
+ if (oneBlock[yy] & bitmask[xx])
+ {
+ dByte += (1 << yy);
+ }
+ }
+ LCD_page[x * 8 + xx][y] = dByte;
+ }
+ }
+ }
+
+ port->Claim();
+
+ // send lcd_soll data to display, controller 1
+ // set page and start address
+ for (y = 0; y < (height + 7) / 8; y++)
+ {
+ SED1520Cmd(SEAD, 1);
+ SED1520Cmd(SEPA + y, 1);
+ SED1520Data(0x00 ^ (config->invert ? 0xff : 0x00), 1); // fill first row with zero
+
+ for (x = 0; x < width / 2 + 1; x++)
+ {
+ SED1520Data(LCD_page[x][y], 1);
+ }
+
+ SED1520Cmd(SEAD, 2);
+ SED1520Cmd(SEPA + y, 2);
+
+ for (x = width / 2; x < width; x++)
+ {
+ SED1520Data(LCD_page[x][y], 2);
+ }
+
+ SED1520Data(0x00 ^ (config->invert ? 0xff : 0x00), 2); // fill last row with zero
+ }
+ port->Release();
+ }
+ else
+ {
+ // draw only the changed bytes
+ }
+}
+
+} // end of namespace
diff --git a/glcddrivers/sed1520.h b/glcddrivers/sed1520.h
new file mode 100644
index 0000000..931d51b
--- /dev/null
+++ b/glcddrivers/sed1520.h
@@ -0,0 +1,72 @@
+/*
+ * GraphLCD driver library
+ *
+ * sed1520.h - SED1520 driver class
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_SED1520_H_
+#define _GLCDDRIVERS_SED1520_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+class cDriverSED1520 : public cDriver
+{
+private:
+ cParallelPort * port;
+ unsigned char ** LCD; // linear lcd display "memory"
+ unsigned char ** LCD_page; // paged lcd display "memory"
+ int refreshCounter;
+ long timeForPortCmdInNs;
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ bool useSleepInit;
+
+ int SEAD;
+ int SEPA;
+ int SEDS;
+ int DION;
+ int DIOF;
+
+ int CS1LO;
+ int CS2LO;
+ int CS1HI;
+ int CS2HI;
+
+ int CDHI;
+ int CDLO;
+
+ int LED;
+ int LEDHI;
+
+ int CheckSetup();
+ int InitGraphic();
+ void SED1520Cmd(unsigned char data, int cmscd);
+ void SED1520Data(unsigned char data, int datacs);
+
+public:
+ cDriverSED1520(cDriverConfig * config);
+ virtual ~cDriverSED1520();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ virtual void Set8Pixels(int x, int y, unsigned char data);
+ virtual void Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/serdisp.c b/glcddrivers/serdisp.c
new file mode 100644
index 0000000..d1bf6f1
--- /dev/null
+++ b/glcddrivers/serdisp.c
@@ -0,0 +1,467 @@
+/*
+ * GraphLCD driver library
+ *
+ * serdisp.h - include support for displays supported by serdisplib (if library is installed)
+ * http://serdisplib.sourceforge.net
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2003-2005 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <dlfcn.h>
+
+#include "common.h"
+#include "config.h"
+#include "serdisp.h"
+
+#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 ))
+
+// taken from serdisp_control.h
+#define FEATURE_CONTRAST 0x01
+#define FEATURE_REVERSE 0x02
+#define FEATURE_BACKLIGHT 0x03
+#define FEATURE_ROTATE 0x04
+
+#define SD_COL_BLACK 0xFF000000
+
+namespace GLCD
+{
+
+cDriverSerDisp::cDriverSerDisp(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ dd = (void *) NULL;
+}
+
+cDriverSerDisp::~cDriverSerDisp(void)
+{
+ delete oldConfig;
+}
+
+int cDriverSerDisp::Init(void)
+{
+ char* errmsg; // error message returned by dlerror()
+
+ std::string controller;
+ std::string optionstring = "";
+ std::string wiringstring;
+
+
+ // dynamically load serdisplib using dlopen() & co.
+
+ sdhnd = dlopen("libserdisp.so", RTLD_LAZY);
+ if (!sdhnd) { // try /usr/local/lib
+ sdhnd = dlopen("/usr/local/lib/libserdisp.so", RTLD_LAZY);
+ }
+
+ if (!sdhnd) { // serdisplib seems not to be installed
+ syslog(LOG_ERR, "%s: error: unable to dynamically load library '%s'. Err: %s (cDriver::Init)\n",
+ config->name.c_str(), "libserdisp.so", "not found");
+ return -1;
+ }
+
+ dlerror(); // clear error code
+
+ /* pre-init some flags, function pointers, ... */
+ supports_options = 0;
+ fg_colour = 1;
+ bg_colour = -1;
+
+ // 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());
+
+ 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_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_setpixcol = (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;
+ }
+ 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;
+ }
+ } /* >= 1.96 */
+ }
+
+ // load other symbols that will be required
+ fp_serdisp_init = (void*(*)(void*, const char*, const char*)) dlsym(sdhnd, "serdisp_init");
+ 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_init", errmsg);
+ return -1;
+ }
+
+ fp_serdisp_rewrite = (void (*)(void*)) dlsym(sdhnd, "serdisp_rewrite");
+ 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_rewrite", errmsg);
+ return -1;
+ }
+
+ fp_serdisp_update = (void (*)(void*)) dlsym(sdhnd, "serdisp_update");
+ 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_update", errmsg);
+ return -1;
+ }
+
+ fp_serdisp_clearbuffer = (void (*)(void*)) dlsym(sdhnd, "serdisp_clearbuffer");
+ 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_clearbuffer", errmsg);
+ return -1;
+ }
+
+ fp_serdisp_feature = (int (*)(void*, int, int)) dlsym(sdhnd, "serdisp_feature");
+ 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_feature", errmsg);
+ return -1;
+ }
+
+ fp_serdisp_close = (void (*)(void*))dlsym(sdhnd, "serdisp_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(), "serdisp_close", errmsg);
+ return -1;
+ }
+
+ fp_serdisp_getwidth = (int (*)(void*)) dlsym(sdhnd, "serdisp_getwidth");
+ 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_getwidth", errmsg);
+ return -1;
+ }
+
+ fp_serdisp_getheight = (int (*)(void*)) dlsym(sdhnd, "serdisp_getheight");
+ 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_getheight", errmsg);
+ return -1;
+ }
+
+ // done loading all required symbols
+
+
+ // setting up the display
+ width = 0;
+ height = 0;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "Controller") {
+ controller = config->options[i].value;
+ } else if (config->options[i].name == "Options") {
+ optionstring = config->options[i].value;
+ } 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 */
+ } 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 */
+ }
+ }
+
+ if (wiringstring.length()) {
+ optionstring = "WIRING=" + wiringstring + ((optionstring != "") ? ";" + optionstring : "");
+ }
+
+ if (controller == "")
+ {
+ syslog(LOG_ERR, "%s error: no controller given!\n", config->name.c_str());
+ return -1;
+ }
+
+
+ if (config->device == "")
+ {
+ // 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);
+ }
+
+ if (sdcd == 0) {
+ syslog(LOG_ERR, "%s: error: unable to open port 0x%x for display %s. (cDriver::Init)\n",
+ config->name.c_str(), config->port, controller.c_str());
+ return -1;
+ }
+
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (serdisp_version < SERDISP_VERSION(1,93) ) {
+ sdcd = fp_PP_open(config->device.c_str());
+ } else {
+ sdcd = fp_SDCONN_open(config->device.c_str());
+ }
+
+ if (sdcd == 0) {
+ syslog(LOG_ERR, "%s: error: unable to open device %s for display %s. (cDriver::Init)\n",
+ config->name.c_str(), config->device.c_str(), controller.c_str());
+ return -1;
+ }
+ }
+
+ 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());
+
+ if (!dd)
+ {
+ syslog(LOG_ERR, "%s: error: cannot open display %s. Err:%s (cDriver::Init)\n",
+ config->name.c_str(), controller.c_str(), "no handle");
+ return -1;
+ }
+
+ width = config->width;
+ if (width <= 0)
+ width = fp_serdisp_getwidth(dd);
+ height = config->height;
+ if (height <= 0)
+ height = fp_serdisp_getheight(dd);
+
+ if (serdisp_version < SERDISP_VERSION(1,96) ) {
+ fp_serdisp_feature(dd, FEATURE_ROTATE, config->upsideDown);
+ fp_serdisp_feature(dd, FEATURE_CONTRAST, config->contrast);
+ fp_serdisp_feature(dd, FEATURE_BACKLIGHT, config->backlight);
+ fp_serdisp_feature(dd, FEATURE_REVERSE, config->invert);
+ } else {
+ /* standard options */
+ fp_serdisp_setoption(dd, "ROTATE", config->upsideDown);
+ fp_serdisp_setoption(dd, "CONTRAST", config->contrast);
+ fp_serdisp_setoption(dd, "BACKLIGHT", config->backlight);
+ fp_serdisp_setoption(dd, "INVERT", config->invert);
+
+ /* driver dependend options */
+ for (unsigned int i = 0; i < config->options.size(); i++) {
+ std::string optionname = config->options[i].name;
+ if (optionname != "UpsideDown" && optionname != "Contrast" &&
+ optionname != "Backlight" && optionname != "Invert") {
+
+ if ( fp_serdisp_isoption(dd, optionname.c_str()) == 1 ) /* if == 1: option is existing AND r/w */
+ fp_serdisp_setoption(dd, optionname.c_str(), strtol(config->options[i].value.c_str(), NULL, 0));
+ }
+ }
+
+ }
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ 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);
+ sdhnd = NULL;
+
+ return 0;
+}
+
+int cDriverSerDisp::CheckSetup()
+{
+ bool update = false;
+
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ config->width != oldConfig->width ||
+ config->height != oldConfig->height)
+ {
+ DeInit();
+ Init();
+ return 0;
+ }
+
+ if (config->contrast != oldConfig->contrast)
+ {
+ fp_serdisp_feature(dd, FEATURE_CONTRAST, config->contrast);
+ oldConfig->contrast = config->contrast;
+ update = true;
+ }
+ if (config->backlight != oldConfig->backlight)
+ {
+ fp_serdisp_feature(dd, FEATURE_BACKLIGHT, config->backlight);
+ oldConfig->backlight = config->backlight;
+ update = true;
+ }
+ if (config->upsideDown != oldConfig->upsideDown)
+ {
+ fp_serdisp_feature(dd, FEATURE_ROTATE, config->upsideDown);
+ oldConfig->upsideDown = config->upsideDown;
+ update = true;
+ }
+ if (config->invert != oldConfig->invert)
+ {
+ fp_serdisp_feature(dd, FEATURE_REVERSE, config->invert);
+ oldConfig->invert = config->invert;
+ update = true;
+ }
+
+ /* driver dependend options */
+ for (unsigned int i = 0; i < config->options.size(); i++) {
+ std::string optionname = config->options[i].name;
+ if (optionname != "UpsideDown" && optionname != "Contrast" &&
+ optionname != "Backlight" && optionname != "Invert") {
+
+ if ( fp_serdisp_isoption(dd, optionname.c_str()) == 1 ) /* if == 1: option is existing AND r/w */
+ fp_serdisp_setoption(dd, optionname.c_str(), strtol(config->options[i].value.c_str(), NULL, 0));
+ oldConfig->options[i] = config->options[i];
+ update = true;
+ }
+ }
+
+
+ if (update)
+ return 1;
+ return 0;
+}
+
+void cDriverSerDisp::Clear(void)
+{
+ if (bg_colour == -1)
+ fp_serdisp_clearbuffer(dd);
+ else { /* if bg_colour 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() */
+ }
+}
+
+void cDriverSerDisp::Set8Pixels(int x, int y, unsigned char data) {
+ int i, start, pixel;
+
+ data = ReverseBits(data);
+
+ start = (x >> 3) << 3;
+
+ 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() */
+ }
+}
+
+void cDriverSerDisp::Refresh(bool refreshAll)
+{
+ if (CheckSetup() == 1)
+ refreshAll = true;
+
+ if (refreshAll)
+ fp_serdisp_rewrite(dd);
+ else
+ fp_serdisp_update(dd);
+}
+
+} // end of namespace
diff --git a/glcddrivers/serdisp.h b/glcddrivers/serdisp.h
new file mode 100644
index 0000000..ddd7827
--- /dev/null
+++ b/glcddrivers/serdisp.h
@@ -0,0 +1,78 @@
+/*
+ * GraphLCD driver library
+ *
+ * serdisp.h - include support for displays supported by serdisplib (if library is installed)
+ * http://serdisplib.sourceforge.net
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2003-2005 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
+ */
+
+#ifndef _GLCDDRIVERS_SERDISP_H_
+#define _GLCDDRIVERS_SERDISP_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+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
+ void* sdcd; // serdisp connect descriptor
+
+ long (*fp_serdisp_getversioncode) ();
+
+ 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
+ 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);
+ int (*fp_serdisp_getwidth) (void* dd);
+ int (*fp_serdisp_getheight) (void* dd);
+ void (*fp_serdisp_quit) (void* dd);
+ void (*fp_serdisp_close) (void* dd);
+
+ int CheckSetup();
+
+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 Refresh(bool refreshAll = false);
+};
+
+#endif
+
+} // end of namespace
diff --git a/glcddrivers/simlcd.c b/glcddrivers/simlcd.c
new file mode 100644
index 0000000..82fad54
--- /dev/null
+++ b/glcddrivers/simlcd.c
@@ -0,0 +1,183 @@
+/*
+ * GraphLCD driver library
+ *
+ * simlcd.c - SimLCD driver class
+ * Output goes to a file instead of lcd.
+ * Use SimLCD tool to view this file.
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include "common.h"
+#include "config.h"
+#include "simlcd.h"
+
+
+namespace GLCD
+{
+
+cDriverSimLCD::cDriverSimLCD(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+}
+
+cDriverSimLCD::~cDriverSimLCD()
+{
+ delete oldConfig;
+}
+
+int cDriverSimLCD::Init()
+{
+ width = config->width;
+ if (width <= 0)
+ width = 240;
+ height = config->height;
+ if (height <= 0)
+ height = 128;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "")
+ {
+ }
+ }
+
+ // setup lcd array
+ LCD = new unsigned char *[(width + 7) / 8];
+ if (LCD)
+ {
+ for (int x = 0; x < (width + 7) / 8; x++)
+ {
+ LCD[x] = new unsigned char[height];
+ memset(LCD[x], 0, height);
+ }
+ }
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ syslog(LOG_INFO, "%s: SIMLCD initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverSimLCD::DeInit()
+{
+ // free lcd array
+ if (LCD)
+ {
+ for (int x = 0; x < (width + 7) / 8; x++)
+ {
+ delete[] LCD[x];
+ }
+ delete[] LCD;
+ }
+
+ return 0;
+}
+
+int cDriverSimLCD::CheckSetup()
+{
+ if (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 cDriverSimLCD::Clear()
+{
+ for (int x = 0; x < (width + 7) / 8; x++)
+ memset(LCD[x], 0, height);
+}
+
+void cDriverSimLCD::Set8Pixels(int x, int y, unsigned char data)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (!config->upsideDown)
+ {
+ // normal orientation
+ LCD[x / 8][y] = LCD[x / 8][y] | data;
+ }
+ else
+ {
+ // upside down orientation
+ x = width - 1 - x;
+ y = height - 1 - y;
+ LCD[x / 8][y] = LCD[x / 8][y] | ReverseBits(data);
+ }
+}
+
+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");
+ if (!fp || refreshAll)
+ {
+ if (fp)
+ fclose(fp);
+ fp = fopen("/tmp/simlcd.dat", "w");
+ if (fp)
+ {
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < (width + 7) / 8; x++)
+ {
+ c = LCD[x][y] ^ (config->invert ? 0xff : 0x00);
+ for (i = 0; i < 8; i++)
+ {
+ if (c & 0x80)
+ {
+ fprintf(fp,"#");
+ }
+ else
+ {
+ fprintf(fp,".");
+ }
+ c = c << 1;
+ }
+ }
+ fprintf(fp,"\n");
+ }
+ fclose(fp);
+ }
+
+ fp = fopen("/tmp/simlcd.sem", "w");
+ fclose(fp);
+ }
+ else
+ {
+ fclose(fp);
+ }
+}
+
+} // end of namespace
diff --git a/glcddrivers/simlcd.h b/glcddrivers/simlcd.h
new file mode 100644
index 0000000..8b2aca8
--- /dev/null
+++ b/glcddrivers/simlcd.h
@@ -0,0 +1,48 @@
+/*
+ * GraphLCD driver library
+ *
+ * simlcd.h - SimLCD driver class
+ * Output goes to a file instead of lcd.
+ * Use SimLCD tool to view this file.
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ */
+
+#ifndef _GLCDDRIVERS_SIMLCD_H_
+#define _GLCDDRIVERS_SIMLCD_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+
+class cDriverSimLCD : public cDriver
+{
+private:
+ unsigned char ** LCD;
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+
+ 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 Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff --git a/glcddrivers/t6963c.c b/glcddrivers/t6963c.c
new file mode 100644
index 0000000..6c0460c
--- /dev/null
+++ b/glcddrivers/t6963c.c
@@ -0,0 +1,678 @@
+/*
+ * GraphLCD driver library
+ *
+ * t6963c.c - T6963C driver class
+ *
+ * low level routines based on lcdproc 0.5 driver, (c) 2001 Manuel Stahl
+ *
+ * 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>
+ */
+
+#include <syslog.h>
+
+#include "common.h"
+#include "config.h"
+#include "port.h"
+#include "t6963c.h"
+
+
+namespace GLCD
+{
+
+// T6963 commands
+const unsigned char kSetCursorPointer = 0x21;
+const unsigned char kSetOffsetRegister = 0x22;
+const unsigned char kSetAddressPointer = 0x24;
+
+const unsigned char kSetTextHomeAddress = 0x40;
+const unsigned char kSetTextArea = 0x41;
+const unsigned char kSetGraphicHomeAddress = 0x42;
+const unsigned char kSetGraphicArea = 0x43;
+
+const unsigned char kSetMode = 0x80;
+const unsigned char kSetDisplayMode = 0x90;
+const unsigned char kSetCursorPattern = 0xA0;
+
+const unsigned char kDataWriteInc = 0xC0;
+const unsigned char kDataReadInc = 0xC1;
+const unsigned char kDataWriteDec = 0xC2;
+const unsigned char kDataReadDec = 0xC3;
+const unsigned char kDataWrite = 0xC4;
+const unsigned char kDataRead = 0xC5;
+
+const unsigned char kAutoWrite = 0xB0;
+const unsigned char kAutoRead = 0xB1;
+const unsigned char kAutoReset = 0xB2;
+
+
+// T6963 Parameters
+const unsigned char kModeOr = 0x00;
+const unsigned char kModeXor = 0x01;
+const unsigned char kModeAnd = 0x03;
+const unsigned char kModeTextAttribute = 0x04;
+const unsigned char kModeInternalCG = 0x00;
+const unsigned char kModeExternalCG = 0x08;
+
+const unsigned char kTextAttributeNormal = 0x00;
+const unsigned char kTextAttributeInverse = 0x05;
+const unsigned char kTextAttributeNoDisplay = 0x03;
+const unsigned char kTextAttributeBlink = 0x08;
+
+const unsigned char kDisplayModeBlink = 0x01;
+const unsigned char kDisplayModeCursor = 0x02;
+const unsigned char kDisplayModeText = 0x04;
+const unsigned char kDisplayModeGraphic = 0x08;
+
+const unsigned short kGraphicBase = 0x0000;
+const unsigned short kTextBase = 0x1500;
+const unsigned short kCGRAMBase = 0x1800;
+
+
+// T6963 Wirings
+static const std::string kWiringStandard = "Standard";
+static const std::string kWiringWindows = "Windows";
+static const std::string kWiringSerial = "Serial";
+
+const unsigned char kStandardWRHI = 0x00; // 01 / nSTRB
+const unsigned char kStandardWRLO = 0x01; //
+const unsigned char kStandardRDHI = 0x00; // 17 / nSELECT
+const unsigned char kStandardRDLO = 0x08; //
+const unsigned char kStandardCEHI = 0x00; // 14 / nLINEFEED
+const unsigned char kStandardCELO = 0x02; //
+const unsigned char kStandardCDHI = 0x04; // 16 / INIT
+const unsigned char kStandardCDLO = 0x00; //
+
+const unsigned char kWindowsWRHI = 0x04; // 16 / INIT
+const unsigned char kWindowsWRLO = 0x00; //
+const unsigned char kWindowsRDHI = 0x00; // 14 / nLINEFEED
+const unsigned char kWindowsRDLO = 0x02; //
+const unsigned char kWindowsCEHI = 0x00; // 01 / nSTRB
+const unsigned char kWindowsCELO = 0x01; //
+const unsigned char kWindowsCDHI = 0x00; // 17 / nSELECT
+const unsigned char kWindowsCDLO = 0x08; //
+
+const unsigned char kSerialWRHI = 0x01; // 01 / nSTRB
+const unsigned char kSerialWRLO = 0x00; //
+const unsigned char kSerialRDHI = 0x08; // 17 / nSELECT
+const unsigned char kSerialRDLO = 0x00; //
+const unsigned char kSerialCEHI = 0x02; // 14 / nLINEFEED
+const unsigned char kSerialCELO = 0x00; //
+const unsigned char kSerialCDHI = 0x00; // 16 / INIT
+const unsigned char kSerialCDLO = 0x04; //
+
+
+cDriverT6963C::cDriverT6963C(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+
+ port = new cParallelPort();
+
+ //width = config->width;
+ //height = config->height;
+ refreshCounter = 0;
+ displayMode = 0;
+ bidirectLPT = 1;
+ autoWrite = false;
+ serial = 0;
+}
+
+cDriverT6963C::~cDriverT6963C()
+{
+ delete port;
+ delete oldConfig;
+}
+
+int cDriverT6963C::Init()
+{
+ int x;
+
+ width = config->width;
+ if (width <= 0)
+ width = 240;
+ height = config->height;
+ if (height <= 0)
+ height = 128;
+
+ // default values
+ FS = 6;
+ WRHI = kStandardWRHI;
+ WRLO = kStandardWRLO;
+ RDHI = kStandardRDHI;
+ RDLO = kStandardRDLO;
+ CEHI = kStandardCEHI;
+ CELO = kStandardCELO;
+ CDHI = kStandardCDHI;
+ CDLO = kStandardCDLO;
+ useAutoMode = true;
+ useStatusCheck = true;
+
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "FontSelect")
+ {
+ int fontSelect = atoi(config->options[i].value.c_str());
+ if (fontSelect == 6)
+ FS = 6;
+ else if (fontSelect == 8)
+ FS = 8;
+ else
+ syslog(LOG_ERR, "%s error: font select %d not supported, using default (%d)!\n",
+ config->name.c_str(), fontSelect, FS);
+ }
+ else if (config->options[i].name == "Wiring")
+ {
+ if (config->options[i].value == kWiringStandard)
+ {
+ WRHI = kStandardWRHI;
+ WRLO = kStandardWRLO;
+ RDHI = kStandardRDHI;
+ RDLO = kStandardRDLO;
+ CEHI = kStandardCEHI;
+ CELO = kStandardCELO;
+ CDHI = kStandardCDHI;
+ CDLO = kStandardCDLO;
+ }
+ else if (config->options[i].value == kWiringWindows)
+ {
+ WRHI = kWindowsWRHI;
+ WRLO = kWindowsWRLO;
+ RDHI = kWindowsRDHI;
+ RDLO = kWindowsRDLO;
+ CEHI = kWindowsCEHI;
+ CELO = kWindowsCELO;
+ CDHI = kWindowsCDHI;
+ CDLO = kWindowsCDLO;
+ }
+ else if (config->options[i].value == kWiringSerial)
+ {
+ serial = 1;
+ WRHI = kSerialWRHI;
+ WRLO = kSerialWRLO;
+ RDHI = kSerialRDHI;
+ RDLO = kSerialRDLO;
+ CEHI = kSerialCEHI;
+ CELO = kSerialCELO;
+ CDHI = kSerialCDHI;
+ CDLO = kSerialCDLO;
+ }
+ else
+ syslog(LOG_ERR, "%s error: wiring %s not supported, using default (Standard)!\n",
+ config->name.c_str(), config->options[i].value.c_str());
+ }
+ else if (config->options[i].name == "AutoMode")
+ {
+ if (config->options[i].value == "yes")
+ useAutoMode = true;
+ else if (config->options[i].value == "no")
+ useAutoMode = false;
+ else
+ syslog(LOG_ERR, "%s error: unknown auto mode setting %s, using default (%s)!\n",
+ config->name.c_str(), config->options[i].value.c_str(), useAutoMode ? "yes" : "no");
+ }
+ else if (config->options[i].name == "StatusCheck")
+ {
+ if (config->options[i].value == "yes")
+ useStatusCheck = true;
+ else if (config->options[i].value == "no")
+ useStatusCheck = false;
+ else
+ syslog(LOG_ERR, "%s error: unknown status check setting %s, using default (%s)!\n",
+ config->name.c_str(), config->options[i].value.c_str(), useStatusCheck ? "yes" : "no");
+ }
+ }
+
+ // setup lcd array (wanted state)
+ newLCD = new unsigned char*[(width + (FS - 1)) / FS];
+ if (newLCD)
+ {
+ for (x = 0; x < (width + (FS - 1)) / FS; x++)
+ {
+ newLCD[x] = new unsigned char[height];
+ memset(newLCD[x], 0, height);
+ }
+ }
+ // setup lcd array (current state)
+ oldLCD = new unsigned char*[(width + (FS - 1)) / FS];
+ if (oldLCD)
+ {
+ for (x = 0; x < (width + (FS - 1)) / FS; x++)
+ {
+ oldLCD[x] = new unsigned char[height];
+ memset(oldLCD[x], 0, height);
+ }
+ }
+
+ if (config->device == "")
+ {
+ // use DirectIO
+ if (port->Open(config->port) != 0)
+ return -1;
+ uSleep(10);
+ }
+ else
+ {
+ // use ppdev
+ if (port->Open(config->device.c_str()) != 0)
+ return -1;
+ }
+
+ // disable chip
+ // disable reading from LCD
+ // disable writing to LCD
+ // command/status mode
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI);
+ port->SetDirection(kForward); // make 8-bit parallel port an output port
+
+ // Test ECP mode
+ if (bidirectLPT == 1)
+ {
+ syslog(LOG_DEBUG, "%s: Testing ECP mode...\n", config->name.c_str());
+ int i = 0;
+ int ecp_input;
+ port->SetDirection(kReverse);
+ for (int i = 0; i < 100; i++)
+ {
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI); // wr, ce, cd, rd
+ T6963CSetControl(WRHI | CELO | CDHI | RDLO);
+ T6963CSetControl(WRHI | CELO | CDHI | RDLO);
+ T6963CSetControl(WRHI | CELO | CDHI | RDLO);
+ ecp_input = port->ReadData();
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI);
+ if ((ecp_input & 0x03) == 0x03)
+ break;
+ }
+ port->SetDirection(kForward);
+ if (i >= 100)
+ {
+ syslog(LOG_DEBUG, "%s: ECP mode not working! -> is now disabled\n", config->name.c_str());
+ bidirectLPT = 0;
+ }
+ else
+ syslog(LOG_DEBUG, "%s: working!\n", config->name.c_str());
+ }
+
+ T6963CCommandWord(kSetGraphicHomeAddress, kGraphicBase);
+ if (width % FS == 0)
+ T6963CCommandWord(kSetGraphicArea, width / FS);
+ else
+ T6963CCommandWord(kSetGraphicArea, width / FS + 1);
+
+ T6963CCommand(kSetMode | kModeOr | kModeInternalCG);
+
+ T6963CDisplayMode(kDisplayModeText, false);
+ T6963CDisplayMode(kDisplayModeGraphic, true);
+ T6963CDisplayMode(kDisplayModeCursor, false);
+ T6963CDisplayMode(kDisplayModeBlink, false);
+
+ port->Release();
+
+ *oldConfig = *config;
+
+ // clear display
+ Clear();
+
+ syslog(LOG_INFO, "%s: T6963 initialized.\n", config->name.c_str());
+ return 0;
+}
+
+int cDriverT6963C::DeInit()
+{
+ int x;
+ // free lcd array (wanted state)
+ if (newLCD)
+ {
+ for (x = 0; x < (width + (FS - 1)) / FS; x++)
+ {
+ delete[] newLCD[x];
+ }
+ delete[] newLCD;
+ }
+ // free lcd array (current state)
+ if (oldLCD)
+ {
+ for (x = 0; x < (width + (FS - 1)) / FS; x++)
+ {
+ delete[] oldLCD[x];
+ }
+ delete[] oldLCD;
+ }
+
+ if (port->Close() != 0)
+ return -1;
+ return 0;
+}
+
+int cDriverT6963C::CheckSetup()
+{
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ 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 cDriverT6963C::Clear()
+{
+ for (int x = 0; x < (width + (FS - 1)) / FS; x++)
+ memset(newLCD[x], 0, height);
+}
+
+void cDriverT6963C::Set8Pixels(int x, int y, unsigned char data)
+{
+ if (x >= width || y >= height)
+ return;
+
+ if (FS == 6)
+ {
+ unsigned char data1 = 0;
+ unsigned char data2 = 0;
+ unsigned char data3 = 0;
+
+ if (!config->upsideDown)
+ {
+ // normal orientation
+ x = x - (x % 8);
+ data1 = data >> (2 + (x % 6));
+ if (x % 6 == 5)
+ {
+ data2 = data >> 1;
+ data3 = data << 5;
+ }
+ else
+ data2 = data << (4 - (x % 6));
+
+ newLCD[x / 6][y] |= data1;
+ if (x / 6 + 1 < (width + 5) / 6)
+ newLCD[x / 6 + 1][y] |= data2;
+ if (x / 6 + 2 < (width + 5) / 6)
+ if (x % 6 == 5)
+ newLCD[x / 6 + 2][y] |= data3;
+ }
+ else
+ {
+ // upside down orientation
+ x = width - 1 - x;
+ y = height - 1 - y;
+ x = x - (x % 8);
+ data = ReverseBits(data);
+
+ data1 = data >> (2 + (x % 6));
+ if (x % 6 == 5)
+ {
+ data2 = data >> 1;
+ data3 = data << 5;
+ }
+ else
+ data2 = data << (4 - (x % 6));
+
+ newLCD[x / 6][y] |= data1;
+ if (x / 6 + 1 < (width + 5) / 6)
+ newLCD[x / 6 + 1][y] |= data2;
+ if (x / 6 + 2 < (width + 5) / 6)
+ if (x % 6 == 5)
+ newLCD[x / 6 + 2][y] |= data3;
+ }
+ }
+ else
+ {
+ if (!config->upsideDown)
+ {
+ newLCD[x / 8][y] |= data;
+ }
+ else
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ newLCD[x / 8][y] |= ReverseBits(data);
+ }
+ }
+}
+
+void cDriverT6963C::Refresh(bool refreshAll)
+{
+ int x,y;
+ int addr = 0;
+
+ if (CheckSetup() == 1)
+ refreshAll = true;
+
+ if (config->refreshDisplay > 0)
+ {
+ refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
+ if (!refreshAll && !refreshCounter)
+ refreshAll = true;
+ }
+
+ port->Claim();
+ if (refreshAll)
+ {
+ // draw all
+ T6963CCommandWord(kSetAddressPointer, kGraphicBase);
+ if (useAutoMode)
+ {
+ T6963CCommand(kAutoWrite);
+ autoWrite = true;
+ }
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < (width + (FS - 1)) / FS; x++)
+ {
+ if (autoWrite)
+ T6963CData((newLCD[x][y]) ^ (config->invert ? 0xff : 0x00));
+ else
+ T6963CCommandByte(kDataWriteInc, (newLCD[x][y]) ^ (config->invert ? 0xff : 0x00));
+ oldLCD[x][y] = newLCD[x][y];
+ }
+ }
+ if (autoWrite)
+ {
+ T6963CCommand(kAutoReset);
+ autoWrite = false;
+ }
+ // and reset RefreshCounter
+ refreshCounter = 0;
+ }
+ else
+ {
+ // draw only the changed bytes
+
+ bool cs = false;
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < (width + (FS - 1)) / FS; x++)
+ {
+ if (oldLCD[x][y] != newLCD[x][y])
+ {
+ if (!cs)
+ {
+ if (width % FS == 0)
+ addr = (y * (width / FS)) + x;
+ else
+ addr = (y * (width / FS + 1)) + x;
+ T6963CCommandWord(kSetAddressPointer, kGraphicBase + addr);
+ if (useAutoMode)
+ {
+ T6963CCommand(kAutoWrite);
+ autoWrite = true;
+ }
+ cs = true;
+ }
+ if (autoWrite)
+ T6963CData((newLCD[x][y]) ^ (config->invert ? 0xff : 0x00));
+ else
+ T6963CCommandByte(kDataWriteInc, (newLCD[x][y]) ^ (config->invert ? 0xff : 0x00));
+ oldLCD[x][y] = newLCD[x][y];
+ }
+ else
+ {
+ if (autoWrite)
+ {
+ T6963CCommand(kAutoReset);
+ autoWrite = false;
+ }
+ cs = false;
+ }
+ }
+ }
+ if (autoWrite)
+ {
+ T6963CCommand(kAutoReset);
+ autoWrite = false;
+ }
+ }
+ port->Release();
+}
+
+void cDriverT6963C::T6963CSetControl(unsigned char flags)
+{
+ unsigned char status = port->ReadControl();
+ status &= 0xF0; // mask 4 bits
+ status |= flags; // add new flags
+ port->WriteControl(status);
+}
+
+void cDriverT6963C::T6963CDSPReady()
+{
+ int input = 0;
+
+ port->SetDirection(kReverse);
+ if (bidirectLPT == 1)
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI);
+ T6963CSetControl(WRHI | CELO | CDHI | RDLO);
+ input = port->ReadData();
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI);
+ if (!autoWrite && (input & 3) == 3)
+ break;
+ if (autoWrite && (input & 8) == 8)
+ break;
+ }
+ }
+ else
+ {
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI);
+ T6963CSetControl(WRHI | CELO | CDHI | RDLO);
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI);
+ }
+ port->SetDirection(kForward);
+}
+
+void cDriverT6963C::T6963CData(unsigned char data)
+{
+ if (serial)
+ {
+ T6963CSetControl(WRLO | CEHI | CDLO | RDLO);
+ for (int i = 128; i; i>>=1)
+ {
+ if (data & i)
+ {
+ T6963CSetControl(WRLO | CEHI | CDHI | RDLO);
+ T6963CSetControl(WRHI | CEHI | CDHI | RDLO);
+ }
+ else
+ {
+ T6963CSetControl(WRLO | CEHI | CDLO | RDLO);
+ T6963CSetControl(WRHI | CEHI | CDLO | RDLO);
+ }
+ }
+ T6963CSetControl(WRLO | CEHI | CDLO | RDLO); // CD down (data)
+ T6963CSetControl(WRLO | CELO | CDLO | RDLO); // CE down
+ T6963CSetControl(WRLO | CEHI | CDLO | RDLO); // CE up
+ }
+ else
+ {
+ if (useStatusCheck)
+ T6963CDSPReady();
+ T6963CSetControl(WRHI | CEHI | CDLO | RDHI); // CD down (data)
+ T6963CSetControl(WRLO | CELO | CDLO | RDHI); // CE & WR down
+ port->WriteData(data);
+ T6963CSetControl(WRHI | CEHI | CDLO | RDHI); // CE & WR up again
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI); // CD up again
+ }
+}
+
+void cDriverT6963C::T6963CCommand(unsigned char cmd)
+{
+ if (serial)
+ {
+ syslog(LOG_DEBUG, "Serial cmd out: ");
+ T6963CSetControl(WRLO | CEHI | CDLO | RDLO);
+ for (int i = 128; i; i>>=1)
+ {
+ if (cmd & i)
+ {
+ T6963CSetControl(WRLO | CEHI | CDHI | RDLO);
+ T6963CSetControl(WRHI | CEHI | CDHI | RDLO);
+ }
+ else
+ {
+ T6963CSetControl(WRLO | CEHI | CDLO | RDLO);
+ T6963CSetControl(WRHI | CEHI | CDLO | RDLO);
+ }
+ }
+ T6963CSetControl(WRLO | CEHI | CDHI | RDLO); // CD up (command)
+ T6963CSetControl(WRLO | CELO | CDHI | RDLO); // CE down
+ T6963CSetControl(WRLO | CEHI | CDHI | RDLO); // CE up
+ T6963CSetControl(WRLO | CEHI | CDLO | RDLO); // CD down
+ }
+ else
+ {
+ if (useStatusCheck)
+ T6963CDSPReady();
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI); // CD up (command)
+ T6963CSetControl(WRLO | CELO | CDHI | RDHI); // CE & WR down
+ port->WriteData(cmd);
+ T6963CSetControl(WRHI | CEHI | CDHI | RDHI); // CE & WR up again
+ T6963CSetControl(WRHI | CEHI | CDLO | RDHI); // CD down again
+ }
+}
+
+void cDriverT6963C::T6963CCommandByte(unsigned char cmd, unsigned char data)
+{
+ T6963CData(data);
+ T6963CCommand(cmd);
+}
+
+void cDriverT6963C::T6963CCommand2Bytes(unsigned char cmd, unsigned char data1, unsigned char data2)
+{
+ T6963CData(data1);
+ T6963CData(data2);
+ T6963CCommand(cmd);
+}
+
+void cDriverT6963C::T6963CCommandWord(unsigned char cmd, unsigned short data)
+{
+ T6963CData(data % 256);
+ T6963CData(data >> 8);
+ T6963CCommand(cmd);
+}
+
+void cDriverT6963C::T6963CDisplayMode(unsigned char mode, bool enable)
+{
+ if (enable)
+ displayMode |= mode;
+ else
+ displayMode &= ~mode;
+ T6963CCommand(kSetDisplayMode | displayMode);
+}
+
+}
diff --git a/glcddrivers/t6963c.h b/glcddrivers/t6963c.h
new file mode 100644
index 0000000..88be16b
--- /dev/null
+++ b/glcddrivers/t6963c.h
@@ -0,0 +1,76 @@
+/*
+ * GraphLCD driver library
+ *
+ * t6963c.h - T6963C driver class
+ *
+ * low level routines based on lcdproc 0.5 driver, (c) 2001 Manuel Stahl
+ *
+ * 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>
+ */
+
+#ifndef _GLCDDRIVERS_T6963C_H_
+#define _GLCDDRIVERS_T6963C_H_
+
+#include "driver.h"
+
+namespace GLCD
+{
+
+class cDriverConfig;
+class cParallelPort;
+
+class cDriverT6963C : public cDriver
+{
+private:
+ cParallelPort * port;
+ unsigned char ** newLCD; // wanted state
+ unsigned char ** oldLCD; // current state
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ int refreshCounter;
+ int bidirectLPT;
+ int displayMode;
+ bool useAutoMode;
+ bool useStatusCheck;
+
+ int serial;
+ int FS;
+ int WRHI;
+ int WRLO;
+ int RDHI;
+ int RDLO;
+ int CEHI;
+ int CELO;
+ int CDHI;
+ int CDLO;
+ bool autoWrite;
+
+ void T6963CSetControl(unsigned char flags);
+ void T6963CDSPReady();
+ void T6963CData(unsigned char data);
+ void T6963CCommand(unsigned char cmd);
+ void T6963CCommandByte(unsigned char cmd, unsigned char data);
+ void T6963CCommand2Bytes(unsigned char cmd, unsigned char data1, unsigned char data2);
+ void T6963CCommandWord(unsigned char cmd, unsigned short data);
+ void T6963CDisplayMode(unsigned char mode, bool enable);
+
+ int CheckSetup();
+
+public:
+ cDriverT6963C(cDriverConfig * config);
+ virtual ~cDriverT6963C();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ virtual void Set8Pixels(int x, int y, unsigned char data);
+ virtual void Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif