graphlcd-base/glcddrivers/gu140x32f.c
author root@rika
Wed, 06 Feb 2008 17:37:50 +0000
changeset 5 37602e25a04a
parent 4 df6a40031aa5
permissions -rw-r--r--
added picctl code
root@4
     1
/*
root@4
     2
 * GraphLCD driver library
root@4
     3
 *
root@4
     4
 * gu140x32f.c  -  8-bit driver module for Noritake GU140x32-F7806 VFD
root@4
     5
 *                 displays. The VFD is operating in its 8 bit-mode
root@4
     6
 *                 connected to a single PC parallel port.
root@4
     7
 *
root@4
     8
 * based on:
root@4
     9
 *   HD61830 device
root@4
    10
 *     (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
root@4
    11
 *   lcdproc 0.4 driver hd44780-ext8bit
root@4
    12
 *     (c) 1999, 1995 Benjamin Tse <blt AT Comports com>
root@4
    13
 *
root@4
    14
 * This file is released under the GNU General Public License. Refer
root@4
    15
 * to the COPYING file distributed with this package.
root@4
    16
 *
root@4
    17
 * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
root@4
    18
 */
root@4
    19
root@4
    20
#include <errno.h>
root@4
    21
#include <syslog.h>
root@4
    22
#include <unistd.h>
root@4
    23
#include <sys/time.h>
root@4
    24
root@4
    25
#include "common.h"
root@4
    26
#include "config.h"
root@4
    27
#include "gu140x32f.h"
root@4
    28
#include "port.h"
root@4
    29
root@4
    30
root@4
    31
