graphlcd-base/glcddrivers/picctl.c
author cpresser@rika
Thu, 07 Feb 2008 11:42:36 +0000
changeset 15 cba463042186
parent 14 ccaf76b245ec
child 16 5bf89d28ba80
permissions -rw-r--r--
glcddrivers: made port non-blocking, fixed input-code
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
root@5
    70
cDriverPICCtl* cDriverPICCtl::instance = 0;
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
root@5
    89
    //width = config->width;
root@5
    90
    //height = config->height;
root@5
    91
    refreshCounter = 0;
root@5
    92
    ack_flag = false;
cpresser@10
    93
    
cpresser@15
    94
    buf_pos = 0;
cpresser@10
    95
    buf_cmd_start = 255;
cpresser@10
    96
    buf_flag_escape = false;
root@5
    97
}
root@5
    98
root@5
    99
cDriverPICCtl::~cDriverPICCtl()
root@5
   100
{
root@5
   101
    delete port;
root@5
   102
    delete oldConfig;
root@5
   103
}
root@5
   104
root@5
   105
void cDriverPICCtl::SignalHandler(int signal)
root@5
   106
{
cpresser@15
   107
//    uint8_t i;
cpresser@14
   108
cpresser@8
   109
    // read all available data
cpresser@15
   110
    while (instance->port->ReadData(&buf[buf_pos]) > 0)
cpresser@8
   111
    {
cpresser@10
   112
        // search for SYNC byte
cpresser@8
   113
        if ((buf[buf_pos] == CMD_SYNC_RECV) && (!buf_flag_escape))
root@5
   114
	{
cpresser@8
   115
	    if (buf_cmd_start != 255)
cpresser@8
   116
	    {
cpresser@8
   117
	        // bytes = buf_cmd_start - buf_pos
cpresser@8
   118
                syslog(LOG_INFO, "PICCtl received a malformed packet. Scrapped xxx bytes\n");
cpresser@8
   119
		buf_pos = 0;
cpresser@8
   120
		buf[buf_pos] = CMD_SYNC_RECV;
cpresser@8
   121
	    }
cpresser@8
   122
 	    buf_cmd_start = buf_pos;
cpresser@8
   123
	}
cpresser@8
   124
cpresser@8
   125
cpresser@8
   126
        if ((buf[buf_pos] == CMD_ESCAPE_BYTE) && (!buf_flag_escape))
cpresser@8
   127
	{
cpresser@14
   128
	    // this byte was for masking only.. ignore it! 
cpresser@8
   129
	    buf_flag_escape = true;
cpresser@14
   130
	    continue;
cpresser@8
   131
	} 
cpresser@14
   132
        buf_flag_escape = false;
cpresser@14
   133
cpresser@14
   134
/*        printf("buf: ");
cpresser@14
   135
        for (i=1; i<=buf_pos; i++) { printf("0x%02x ",buf[i]);}
cpresser@14
   136
	printf("\n");*/
cpresser@15
   137
        
cpresser@15
   138
	buf_pos++;
cpresser@8
   139
cpresser@8
   140
        // we need to check for a valid packet...
cpresser@15
   141
	if (buf_pos >= CMD_DATA_START)
cpresser@8
   142
	{
cpresser@8
   143
            // if we recieved a valid packet: start decoding
cpresser@8
   144
	    if (buf[CMD_HDR_LENGTH+1] == (buf_pos - CMD_DATA_START))
cpresser@8
   145
	    {
cpresser@15
   146
	        instance->DecodeCmd(&buf[buf_cmd_start],buf_pos);
cpresser@8
   147
		buf_pos = 0;
cpresser@15
   148
		buf_cmd_start = 255;
cpresser@8
   149
	    }
cpresser@8
   150
	}
cpresser@8
   151
cpresser@8
   152
    }
cpresser@8
   153
}
cpresser@8
   154
cpresser@8
   155
cpresser@8
   156
