graphlcd-base/glcddrivers/picctl.c
author cpresser@rika
Thu, 07 Feb 2008 12:41:15 +0000
changeset 20 23b8c749e5a0
parent 18 8cd4c128bd99
child 29 2723893dc865
permissions -rw-r--r--
glcddrivers: fixed input handling
     1 /*
     2  * GraphLCD driver library
     3  *
     4  * picctl.c  -  PIC controlled LCD driver class
     5  *
     6  * This file is released under the GNU General Public License. Refer
     7  * to the COPYING file distributed with this package.
     8  *
     9  * Codebase by Andreas Regel <andreas.regel AT powarman.de>
    10  * (c) 2007 Carsten Presser
    11  */
    12 
    13 #include <stdint.h>
    14 #include <syslog.h>
    15 #include <math.h>
    16 
    17 #include "common.h"
    18 #include "config.h"
    19 #include "port.h"
    20 #include "picctl.h"
    21 
    22 
    23 
    24 namespace GLCD
    25 {
    26 
    27 /* command header:
    28 **  8 bits  sync byte (0xAA for sent commands, 0x55 for received commands)
    29 **  8 bits  command id
    30 ** 16 bits  command length (excluding header)
    31 */
    32 const unsigned char CMD_HDR_SYNC    = 0;
    33 const unsigned char CMD_HDR_COMMAND = 1;
    34 const unsigned char CMD_HDR_LENGTH  = 2;
    35 const unsigned char CMD_DATA_START  = 4;
    36 
    37 const unsigned char CMD_SYNC_SEND   = 0xAA;
    38 const unsigned char CMD_SYNC_RECV   = 0x55;
    39 const unsigned char CMD_ESCAPE_BYTE = 0x42;
    40 
    41 
    42 const unsigned char CMD_SYS_SYNC =		0x00;
    43 const unsigned char CMD_SYS_ACK	=		0x01;
    44 const unsigned char CMD_SYS_NACK =		0x02;
    45 const unsigned char CMD_SYS_NIMP =		0xFF;
    46 const unsigned char CMD_SYS_IR =		0x10;
    47 
    48 const unsigned char CMD_DISP_CLEAR_SCREEN =	0x10;
    49 const unsigned char CMD_DISP_SET_ROW_DATA =  	0x14;
    50 const unsigned char CMD_DISP_SET_ADDRESS =	0x16;
    51 
    52 const unsigned char CMD_READ_CLOCK =		0x40;
    53 const unsigned char CMD_WRITE_CLOCK =		0x41;
    54 const unsigned char CMD_SET_PWM1 =		0x45;
    55 const unsigned char CMD_SET_PWM2 =		0x46;
    56 
    57 const unsigned char CMD_SET_MODE_MANAGED =	0x70;
    58 const unsigned char CMD_SET_MODE_UNMANAGED =	0x71;
    59 
    60 const unsigned char CMD_BOOT =			0x80;
    61 
    62 
    63 // globals...
    64 uint8_t cDriverPICCtl::buf[255];
    65 uint8_t cDriverPICCtl::buf_pos;
    66 uint8_t cDriverPICCtl::buf_cmd_start;
    67 bool cDriverPICCtl::buf_flag_escape;
    68 
    69 // singleton
    70 cDriverPICCtl* cDriverPICCtl::instance = 0;
    71 
    72 cDriverPICCtl* cDriverPICCtl::getInstance(cDriverConfig * config)
    73 {
    74     if (!instance)
    75         instance = new cDriverPICCtl(config);
    76     return instance;
    77 }
    78 // end singleton-pattern
    79 
    80 
    81 
    82 cDriverPICCtl::cDriverPICCtl(cDriverConfig * config)
    83 :   config(config)
    84 {
    85     oldConfig = new cDriverConfig(*config);
    86 
    87     port = new cSerialPort();
    88 
    89     //width = config->width;
    90     //height = config->height;
    91     refreshCounter = 0;
    92     ack_flag = false;
    93     
    94     buf_pos = 0;
    95     buf_cmd_start = 255;
    96     buf_flag_escape = false;
    97 }
    98 
    99 cDriverPICCtl::~cDriverPICCtl()
   100 {
   101     delete port;
   102     delete oldConfig;
   103 }
   104 
   105 void cDriverPICCtl::SignalHandler(int signal)
   106 {
   107     //uint8_t i;
   108 
   109     // read all available data
   110     while (instance->port->ReadData(&buf[buf_pos]) > 0)
   111     {
   112         // search for SYNC byte
   113         if ((buf[buf_pos] == CMD_SYNC_RECV) && (!buf_flag_escape))
   114 	{
   115 	    if (buf_cmd_start != 255)
   116 	    {
   117 		/*printf("Damaged Packet: ");
   118 	        for (i=buf_cmd_start; i<buf_pos; i++)
   119 		{
   120 		  printf("0x%02x ",buf[i]);
   121 		}
   122 		printf("; buf_pos = %d, buf_cmd_start = %d\n",buf_pos,buf_cmd_start);*/
   123 
   124                 syslog(LOG_INFO, "PICCtl received a malformed packet. Scrapped %d bytes\n",(buf_pos - buf_cmd_start));
   125 		buf_pos = 0;
   126 		buf[buf_pos] = CMD_SYNC_RECV;
   127 	    }
   128  	    buf_cmd_start = buf_pos;
   129 	}
   130 
   131 
   132         if ((buf[buf_pos] == CMD_ESCAPE_BYTE) && (!buf_flag_escape))
   133 	{
   134 	    // this byte was for masking only.. ignore it! 
   135 	    buf_flag_escape = true;
   136 	    continue;
   137 	} 
   138         buf_flag_escape = false;
   139 
   140 /*        printf("buf: ");
   141         for (i=1; i<=buf_pos; i++) { printf("0x%02x ",buf[i]);}
   142 	printf("\n");*/
   143         
   144 	buf_pos++;
   145 
   146         // we need to check for a valid packet...
   147 	if ((buf_pos - buf_cmd_start) >= CMD_DATA_START)
   148 	{
   149             // if we recieved a valid packet: start decoding
   150 	    if (buf[buf_cmd_start + CMD_HDR_LENGTH+1] == (buf_pos - buf_cmd_start - CMD_DATA_START))
   151 	    {
   152 	        instance->DecodeCmd(&buf[buf_cmd_start],buf_pos);
   153 		buf_pos = 0;
   154 		buf_cmd_start = 255;
   155 	    }
   156 	}
   157 
   158     }
   159 }
   160 
   161 
   162 void cDriverPICCtl::DecodeCmd(uint8_t * cmd, uint8_t len)
   163 {
   164 /*    uint8_t i;
   165     printf("cmd(%2d): ",len);
   166     for (i=0; i<len; i++) { printf("0x%02x ",cmd[i]);}
   167     printf("\n"); */
   168 
   169     switch (cmd[CMD_HDR_COMMAND])
   170     {
   171         case CMD_SYS_ACK:	ack_flag = true;
   172 	 			break;
   173 
   174 	case CMD_SYS_IR:	syslog(LOG_INFO," %s: incoming Key-Event 0x%02x (Source 0x%02x)\n",config->name.c_str(), cmd[CMD_DATA_START+1], cmd[CMD_DATA_START]);
   175 	                        printf(" %s: incoming Key-Event 0x%02x (Source 0x%02x)\n",config->name.c_str(), cmd[CMD_DATA_START+1], cmd[CMD_DATA_START]);
   176 	  			break;
   177 
   178 	default:		syslog(LOG_INFO," %s: recieved Message 0x%x \n",config->name.c_str(), cmd[CMD_HDR_COMMAND]);
   179     }
   180 
   181 
   182 }
   183 
   184 int cDriverPICCtl::Init()
   185 {
   186     int y;
   187 
   188     // fixed values so far...
   189     width = 240;
   190     height = 64;
   191 
   192     for (unsigned int i = 0; i < config->options.size(); i++)
   193     {
   194         if (config->options[i].name == "")
   195         {
   196         }
   197     }
   198 
   199     // setup lcd array (wanted state)
   200     newLCD = new unsigned char*[height];
   201     if (newLCD)
   202     {
   203         for (y = 0; y < height; y++)
   204         {
   205             newLCD[y] = new unsigned char[width/8];
   206             memset(newLCD[y], 0, (width/8));
   207         }
   208     }
   209     // setup lcd array (current state)
   210     oldLCD = new unsigned char*[height];
   211     if (oldLCD)
   212     {
   213         for (y = 0; y < height; y++)
   214         {
   215             oldLCD[y] = new unsigned char[width/8];
   216             memset(oldLCD[y], 0, (width/8));
   217         }
   218     }
   219 
   220     if (config->device == "")
   221     {
   222         return -1;
   223     }
   224     if (port->Open(config->device.c_str(), SignalHandler) != 0)
   225         return -1;
   226 
   227     *oldConfig = *config;
   228 
   229     // clear display
   230     Clear();
   231     CmdDispClearScreen();
   232     CmdDispSetManaged();
   233     CmdDispSetBrightness(0);
   234 
   235     syslog(LOG_INFO, "%s: PICCtl initialized.\n", config->name.c_str());
   236     return 0;
   237 }
   238 
   239 int cDriverPICCtl::DeInit()
   240 {
   241     int y;
   242     // free lcd array (wanted state)
   243     if (newLCD)
   244     {
   245         for (y = 0; y < height; y++)
   246         {
   247             delete[] newLCD[y];
   248         }
   249         delete[] newLCD;
   250     }
   251     // free lcd array (current state)
   252     if (oldLCD)
   253     {
   254         for (y = 0; y < height; y++)
   255         {
   256             delete[] oldLCD[y];
   257         }
   258         delete[] oldLCD;
   259     }
   260 
   261     CmdDispSetUnManaged();
   262     
   263     delete instance;
   264     instance = 0;
   265 
   266     if (port->Close() != 0)
   267         return -1;
   268     return 0;
   269 }
   270 
   271 int cDriverPICCtl::CheckSetup()
   272 {
   273     if (config->device != oldConfig->device ||
   274         config->width != oldConfig->width ||
   275         config->height != oldConfig->height)
   276     {
   277         DeInit();
   278         Init();
   279         return 0;
   280     }
   281 
   282     if (config->upsideDown != oldConfig->upsideDown ||
   283         config->invert != oldConfig->invert)
   284     {
   285         oldConfig->upsideDown = config->upsideDown;
   286         oldConfig->invert = config->invert;
   287         return 1;
   288     }
   289     return 0;
   290 }
   291 
   292 void cDriverPICCtl::Clear()
   293 {
   294     for (int y = 0; y < height; y++)
   295         memset(newLCD[y], 0, (width/8));
   296 }
   297 
   298 void cDriverPICCtl::Set8Pixels(int x, int y, unsigned char data)
   299 {
   300     if (x >= width || y >= height)
   301         return;
   302 
   303     if (!config->upsideDown)
   304     {
   305         newLCD[y][x/8] = data;
   306     }
   307     else
   308     {
   309         x = width - 1 - x;
   310         y = height - 1 - y;
   311         newLCD[y][x / 8] |= ReverseBits(data);
   312     }
   313 }
   314 
   315 void cDriverPICCtl::Refresh(bool refreshAll)
   316 {
   317     int y;
   318 
   319     if (CheckSetup() == 1)
   320         refreshAll = true;
   321 
   322     if (config->refreshDisplay > 0)
   323     {
   324         refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
   325         if (!refreshAll && !refreshCounter)
   326             refreshAll = true;
   327     }
   328 
   329 
   330     if (refreshAll)
   331     {
   332         // draw all
   333         // always draw a complete row! (30 bytes!)
   334         for (y = 0; y < height; y++)
   335         {
   336             CmdDispSetColData(y, 0, (width/8), newLCD[y]);
   337             memcpy(oldLCD[y], newLCD[y], (width/8));
   338         }
   339         // and reset RefreshCounter
   340         refreshCounter = 0;
   341     }
   342     else
   343     {
   344 	// for every line
   345 	for (y = 0; y< height; y++)
   346         {
   347             // did anysthing change? -> draw new line
   348 	    if (memcmp(newLCD[y],oldLCD[y],(width/8)) != 0)
   349             {
   350                  CmdDispSetColData(y, 0, (width/8), newLCD[y]);
   351                  memcpy(oldLCD[y], newLCD[y], (width/8));
   352             }
   353         }
   354     }
   355 }
   356 
   357 void cDriverPICCtl::SetBrightness(unsigned int percent)
   358 {
   359     CmdDispSetBrightness(percent);
   360 }
   361 
   362 void cDriverPICCtl::SetClock(unsigned int percent)
   363 {
   364     CmdDispSetBrightness(percent);
   365 }
   366 
   367 int cDriverPICCtl::WaitForAck(void)
   368 {
   369     int timeout;
   370 
   371     for (timeout=0; timeout<10000; timeout++)
   372     {
   373     	usleep(10);
   374 	if (ack_flag) return 1;
   375     }
   376     syslog(LOG_INFO, "PICCtl: missed a ACK packet!.\n");
   377     return 0;
   378 }
   379 
   380 void cDriverPICCtl::CmdDispClearScreen(void)
   381 {
   382     uint8_t cmd[4];
   383 
   384     cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
   385     cmd[CMD_HDR_COMMAND] = CMD_DISP_CLEAR_SCREEN;
   386     cmd[CMD_HDR_LENGTH] = 0;
   387     cmd[CMD_HDR_LENGTH+1] = 0;
   388 
   389     port->WriteData(cmd, 4);
   390     WaitForAck();
   391 }
   392 
   393 void cDriverPICCtl::CmdDispSetBrightness(uint8_t percent)
   394 {
   395     uint8_t cmd[5];
   396 
   397     cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
   398     cmd[CMD_HDR_COMMAND] = CMD_SET_PWM1;
   399     cmd[CMD_HDR_LENGTH] = 0;
   400     cmd[CMD_HDR_LENGTH+1] = 1;
   401     cmd[CMD_DATA_START] = (uint8_t) round(percent * 2.55);
   402 
   403     port->WriteData(cmd, 5);
   404     WaitForAck();
   405 }
   406 
   407 void cDriverPICCtl::CmdDispSetColData(uint8_t yoffset, uint8_t xoffset, uint8_t length, uint8_t * data)
   408 {
   409     uint8_t cmd[64];
   410     uint16_t address;
   411 
   412     address = 0x1E * yoffset + xoffset;
   413 
   414     cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
   415     cmd[CMD_HDR_COMMAND] = CMD_DISP_SET_ROW_DATA;
   416     cmd[CMD_HDR_LENGTH] = 0;
   417     cmd[CMD_HDR_LENGTH+1] = (length + 2);
   418     cmd[CMD_DATA_START] = (uint8_t)(address % 256);	// lower address
   419     cmd[CMD_DATA_START+1] = (uint8_t)(address / 256);	// upper address
   420     memcpy(&cmd[CMD_DATA_START+2], data, length);
   421 
   422     port->WriteData(cmd, length + 6);
   423     WaitForAck();
   424 
   425 //    for (address = 0; address < length+6; address ++) printf("0x%02x ",cmd[address]);
   426 //  printf("address=0x%x upper=0x%x lower=0x%x \n", address, (uint8_t)(address / 256), (uint8_t)(address % 256));
   427 //    printf("\n");
   428 }
   429 
   430 void cDriverPICCtl::CmdDispSetManaged(void)
   431 {
   432     uint8_t cmd[4];
   433 
   434     cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
   435     cmd[CMD_HDR_COMMAND] = CMD_SET_MODE_MANAGED;
   436     cmd[CMD_HDR_LENGTH] = 0;
   437     cmd[CMD_HDR_LENGTH+1] = 0;
   438 
   439     port->WriteData(cmd,4);
   440     WaitForAck();
   441 }
   442 
   443 void cDriverPICCtl::CmdDispSetUnManaged(void)
   444 {
   445     uint8_t cmd[4];
   446 
   447     cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
   448     cmd[CMD_HDR_COMMAND] = CMD_SET_MODE_UNMANAGED;
   449     cmd[CMD_HDR_LENGTH] = 0;
   450     cmd[CMD_HDR_LENGTH+1] = 0;
   451 
   452     port->WriteData(cmd,4);
   453     WaitForAck();
   454 }
   455 
   456 
   457 } // end NameSpace