namespace GLCD
root@4
    32
{
root@4
    33
root@4
    34
// Defines for hd44780 Displays
root@4
    35
#define RS_DAT      0x00
root@4
    36
#define RS_CMD      0x01
root@4
    37
root@4
    38
#define CLEAR       0x01
root@4
    39
root@4
    40
#define HOMECURSOR  0x02
root@4
    41
root@4
    42
#define ENTRYMODE   0x04
root@4
    43
#define E_MOVERIGHT 0x02
root@4
    44
#define E_MOVELEFT  0x00
root@4
    45
#define EDGESCROLL  0x01
root@4
    46
#define NOSCROLL    0x00
root@4
    47
root@4
    48
#define ONOFFCTRL   0x08
root@4
    49
#define DISPON      0x04
root@4
    50
#define DISPOFF     0x00
root@4
    51
#define CURSORON    0x02
root@4
    52
#define CURSOROFF   0x00
root@4
    53
#define CURSORBLINK 0x01
root@4
    54
#define CURSORNOBLINK 0x00
root@4
    55
root@4
    56
#define CURSORSHIFT 0x10
root@4
    57
#define SCROLLDISP  0x08
root@4
    58
#define MOVECURSOR  0x00
root@4
    59
#define MOVERIGHT   0x04
root@4
    60
#define MOVELEFT    0x00
root@4
    61
root@4
    62
#define FUNCSET     0x20
root@4
    63
#define IF_8BIT     0x10
root@4
    64
#define IF_4BIT     0x00
root@4
    65
root@4
    66
// Control output lines
root@4
    67
// Write to baseaddress+2
root@4
    68
#define nSTRB       0x01    // pin 1; negative logic
root@4
    69
#define nLF         0x02    // pin 14
root@4
    70
#define nINIT       0x04    // pin 16; the only positive logic output line
root@4
    71
#define nSEL        0x08    // pin 17
root@4
    72
#define ENIRQ       0x10    // Enable IRQ via ACK line (don't enable this withouT
root@4
    73
                            // setting up interrupt stuff too)
root@4
    74
#define ENBI        0x20    // Enable bi-directional port (is nice to play with!
root@4
    75
                            // I first didn't know a SPP could do this)
root@4
    76
root@4
    77
#define OUTMASK     0x0B    // SEL, LF and STRB are hardware inverted
root@4
    78
                            // Use this mask only for the control output lines
root@4
    79
                            // XOR with this mask ( ^ OUTMASK )
root@4
    80
root@4
    81
static const std::string kWiringStandard = "Standard";
root@4
    82
static const std::string kWiringWindows  = "Windows";
root@4
    83
root@4
    84
// standard wiring
root@4
    85
// #define RS        nSTRB
root@4
    86
// #define RW        nLF
root@4
    87
// #define EN1       nINIT
root@4
    88
// #define BL        nSEL
root@4
    89
root@4
    90
// windows wiring
root@4
    91
// #define RS        nINIT
root@4
    92
// #define RW        nLF
root@4
    93
// #define EN1       nSTRB
root@4
    94
// #define BL        nSEL
root@4
    95
root@4
    96
root@4
    97
cDriverGU140X32F::cDriverGU140X32F(cDriverConfig * config)
root@4
    98
:   config(config),
root@4
    99
    m_pDrawMem(0),
root@4
   100
    m_pVFDMem(0)
root@4
   101
{
root@4
   102
    oldConfig = new cDriverConfig(*config);
root@4
   103
root@4
   104
    port = new cParallelPort();
root@4
   105
root@4
   106
    m_nRefreshCounter = 0;
root@4
   107
}
root@4
   108
root@4
   109
cDriverGU140X32F::~cDriverGU140X32F()
root@4
   110
{
root@4
   111
    delete port;
root@4
   112
    delete oldConfig;
root@4
   113
}
root@4
   114
root@4
   115
int cDriverGU140X32F::Init()
root@4
   116
{
root@4
   117
    int x;
root@4
   118
    struct timeval tv1, tv2;
root@4
   119
root@4
   120
    // default values
root@4
   121
    width = config->width;
root@4
   122
    if (width <= 0)
root@4
   123
        width = 140;
root@4
   124
    height = config->height;
root@4
   125
    if (height <= 0)
root@4
   126
        height = 32;
root@4
   127
    m_iSizeYb = ((height + 7) / 8); // 4
root@4
   128
    m_WiringRS = nSTRB;
root@4
   129
    m_WiringEN1 = nINIT;
root@4
   130
root@4
   131
    for (unsigned int i = 0; i < config->options.size(); i++)
root@4
   132
    {
root@4
   133
        if (config->options[i].name == "Wiring")
root@4
   134
        {
root@4
   135
            if (config->options[i].value == kWiringStandard)
root@4
   136
            {
root@4
   137
                m_WiringRS = nSTRB;
root@4
   138
                m_WiringEN1 = nINIT;
root@4
   139
            }
root@4
   140
            else if (config->options[i].value == kWiringWindows)
root@4
   141
            {
root@4
   142
                m_WiringRS = nINIT;
root@4
   143
                m_WiringEN1 = nSTRB;
root@4
   144
            }
root@4
   145
            else
root@4
   146
                syslog(LOG_ERR, "%s error: wiring %s not supported, using default (Standard)!\n",
root@4
   147
                       config->name.c_str(), config->options[i].value.c_str());
root@4
   148
        }
root@4
   149
    }
root@4
   150
root@4
   151
    // setup the memory array for the drawing array gu140x32f
root@4
   152
    m_pDrawMem = new unsigned char[width * m_iSizeYb];
root@4
   153
    Clear();
root@4
   154
root@4
   155
    // setup the memory array for the display array gu140x32f
root@4
   156
    m_pVFDMem = new unsigned char[width * m_iSizeYb];
root@4
   157
    ClearVFDMem();
root@4
   158
root@4
   159
    if (config->device == "")
root@4
   160
    {
root@4
   161
        // use DirectIO
root@4
   162
        if (port->Open(config->port) != 0)
root@4
   163
            return -1;
root@4
   164
        uSleep(10);
root@4
   165
    }
root@4
   166
    else
root@4
   167
    {
root@4
   168
        // use ppdev
root@4
   169
        if (port->Open(config->device.c_str()) != 0)
root@4
   170
            return -1;
root@4
   171
    }
root@4
   172
root@4
   173
    if (nSleepInit() != 0)
root@4
   174
    {
root@4
   175
        syslog(LOG_ERR, "%s: INFO: cannot change wait parameters  Err: %s (cDriver::Init)\n", config->name.c_str(), strerror(errno));
root@4
   176
        m_bSleepIsInit = false;
root@4
   177
    }
root@4
   178
    else
root@4
   179
    {
root@4
   180
        m_bSleepIsInit = true;
root@4
   181
    }
root@4
   182
root@4
   183
    syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
root@4
   184
    gettimeofday(&tv1, 0);
root@4
   185
    for (x = 0; x < 10000; x++)
root@4
   186
    {
root@4
   187
        port->WriteData(x % 0x100);
root@4
   188
    }
root@4
   189
    gettimeofday(&tv2, 0);
root@4
   190
    nSleepDeInit();
root@4
   191
    m_nTimingAdjustCmd = ((tv2.tv_sec - tv1.tv_sec) * 10000 + (tv2.tv_usec - tv1.tv_usec)) / 1000;
root@4
   192
    syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), m_nTimingAdjustCmd);