void cDriverPICCtl::DecodeCmd(uint8_t * cmd, uint8_t len)
cpresser@8
   157
{
cpresser@15
   158
/*    uint8_t i;
cpresser@14
   159
    printf("cmd(%2d): ",len);
cpresser@14
   160
    for (i=0; i<len; i++) { printf("0x%02x ",cmd[i]);}
cpresser@15
   161
    printf("\n");*/
cpresser@14
   162
cpresser@8
   163
    switch (cmd[CMD_HDR_COMMAND])
cpresser@8
   164
    {
cpresser@14
   165
        case CMD_SYS_ACK:	ack_flag = true;
cpresser@8
   166
	 			break;
cpresser@8
   167
cpresser@8
   168
	case CMD_SYS_IR:	printf(" Incoming Key-Event 0x%02x (Source 0x%02x)\n",cmd[CMD_DATA_START+1],cmd[CMD_DATA_START]);
root@5
   169
	  			break;
root@5
   170
cpresser@8
   171
	default:		printf(" recieved Message 0x%x \n",cmd[CMD_HDR_COMMAND]);
root@5
   172
    }
root@5
   173
cpresser@14
   174
root@5
   175
}
root@5
   176
root@5
   177
int cDriverPICCtl::Init()
root@5
   178
{
root@5
   179
    int y;
root@5
   180
root@5
   181
    // fixed values so far...
root@5
   182
    width = 240;
root@5
   183
    height = 64;
root@5
   184
root@5
   185
    for (unsigned int i = 0; i < config->options.size(); i++)
root@5
   186
    {
root@5
   187
        if (config->options[i].name == "")
root@5
   188
        {
root@5
   189
        }
root@5
   190
    }
root@5
   191
root@5
   192
    // setup lcd array (wanted state)
root@5
   193
    newLCD = new unsigned char*[height];
root@5
   194
    if (newLCD)
root@5
   195
    {
root@5
   196
        for (y = 0; y < height; y++)
root@5
   197
        {
root@5
   198
            newLCD[y] = new unsigned char[width/8];
root@5
   199
            memset(newLCD[y], 0, (width/8));
root@5
   200
        }
root@5
   201
    }
root@5
   202
    // setup lcd array (current state)
root@5
   203
    oldLCD = new unsigned char*[height];
root@5
   204
    if (oldLCD)
root@5
   205
    {
root@5
   206
        for (y = 0; y < height; y++)
root@5
   207
        {
root@5
   208
            oldLCD[y] = new unsigned char[width/8];
root@5
   209
            memset(oldLCD[y], 0, (width/8));
root@5
   210
        }
root@5
   211
    }
root@5
   212
root@5
   213
    if (config->device == "")
root@5
   214
    {
root@5
   215
        return -1;
root@5
   216
    }
root@5
   217
    if (port->Open(config->device.c_str(), SignalHandler) != 0)
root@5
   218
        return -1;
root@5
   219
root@5
   220
    *oldConfig = *config;
root@5
   221
root@5
   222
    // clear display
root@5
   223
    Clear();
root@5
   224
    CmdDispClearScreen();
root@5
   225
    CmdDispSetManaged();
cpresser@15
   226
    CmdDispSetBrightness(0);
root@5
   227
root@5
   228
    syslog(LOG_INFO, "%s: PICCtl initialized.\n", config->name.c_str());
root@5
   229
    return 0;
root@5
   230
}
root@5
   231
root@5
   232
int cDriverPICCtl::DeInit()
root@5
   233
{
root@5
   234
    int y;
root@5
   235
    // free lcd array (wanted state)
root@5
   236
    if (newLCD)
root@5
   237
    {
root@5
   238
        for (y = 0; y < height; y++)
root@5
   239
        {
root@5
   240
            delete[] newLCD[y];
root@5
   241
        }
root@5
   242
        delete[] newLCD;
root@5
   243
    }
root@5
   244
    // free lcd array (current state)
root@5
   245
    if (oldLCD)
root@5
   246
    {
root@5
   247
        for (y = 0; y < height; y++)
root@5
   248
        {
root@5
   249
            delete[] oldLCD[y];
root@5
   250
        }
root@5
   251
        delete[] oldLCD;
root@5
   252
    }
root@5
   253
root@5
   254
    CmdDispSetUnManaged();
root@5
   255
    
root@5
   256
    delete instance;
root@5
   257
    instance = 0;
root@5
   258
root@5
   259
    if (port->Close() != 0)
root@5
   260
        return -1;
root@5
   261
    return 0;
root@5
   262
}
root@5
   263
root@5
   264
