diff options
author | andreas 'randy' weinberger <vdr@smue.org> | 2010-02-21 19:58:27 +0100 |
---|---|---|
committer | andreas 'randy' weinberger <vdr@smue.org> | 2010-02-21 19:58:27 +0100 |
commit | 10ab31fa86dbf9875b5f6baa6ac59fefaaf86be3 (patch) | |
tree | 60ad7c856565f03e145b2996d1bb5f9cd64c0532 /glcddrivers | |
download | graphlcd-base-10ab31fa86dbf9875b5f6baa6ac59fefaaf86be3.tar.gz graphlcd-base-10ab31fa86dbf9875b5f6baa6ac59fefaaf86be3.tar.bz2 |
initial git upload, based on graphlcd-base-0.1.5
Diffstat (limited to 'glcddrivers')
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, ¶m); + 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, ¶m); + 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 |