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