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