root@5: /* root@5: * GraphLCD driver library root@5: * root@5: * picctl.c - PIC controlled LCD driver class root@5: * root@5: * This file is released under the GNU General Public License. Refer root@5: * to the COPYING file distributed with this package. root@5: * root@5: * Codebase by Andreas Regel root@5: * (c) 2007 Carsten Presser root@5: */ root@5: root@5: #include root@5: #include root@5: #include root@30: #include root@5: root@5: #include "common.h" root@5: #include "config.h" root@5: #include "port.h" root@5: #include "picctl.h" root@5: root@5: root@5: root@5: namespace GLCD root@5: { root@5: root@5: /* command header: root@5: ** 8 bits sync byte (0xAA for sent commands, 0x55 for received commands) root@5: ** 8 bits command id root@5: ** 16 bits command length (excluding header) root@5: */ root@5: const unsigned char CMD_HDR_SYNC = 0; root@5: const unsigned char CMD_HDR_COMMAND = 1; root@5: const unsigned char CMD_HDR_LENGTH = 2; root@5: const unsigned char CMD_DATA_START = 4; root@5: cpresser@8: const unsigned char CMD_SYNC_SEND = 0xAA; cpresser@8: const unsigned char CMD_SYNC_RECV = 0x55; cpresser@8: const unsigned char CMD_ESCAPE_BYTE = 0x42; root@5: root@5: root@5: const unsigned char CMD_SYS_SYNC = 0x00; root@5: const unsigned char CMD_SYS_ACK = 0x01; root@5: const unsigned char CMD_SYS_NACK = 0x02; root@5: const unsigned char CMD_SYS_NIMP = 0xFF; root@5: const unsigned char CMD_SYS_IR = 0x10; root@5: root@5: const unsigned char CMD_DISP_CLEAR_SCREEN = 0x10; root@5: const unsigned char CMD_DISP_SET_ROW_DATA = 0x14; root@5: const unsigned char CMD_DISP_SET_ADDRESS = 0x16; root@5: root@5: const unsigned char CMD_READ_CLOCK = 0x40; root@5: const unsigned char CMD_WRITE_CLOCK = 0x41; root@5: const unsigned char CMD_SET_PWM1 = 0x45; root@5: const unsigned char CMD_SET_PWM2 = 0x46; root@5: root@5: const unsigned char CMD_SET_MODE_MANAGED = 0x70; root@5: const unsigned char CMD_SET_MODE_UNMANAGED = 0x71; root@5: root@5: const unsigned char CMD_BOOT = 0x80; cpresser@8: cpresser@8: root@5: cDriverPICCtl::cDriverPICCtl(cDriverConfig * config) root@5: : config(config) root@5: { root@5: oldConfig = new cDriverConfig(*config); root@5: root@5: port = new cSerialPort(); root@5: test@29: width = config->width; test@29: height = config->height; test@29: root@5: refreshCounter = 0; root@5: ack_flag = false; cpresser@10: cpresser@15: buf_pos = 0; cpresser@10: buf_cmd_start = 255; cpresser@10: buf_flag_escape = false; root@30: root@30: keys_pos = 0; root@30: keys_pos_ = 0; root@5: } root@5: root@5: cDriverPICCtl::~cDriverPICCtl() root@5: { root@5: delete port; test@29: port = NULL; root@5: delete oldConfig; test@29: oldConfig = NULL; root@5: } root@5: root@30: bool cDriverPICCtl::HasKeys() root@30: { root@30: return true; root@30: } root@30: root@30: int cDriverPICCtl::GetKey() root@30: { root@30: InputHandler(); root@30: root@30: if (keys_pos != keys_pos_) root@30: { root@30: keys_pos_ = keys_pos; root@30: return(keys[keys_pos-1]); root@30: } root@30: else root@30: { root@30: return(-1); root@30: } root@30: root@30: } root@30: root@30: void cDriverPICCtl::InputHandler() root@30: { test@29: // read all available data (always get single bytes...) root@30: while (port->ReadData(&buf[buf_pos]) > 0) cpresser@8: { cpresser@10: // search for SYNC byte cpresser@8: if ((buf[buf_pos] == CMD_SYNC_RECV) && (!buf_flag_escape)) root@5: { cpresser@8: if (buf_cmd_start != 255) cpresser@8: { root@30: #ifdef DEBUG root@30: uint8_t i; root@30: printf("Damaged Packet: "); cpresser@20: for (i=buf_cmd_start; i= CMD_DATA_START) cpresser@8: { cpresser@8: // if we recieved a valid packet: start decoding cpresser@20: if (buf[buf_cmd_start + CMD_HDR_LENGTH+1] == (buf_pos - buf_cmd_start - CMD_DATA_START)) cpresser@8: { root@30: DecodeCmd(&buf[buf_cmd_start],buf_pos); cpresser@8: buf_pos = 0; cpresser@15: buf_cmd_start = 255; cpresser@8: } cpresser@8: } cpresser@8: cpresser@8: } cpresser@8: } cpresser@8: cpresser@8: void cDriverPICCtl::DecodeCmd(uint8_t * cmd, uint8_t len) cpresser@8: { root@30: #ifdef DEBUG root@30: uint8_t i; cpresser@14: printf("cmd(%2d): ",len); cpresser@14: for (i=0; iname.c_str(), cmd[CMD_DATA_START+1]); root@30: #endif root@5: break; root@5: cpresser@18: default: syslog(LOG_INFO," %s: recieved Message 0x%x \n",config->name.c_str(), cmd[CMD_HDR_COMMAND]); root@5: } root@5: cpresser@14: root@5: } root@5: root@5: int cDriverPICCtl::Init() root@5: { root@5: int y; root@5: root@5: // fixed values so far... root@5: width = 240; root@5: height = 64; root@5: root@5: for (unsigned int i = 0; i < config->options.size(); i++) root@5: { root@5: if (config->options[i].name == "") root@5: { root@5: } root@5: } root@5: root@5: // setup lcd array (wanted state) root@5: newLCD = new unsigned char*[height]; root@5: if (newLCD) root@5: { root@5: for (y = 0; y < height; y++) root@5: { root@5: newLCD[y] = new unsigned char[width/8]; root@5: memset(newLCD[y], 0, (width/8)); root@5: } root@5: } root@5: // setup lcd array (current state) root@5: oldLCD = new unsigned char*[height]; root@5: if (oldLCD) root@5: { root@5: for (y = 0; y < height; y++) root@5: { root@5: oldLCD[y] = new unsigned char[width/8]; root@5: memset(oldLCD[y], 0, (width/8)); root@5: } root@5: } root@5: root@5: if (config->device == "") root@5: { root@5: return -1; root@5: } root@30: if (port->Open(config->device.c_str()) != 0) root@5: return -1; root@5: root@5: *oldConfig = *config; root@5: root@5: // clear display root@5: Clear(); root@5: CmdDispClearScreen(); root@5: CmdDispSetManaged(); root@5: root@5: syslog(LOG_INFO, "%s: PICCtl initialized.\n", config->name.c_str()); root@5: return 0; root@5: } root@5: root@5: int cDriverPICCtl::DeInit() root@5: { root@5: int y; root@30: root@30: CmdDispSetUnManaged(); root@30: CmdDispClearScreen(); root@30: root@5: // free lcd array (wanted state) root@5: if (newLCD) root@5: { root@5: for (y = 0; y < height; y++) root@5: { root@5: delete[] newLCD[y]; root@5: } root@5: delete[] newLCD; root@5: } root@5: // free lcd array (current state) root@5: if (oldLCD) root@5: { root@5: for (y = 0; y < height; y++) root@5: { root@5: delete[] oldLCD[y]; root@5: } root@5: delete[] oldLCD; root@5: } root@5: root@5: root@5: if (port->Close() != 0) root@5: return -1; test@29: root@5: return 0; root@5: } root@5: root@5: int cDriverPICCtl::CheckSetup() root@5: { root@5: if (config->device != oldConfig->device || root@5: config->width != oldConfig->width || root@5: config->height != oldConfig->height) root@5: { root@5: DeInit(); root@5: Init(); root@5: return 0; root@5: } root@5: root@5: if (config->upsideDown != oldConfig->upsideDown || root@5: config->invert != oldConfig->invert) root@5: { root@5: oldConfig->upsideDown = config->upsideDown; root@5: oldConfig->invert = config->invert; root@5: return 1; root@5: } root@5: return 0; root@5: } root@5: root@5: void cDriverPICCtl::Clear() root@5: { root@5: for (int y = 0; y < height; y++) root@5: memset(newLCD[y], 0, (width/8)); root@5: } root@5: root@5: void cDriverPICCtl::Set8Pixels(int x, int y, unsigned char data) root@5: { root@5: if (x >= width || y >= height) root@5: return; root@5: root@5: if (!config->upsideDown) root@5: { root@5: newLCD[y][x/8] = data; root@5: } root@5: else root@5: { root@5: x = width - 1 - x; root@5: y = height - 1 - y; root@5: newLCD[y][x / 8] |= ReverseBits(data); root@5: } root@5: } root@5: root@5: void cDriverPICCtl::Refresh(bool refreshAll) root@5: { root@5: int y; root@5: root@5: if (CheckSetup() == 1) root@5: refreshAll = true; root@5: root@5: if (config->refreshDisplay > 0) root@5: { root@5: refreshCounter = (refreshCounter + 1) % config->refreshDisplay; root@5: if (!refreshAll && !refreshCounter) root@5: refreshAll = true; root@5: } root@5: root@5: root@5: if (refreshAll) root@5: { root@5: // draw all root@5: // always draw a complete row! (30 bytes!) root@5: for (y = 0; y < height; y++) root@5: { root@5: CmdDispSetColData(y, 0, (width/8), newLCD[y]); root@5: memcpy(oldLCD[y], newLCD[y], (width/8)); root@5: } root@5: // and reset RefreshCounter root@5: refreshCounter = 0; root@5: } root@5: else root@5: { root@5: // for every line root@5: for (y = 0; y< height; y++) root@5: { root@5: // did anysthing change? -> draw new line root@5: if (memcmp(newLCD[y],oldLCD[y],(width/8)) != 0) root@5: { root@5: CmdDispSetColData(y, 0, (width/8), newLCD[y]); root@5: memcpy(oldLCD[y], newLCD[y], (width/8)); root@5: } root@5: } root@5: } root@5: } root@5: root@5: void cDriverPICCtl::SetBrightness(unsigned int percent) root@5: { root@5: CmdDispSetBrightness(percent); root@5: } root@5: root@5: int cDriverPICCtl::WaitForAck(void) root@5: { root@5: int timeout; root@5: test@29: for (timeout=0; timeout<1000; timeout++) test@29: { root@30: InputHandler(); test@29: usleep(100); test@29: if (ack_flag) return 0; test@29: } test@29: syslog(LOG_INFO, "%s: PICCtl missed a ACK packet!\n", config->name.c_str()); root@30: root@30: root@30: #ifdef DEBUG root@30: int i; root@30: printf("%s: PICCtl missed a ACK packet!\n", config->name.c_str()); root@30: for (i=0; iWriteData(cmd, 4); root@5: WaitForAck(); root@5: } root@5: root@5: void cDriverPICCtl::CmdDispSetBrightness(uint8_t percent) root@5: { root@5: uint8_t cmd[5]; root@5: root@5: cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND; root@5: cmd[CMD_HDR_COMMAND] = CMD_SET_PWM1; root@5: cmd[CMD_HDR_LENGTH] = 0; root@5: cmd[CMD_HDR_LENGTH+1] = 1; root@5: cmd[CMD_DATA_START] = (uint8_t) round(percent * 2.55); root@5: test@29: ack_flag = false; root@5: port->WriteData(cmd, 5); root@5: WaitForAck(); root@5: } root@5: root@5: void cDriverPICCtl::CmdDispSetColData(uint8_t yoffset, uint8_t xoffset, uint8_t length, uint8_t * data) root@5: { root@5: uint8_t cmd[64]; root@5: uint16_t address; root@5: root@5: address = 0x1E * yoffset + xoffset; root@5: root@5: cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND; root@5: cmd[CMD_HDR_COMMAND] = CMD_DISP_SET_ROW_DATA; root@5: cmd[CMD_HDR_LENGTH] = 0; root@5: cmd[CMD_HDR_LENGTH+1] = (length + 2); root@5: cmd[CMD_DATA_START] = (uint8_t)(address % 256); // lower address root@5: cmd[CMD_DATA_START+1] = (uint8_t)(address / 256); // upper address root@5: memcpy(&cmd[CMD_DATA_START+2], data, length); root@5: test@29: ack_flag = false; root@5: port->WriteData(cmd, length + 6); root@5: WaitForAck(); root@5: root@5: // for (address = 0; address < length+6; address ++) printf("0x%02x ",cmd[address]); root@5: // printf("address=0x%x upper=0x%x lower=0x%x \n", address, (uint8_t)(address / 256), (uint8_t)(address % 256)); root@5: // printf("\n"); root@5: } root@5: root@5: void cDriverPICCtl::CmdDispSetManaged(void) root@5: { root@5: uint8_t cmd[4]; root@5: root@5: cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND; root@5: cmd[CMD_HDR_COMMAND] = CMD_SET_MODE_MANAGED; root@5: cmd[CMD_HDR_LENGTH] = 0; root@5: cmd[CMD_HDR_LENGTH+1] = 0; root@5: test@29: ack_flag = false; root@5: port->WriteData(cmd,4); root@5: WaitForAck(); root@5: } root@5: root@5: void cDriverPICCtl::CmdDispSetUnManaged(void) root@5: { root@5: uint8_t cmd[4]; root@5: root@5: cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND; root@5: cmd[CMD_HDR_COMMAND] = CMD_SET_MODE_UNMANAGED; root@5: cmd[CMD_HDR_LENGTH] = 0; root@5: cmd[CMD_HDR_LENGTH+1] = 0; root@5: root@5: port->WriteData(cmd,4); root@5: WaitForAck(); root@5: } root@5: root@5: root@5: } // end NameSpace