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