int cDriverPICCtl::CheckSetup()
root@5
   265
{
root@5
   266
    if (config->device != oldConfig->device ||
root@5
   267
        config->width != oldConfig->width ||
root@5
   268
        config->height != oldConfig->height)
root@5
   269
    {
root@5
   270
        DeInit();
root@5
   271
        Init();
root@5
   272
        return 0;
root@5
   273
    }
root@5
   274
root@5
   275
    if (config->upsideDown != oldConfig->upsideDown ||
root@5
   276
        config->invert != oldConfig->invert)
root@5
   277
    {
root@5
   278
        oldConfig->upsideDown = config->upsideDown;
root@5
   279
        oldConfig->invert = config->invert;
root@5
   280
        return 1;
root@5
   281
    }
root@5
   282
    return 0;
root@5
   283
}
root@5
   284
root@5
   285
void cDriverPICCtl::Clear()
root@5
   286
{
root@5
   287
    for (int y = 0; y < height; y++)
root@5
   288
        memset(newLCD[y], 0, (width/8));
root@5
   289
}
root@5
   290
root@5
   291
void cDriverPICCtl::Set8Pixels(int x, int y, unsigned char data)
root@5
   292
{
root@5
   293
    if (x >= width || y >= height)
root@5
   294
        return;
root@5
   295
root@5
   296
    if (!config->upsideDown)
root@5
   297
    {
root@5
   298
        newLCD[y][x/8] = data;
root@5
   299
    }
root@5
   300
    else
root@5
   301
    {
root@5
   302
        x = width - 1 - x;
root@5
   303
        y = height - 1 - y;
root@5
   304
        newLCD[y][x / 8] |= ReverseBits(data);
root@5
   305
    }
root@5
   306
}
root@5
   307
root@5
   308
void cDriverPICCtl::Refresh(bool refreshAll)
root@5
   309
{
root@5
   310
    int y;
root@5
   311
root@5
   312
    if (CheckSetup() == 1)
root@5
   313
        refreshAll = true;
root@5
   314
root@5
   315
    if (config->refreshDisplay > 0)
root@5
   316
    {
root@5
   317
        refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
root@5
   318
        if (!refreshAll && !refreshCounter)
root@5
   319
            refreshAll = true;
root@5
   320
    }
root@5
   321
root@5
   322
root@5
   323
    if (refreshAll)
root@5
   324
    {
root@5
   325
        // draw all
root@5
   326
        // always draw a complete row! (30 bytes!)
root@5
   327
        for (y = 0; y < height; y++)
root@5
   328
        {
root@5
   329
            CmdDispSetColData(y, 0, (width/8), newLCD[y]);
root@5
   330
            memcpy(oldLCD[y], newLCD[y], (width/8));
root@5
   331
        }
root@5
   332
        // and reset RefreshCounter
root@5
   333
        refreshCounter = 0;
root@5
   334
    }
root@5
   335
    else
root@5
   336
    {
root@5
   337
	// for every line
root@5
   338
	for (y = 0; y< height; y++)
root@5
   339
        {
root@5
   340
            // did anysthing change? -> draw new line
root@5
   341
	    if (memcmp(newLCD[y],oldLCD[y],(width/8)) != 0)
root@5
   342
            {
root@5
   343
                 CmdDispSetColData(y, 0, (width/8), newLCD[y]);
root@5
   344
                 memcpy(oldLCD[y], newLCD[y], (width/8));
root@5
   345
            }
root@5
   346
        }
root@5
   347
    }
root@5
   348
}
root@5
   349
root@5
   350
void cDriverPICCtl::SetBrightness(unsigned int percent)
root@5
   351
{
root@5
   352
    CmdDispSetBrightness(percent);
root@5
   353
}
root@5
   354
root@5
   355
void cDriverPICCtl::SetClock(unsigned int percent)
root@5
   356
{
root@5
   357
    CmdDispSetBrightness(percent);
root@5
   358
}
root@5
   359
root@5
   360
int cDriverPICCtl::WaitForAck(void)
root@5
   361
{
root@5
   362
    int timeout;
root@5
   363
root@5
   364
    for (timeout=0; timeout<10000; timeout++)
root@5
   365
    {
root@5
   366
    	usleep(10);
root@5
   367
	if (ack_flag) return 1;
root@5
   368
    }
root@5
   369
    syslog(LOG_INFO, "PICCtl: missed a ACK packet!.\n");
root@5
   370
    return 0;
root@5
   371
}
root@5
   372