root@4
   193
root@4
   194
root@4
   195
    // setup the lcd in 8 bit mode
root@4
   196
    Write(RS_CMD, FUNCSET | IF_8BIT, 4100);
root@4
   197
    Write(RS_CMD, FUNCSET | IF_8BIT, 100);
root@4
   198
    Write(RS_CMD, FUNCSET | IF_8BIT, 40);
root@4
   199
root@4
   200
    Write(RS_CMD, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK, 40);
root@4
   201
    Write(RS_CMD, CLEAR, 1600);
root@4
   202
    Write(RS_CMD, HOMECURSOR, 1600);
root@4
   203
root@4
   204
    port->Release();
root@4
   205
root@4
   206
    *oldConfig = *config;
root@4
   207
root@4
   208
    // Set Display SetBrightness
root@4
   209
    SetBrightness(config->brightness);
root@4
   210
    // clear display
root@4
   211
    ClearVFDMem();
root@4
   212
    Clear();
root@4
   213
root@4
   214
    syslog(LOG_INFO, "%s: gu140x32f initialized.\n", config->name.c_str());
root@4
   215
    return 0;
root@4
   216
}
root@4
   217
root@4
   218
int cDriverGU140X32F::DeInit()
root@4
   219
{
root@4
   220
    if (m_pVFDMem)
root@4
   221
        delete[] m_pVFDMem;
root@4
   222
    if (m_pDrawMem)
root@4
   223
        delete[] m_pDrawMem;
root@4
   224
root@4
   225
    if (port->Close() != 0)
root@4
   226
        return -1;
root@4
   227
    return 0;
root@4
   228
}
root@4
   229
root@4
   230
int cDriverGU140X32F::CheckSetup()
root@4
   231
{
root@4
   232
    if (config->device != oldConfig->device ||
root@4
   233
        config->port != oldConfig->port ||
root@4
   234
        config->width != oldConfig->width ||
root@4
   235
        config->height != oldConfig->height)
root@4
   236
    {
root@4
   237
        DeInit();
root@4
   238
        Init();
root@4
   239
        return 0;
root@4
   240
    }
root@4
   241
root@4
   242
    if (config->brightness != oldConfig->brightness)
root@4
   243
    {
root@4
   244
        oldConfig->brightness = config->brightness;
root@4
   245
        SetBrightness(config->brightness);
root@4
   246
    }
root@4
   247
root@4
   248
    if (config->upsideDown != oldConfig->upsideDown ||
root@4
   249
        config->invert != oldConfig->invert)
root@4
   250
    {
root@4
   251
        oldConfig->upsideDown = config->upsideDown;
root@4
   252
        oldConfig->invert = config->invert;
root@4
   253
        return 1;
root@4
   254
    }
root@4
   255
    return 0;
root@4
   256
}
root@4
   257
root@4
   258
void cDriverGU140X32F::ClearVFDMem()
root@4
   259
{
root@4
   260
    for (int n = 0; m_pVFDMem && n < (width * m_iSizeYb); n++)
root@4
   261
        m_pVFDMem[n] = 0x00;
root@4
   262
}
root@4
   263
root@4
   264
