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