diff options
Diffstat (limited to 'glcddrivers/ks0108.c')
-rw-r--r-- | glcddrivers/ks0108.c | 593 |
1 files changed, 593 insertions, 0 deletions
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 |