summaryrefslogtreecommitdiff
path: root/glcddrivers/sed1520.c
diff options
context:
space:
mode:
Diffstat (limited to 'glcddrivers/sed1520.c')
-rw-r--r--glcddrivers/sed1520.c402
1 files changed, 402 insertions, 0 deletions
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