/* * GraphLCD driver library * * usbserlcd.c - USBserLCD driver class * * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * * (c) 2017 Manuel Reimer */ #include #include #include #include "common.h" #include "config.h" #include "port.h" #include "usbserlcd.h" #include "stdint.h" namespace GLCD { cDriverUSBserLCD::cDriverUSBserLCD(cDriverConfig * config) : cDriver(config) { port = new cSerialPort(); refreshCounter = 0; FS = 8; brightness = 255; } cDriverUSBserLCD::~cDriverUSBserLCD() { delete port; } int cDriverUSBserLCD::Init() { width = config->width; if (width <= 0) width = 240; height = config->height; if (height <= 0) height = 128; // setup lcd array (wanted state) newLCD = new unsigned char*[(width + (FS - 1)) / FS]; if (newLCD) { for (int 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 (int x = 0; x < (width + (FS - 1)) / FS; x++) { oldLCD[x] = new unsigned char[height]; memset(oldLCD[x], 0, height); } } if (config->device == "") return -1; if (port->Open(config->device.c_str()) != 0) return -1; port->SetBaudRate(150000); *oldConfig = *config; // clear display Clear(); syslog(LOG_INFO, "%s: USBserLCD initialized.\n", config->name.c_str()); return 0; } int cDriverUSBserLCD::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 cDriverUSBserLCD::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 cDriverUSBserLCD::Clear() { for (int x = 0; x < (width + (FS - 1)) / FS; x++) memset(newLCD[x], 0, height); } void cDriverUSBserLCD::SetPixel(int x, int y, uint32_t data) { if (x >= width || y >= height) return; int pos = x % 8; if (config->upsideDown) { x = width - 1 - x; y = height - 1 - y; } else { pos = 7 - pos; // reverse bit position } if (data == GRAPHLCD_White) newLCD[x / 8][y] |= (1 << pos); else newLCD[x / 8][y] &= ( 0xFF ^ (1 << pos) ); } void cDriverUSBserLCD::Refresh(bool refreshAll) { int x,y; uint16_t addr = 0; uint16_t len = 0; if (CheckSetup() == 1) refreshAll = true; if (config->refreshDisplay > 0) { refreshCounter = (refreshCounter + 1) % config->refreshDisplay; if (!refreshAll && !refreshCounter) refreshAll = true; } // draw all std::string full_seq = "GLCD"; full_seq.reserve(8500); full_seq += PKGTYPE_DATA; // Have to do it this way to get the NULL added full_seq.append((char*)&addr, 2); std::string bytes = ""; for (y = 0; y < height; y++) { for (x = 0; x < (width + (FS - 1)) / FS; x++) { char byte = (newLCD[x][y]) ^ (config->invert ? 0xff : 0x00); bytes.append(&byte, 1); if (refreshAll) oldLCD[x][y] = newLCD[x][y]; } } len = bytes.length(); full_seq.append((char*)&len, 2); full_seq.append(bytes); // and reset RefreshCounter refreshCounter = 0; if (refreshAll) { port->WriteData(full_seq); return; } // draw only the changed bytes std::string part_seq = ""; part_seq.reserve(8500); std::string block_seq = "GLCD"; block_seq.reserve(8500); block_seq += PKGTYPE_DATA; bool cs = false; bytes = ""; 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; block_seq = "GLCD"; block_seq += PKGTYPE_DATA; block_seq.append((char*)&addr, 2); bytes = ""; len = 0; cs = true; } char byte = (newLCD[x][y]) ^ (config->invert ? 0xff : 0x00); bytes.append(&byte, 1); oldLCD[x][y] = newLCD[x][y]; } else if (bytes != "") { part_seq.append(block_seq); len = bytes.length(); part_seq.append((char*)&len, 2); part_seq.append(bytes); cs = false; bytes = ""; block_seq = ""; } } } if (bytes != "") { part_seq.append(block_seq); len = bytes.length(); part_seq.append((char*)&len, 2); part_seq.append(bytes); } // Send the smaller data block. if (part_seq.length() < full_seq.length()) port->WriteData(part_seq); else port->WriteData(full_seq); } void cDriverUSBserLCD::SetBrightness(unsigned int percent) { return; unsigned char brightness = 255 * percent / 100; std::string pkg = "GLCD" + PKGTYPE_BRIGHTNESS + brightness; port->WriteData(pkg); } }