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/t6963c.c | |
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/t6963c.c')
-rw-r--r-- | glcddrivers/t6963c.c | 678 |
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); +} + +} |