summaryrefslogtreecommitdiff
path: root/glcddrivers/t6963c.c
diff options
context:
space:
mode:
authorandreas 'randy' weinberger <vdr@smue.org>2010-02-21 19:58:27 +0100
committerandreas 'randy' weinberger <vdr@smue.org>2010-02-21 19:58:27 +0100
commit10ab31fa86dbf9875b5f6baa6ac59fefaaf86be3 (patch)
tree60ad7c856565f03e145b2996d1bb5f9cd64c0532 /glcddrivers/t6963c.c
downloadgraphlcd-base-10ab31fa86dbf9875b5f6baa6ac59fefaaf86be3.tar.gz
graphlcd-base-10ab31fa86dbf9875b5f6baa6ac59fefaaf86be3.tar.bz2
initial git upload, based on graphlcd-base-0.1.5
Diffstat (limited to 'glcddrivers/t6963c.c')
-rw-r--r--glcddrivers/t6963c.c678
1 files changed, 678 insertions, 0 deletions
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);
+}
+
+}