root@5
   373
void cDriverPICCtl::CmdDispClearScreen(void)
root@5
   374
{
root@5
   375
    uint8_t cmd[4];
root@5
   376
root@5
   377
    cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
root@5
   378
    cmd[CMD_HDR_COMMAND] = CMD_DISP_CLEAR_SCREEN;
root@5
   379
    cmd[CMD_HDR_LENGTH] = 0;
root@5
   380
    cmd[CMD_HDR_LENGTH+1] = 0;
root@5
   381
root@5
   382
    port->WriteData(cmd, 4);
root@5
   383
    WaitForAck();
root@5
   384
}
root@5
   385
root@5
   386
void cDriverPICCtl::CmdDispSetBrightness(uint8_t percent)
root@5
   387
{
root@5
   388
    uint8_t cmd[5];
root@5
   389
root@5
   390
    cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
root@5
   391
    cmd[CMD_HDR_COMMAND] = CMD_SET_PWM1;
root@5
   392
    cmd[CMD_HDR_LENGTH] = 0;
root@5
   393
    cmd[CMD_HDR_LENGTH+1] = 1;
root@5
   394
    cmd[CMD_DATA_START] = (uint8_t) round(percent * 2.55);
root@5
   395
root@5
   396
    port->WriteData(cmd, 5);
root@5
   397
    WaitForAck();
root@5
   398
}
root@5
   399
root@5
   400
void cDriverPICCtl::CmdDispSetColData(uint8_t yoffset, uint8_t xoffset, uint8_t length, uint8_t * data)
root@5
   401
{
root@5
   402
    uint8_t cmd[64];
root@5
   403
    uint16_t address;
root@5
   404
root@5
   405
    address = 0x1E * yoffset + xoffset;
root@5
   406
root@5
   407
    cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
root@5
   408
    cmd[CMD_HDR_COMMAND] = CMD_DISP_SET_ROW_DATA;
root@5
   409
    cmd[CMD_HDR_LENGTH] = 0;
root@5
   410
    cmd[CMD_HDR_LENGTH+1] = (length + 2);
root@5
   411
    cmd[CMD_DATA_START] = (uint8_t)(address % 256);	// lower address
root@5
   412
    cmd[CMD_DATA_START+1] = (uint8_t)(address / 256);	// upper address
root@5
   413
    memcpy(&cmd[CMD_DATA_START+2], data, length);
root@5
   414
root@5
   415
    port->WriteData(cmd, length + 6);
root@5
   416
    WaitForAck();
root@5
   417
root@5
   418
//    for (address = 0; address < length+6; address ++) printf("0x%02x ",cmd[address]);
root@5
   419
//  printf("address=0x%x upper=0x%x lower=0x%x \n", address, (uint8_t)(address / 256), (uint8_t)(address % 256));
root@5
   420
//    printf("\n");
root@5
   421
}
root@5
   422
root@5
   423
void cDriverPICCtl::CmdDispSetManaged(void)
root@5
   424
{
root@5
   425
    uint8_t cmd[4];
root@5
   426
root@5
   427
    cmd[CMD_HDR_SYNC] = CMD_SYNC_SEND;
root@5
   428
    cmd[CMD_HDR_COMMAND] = CMD_SET_MODE_MANAGED;
root@5
   429
    cmd[CMD_HDR_LENGTH] = 0;
root@5
   430
    cmd[CMD_HDR_LENGTH+1] = 0;
root@5
   431
root@5
   432
    port->WriteData(cmd,4);
root@5
   433
    WaitForAck();
root@5
   434
}
root@5
   435
root@5
   436
void cDriverPICCtl::CmdDispSetUnManaged(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_UNMANAGED;
root@5
   442
    cmd[CMD_HDR_LENGTH] = 0;
root@5
   443
    cmd[CMD_HDR_LENGTH+1] = 0;
root@5
   444
root@5
   445
    port->WriteData(cmd,4);
root@5
   446
    WaitForAck();
root@5
   447
}
root@5
   448
root@5
   449
root@5
   450
} // end NameSpace