void cDriverGU140X32F::Clear()
root@4
   265
{
root@4
   266
    for (int n = 0; m_pDrawMem && n < (width * m_iSizeYb); n++)
root@4
   267
        m_pDrawMem[n] = 0x00;
root@4
   268
}
root@4
   269
root@4
   270
void cDriverGU140X32F::SetBrightness(unsigned int percent)
root@4
   271
{
root@4
   272
    port->Claim();
root@4
   273
root@4
   274
    unsigned char level;
root@4
   275
    if (percent > 100)
root@4
   276
        percent = 100;
root@4
   277
    level = percent / 25;
root@4
   278
    if (level < 1)
root@4
   279
        level = 1;
root@4
   280
    level = (4 - level) & 0x03;
root@4
   281
    // Set Brightness
root@4
   282
    // 00 - 100%
root@4
   283
    // 01 -  75%
root@4
   284
    // 02 -  50%
root@4
   285
    // 03 -  25%
root@4
   286
    Write(RS_CMD, FUNCSET | IF_8BIT, 40);
root@4
   287
    Write(RS_DAT, level, 40);
root@4
   288
root@4
   289
    port->Release();
root@4
   290
}
root@4
   291
root@4
   292
void cDriverGU140X32F::Write(unsigned char nFlags, unsigned char bData, unsigned int nMicroSecBusyTime)
root@4
   293
{
root@4
   294
    if (m_bSleepIsInit)
root@4
   295
        nSleepInit();
root@4
   296
root@4
   297
    unsigned char enableLines = 0, portControl;
root@4
   298
root@4
   299
    // Only one controller is supported
root@4
   300
    enableLines = m_WiringEN1;
root@4
   301
root@4
   302
    if (nFlags == RS_CMD)
root@4
   303
        portControl = 0;
root@4
   304
    else // if (nFlags == RS_DAT)
root@4
   305
        portControl = m_WiringRS;
root@4
   306
root@4
   307
    // portControl |= m_WiringBL;
root@4
   308
root@4
   309
    port->WriteControl(portControl ^ OUTMASK);                  //Reset controlbits
root@4
   310
    port->WriteData(bData);                                     //Set data
root@4
   311
    port->WriteControl((enableLines | portControl) ^ OUTMASK);  //Set controlbits
root@4
   312
root@4
   313
    // How long hold the data active
root@4
   314
    if (m_bSleepIsInit && (25 + (100 * config->adjustTiming) - m_nTimingAdjustCmd > 0))
root@4
   315
    {
root@4
   316
        // Wait 50ns
root@4
   317
        nSleep(std::max(25L, 50 + (100 * config->adjustTiming) - m_nTimingAdjustCmd));
root@4
   318
    }
root@4
   319
root@4
   320
    port->WriteControl(portControl ^ OUTMASK);                  //Reset controlbits
root@4
   321
root@4
   322
    nSleep((nMicroSecBusyTime * 1000) + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
root@4
   323
root@4
   324
    if (m_bSleepIsInit)
root@4
   325
        nSleepDeInit();
root@4
   326
}
root@4
   327
root@4
   328
void cDriverGU140X32F::SetPixel(int x, int y)
root@4
   329
{
root@4
   330
    unsigned char c;
root@4
   331
    int n;
root@4
   332
root@4
   333
    if (!m_pDrawMem)
root@4
   334
        return;
root@4
   335
root@4
   336
    if (x >= width || x < 0)
root@4
   337
        return;
root@4
   338
    if (y >= height || y < 0)
root@4
   339
        return;
root@4
   340
root@4
   341
    if (config->upsideDown)
root@4
   342
    {
root@4
   343
        x = width - 1 - x;
root@4
   344
        y = height - 1 - y;
root@4
   345
    }
root@4
   346
root@4
   347
    n = x + ((y / 8) * width);
root@4
   348
    c = 0x80 >> (y % 8);
root@4
   349
root@4
   350
    m_pDrawMem[n] |= c;
root@4
   351
}
root@4
   352
root@4
   353
void cDriverGU140X32F::Set8Pixels(int x, int y, unsigned char data)
root@4
   354
{
root@4
   355
    int n;
root@4
   356
root@4
   357
    // x - pos is'nt mayby align to 8
root@4
   358
    x &= 0xFFF8;
root@4
   359
root@4
   360
    for (n = 0; n < 8; ++n)
root@4
   361
    {
root@4
   362
        if (data & (0x80 >> n))      // if bit is set
root@4
   363
            SetPixel(x + n, y);
root@4
   364
    }
root@4
   365
}
root@4
   366
root@4
   367
void cDriverGU140X32F::Refresh(bool refreshAll)
root@4
   368
{
root@4
   369
    int n, x, yb;
root@4
   370
root@4
   371
    if (!m_pVFDMem || !m_pDrawMem)
root@4
   372
        return;
root@4
   373
root@4
   374
    bool doRefresh = false;
root@4
   375
    int minX = width;
root@4
   376
    int maxX = 0;
root@4
   377
    int minYb = m_iSizeYb;
root@4
   378
    int maxYb = 0;
root@4
   379
root@4
   380
    if (CheckSetup() > 0)
root@4
   381
        refreshAll = true;
root@4
   382
root@4
   383
    for (yb = 0; yb < m_iSizeYb; ++yb)
root@4
   384
        for (x = 0; x < width; ++x)
root@4
   385
        {
root@4
   386
            n = x + (yb * width);
root@4
   387
            if (m_pVFDMem[n] != m_pDrawMem[n])
root@4
   388
            {
root@4
   389
                m_pVFDMem[n] = m_pDrawMem[n];
root@4
   390
                minX = std::min(minX, x);
root@4
   391
                maxX = std::max(maxX, x);
root@4
   392
                minYb = std::min(minYb, yb);
root@4
   393
                maxYb = std::max(maxYb, yb + 1);
root@4
   394
                doRefresh = true;
root@4
   395
            }
root@4
   396
        }
root@4
   397
root@4
   398
    m_nRefreshCounter = (m_nRefreshCounter + 1) % config->refreshDisplay;
root@4
   399
root@4
   400
    if (!refreshAll && !m_nRefreshCounter)
root@4
   401
        refreshAll = true;
root@4
   402
root@4
   403
    if (refreshAll || doRefresh)
root@4
   404
    {
root@4
   405
        if (refreshAll)
root@4
   406
        {
root@4
   407
            minX = 0;
root@4
   408
            maxX = width;
root@4
   409
            minYb = 0;
root@4
   410
            maxYb = m_iSizeYb;
root@4
   411
            // and reset RefreshCounter
root@4
   412
            m_nRefreshCounter = 0;
root@4
   413
        }
root@4
   414
root@4
   415
        minX = std::max(minX, 0);
root@4
   416
        maxX = std::min(maxX, width - 1);
root@4
   417
        minYb = std::max(minYb, 0);
root@4
   418
        maxYb = std::min(maxYb, m_iSizeYb);
root@4
   419
root@4
   420
        port->Claim();
root@4
   421
        // send lcd data to display, controller
root@4
   422
        Write(RS_CMD, 0xF1, 40);
root@4
   423
        Write(RS_DAT, minX, 40);
root@4
   424
        Write(RS_DAT, (minYb * 8) & 0xFFF8, 40);
root@4
   425
        Write(RS_DAT, maxX, 40);
root@4
   426
        Write(RS_DAT, (maxYb * 8), 40);
root@4
   427
root@4
   428
        Write(RS_DAT, 'v', 500);
root@4
   429
root@4
   430
        for (yb = minYb; yb <= maxYb; ++yb)
root@4
   431
            for (x = minX; x <= maxX; ++x)
root@4
   432
            {
root@4
   433
                n = x + (yb * width);
root@4
   434
root@4
   435
                if (n >= (width * m_iSizeYb))
root@4
   436
                    break;
root@4
   437
                Write(RS_DAT, (m_pVFDMem[n]) ^ (config->invert ? 0xff : 0x00), 40);
root@4
   438
            }
root@4
   439
        port->Release();
root@4
   440
    }
root@4
   441
}
root@4
   442
root@4
   443
} // end of namespace