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