1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/graphlcd-base/glcddrivers/gu140x32f.c Wed Feb 06 17:32:55 2008 +0000
1.3 @@ -0,0 +1,443 @@
1.4 +/*
1.5 + * GraphLCD driver library
1.6 + *
1.7 + * gu140x32f.c - 8-bit driver module for Noritake GU140x32-F7806 VFD
1.8 + * displays. The VFD is operating in its 8 bit-mode
1.9 + * connected to a single PC parallel port.
1.10 + *
1.11 + * based on:
1.12 + * HD61830 device
1.13 + * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
1.14 + * lcdproc 0.4 driver hd44780-ext8bit
1.15 + * (c) 1999, 1995 Benjamin Tse <blt AT Comports com>
1.16 + *
1.17 + * This file is released under the GNU General Public License. Refer
1.18 + * to the COPYING file distributed with this package.
1.19 + *
1.20 + * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
1.21 + */
1.22 +
1.23 +#include <errno.h>
1.24 +#include <syslog.h>
1.25 +#include <unistd.h>
1.26 +#include <sys/time.h>
1.27 +
1.28 +#include "common.h"
1.29 +#include "config.h"
1.30 +#include "gu140x32f.h"
1.31 +#include "port.h"
1.32 +
1.33 +
1.34 +namespace GLCD
1.35 +{
1.36 +
1.37 +// Defines for hd44780 Displays
1.38 +#define RS_DAT 0x00
1.39 +#define RS_CMD 0x01
1.40 +
1.41 +#define CLEAR 0x01
1.42 +
1.43 +#define HOMECURSOR 0x02
1.44 +
1.45 +#define ENTRYMODE 0x04
1.46 +#define E_MOVERIGHT 0x02
1.47 +#define E_MOVELEFT 0x00
1.48 +#define EDGESCROLL 0x01
1.49 +#define NOSCROLL 0x00
1.50 +
1.51 +#define ONOFFCTRL 0x08
1.52 +#define DISPON 0x04
1.53 +#define DISPOFF 0x00
1.54 +#define CURSORON 0x02
1.55 +#define CURSOROFF 0x00
1.56 +#define CURSORBLINK 0x01
1.57 +#define CURSORNOBLINK 0x00
1.58 +
1.59 +#define CURSORSHIFT 0x10
1.60 +#define SCROLLDISP 0x08
1.61 +#define MOVECURSOR 0x00
1.62 +#define MOVERIGHT 0x04
1.63 +#define MOVELEFT 0x00
1.64 +
1.65 +#define FUNCSET 0x20
1.66 +#define IF_8BIT 0x10
1.67 +#define IF_4BIT 0x00
1.68 +
1.69 +// Control output lines
1.70 +// Write to baseaddress+2
1.71 +#define nSTRB 0x01 // pin 1; negative logic
1.72 +#define nLF 0x02 // pin 14
1.73 +#define nINIT 0x04 // pin 16; the only positive logic output line
1.74 +#define nSEL 0x08 // pin 17
1.75 +#define ENIRQ 0x10 // Enable IRQ via ACK line (don't enable this withouT
1.76 + // setting up interrupt stuff too)
1.77 +#define ENBI 0x20 // Enable bi-directional port (is nice to play with!
1.78 + // I first didn't know a SPP could do this)
1.79 +
1.80 +#define OUTMASK 0x0B // SEL, LF and STRB are hardware inverted
1.81 + // Use this mask only for the control output lines
1.82 + // XOR with this mask ( ^ OUTMASK )
1.83 +
1.84 +static const std::string kWiringStandard = "Standard";
1.85 +static const std::string kWiringWindows = "Windows";
1.86 +
1.87 +// standard wiring
1.88 +// #define RS nSTRB
1.89 +// #define RW nLF
1.90 +// #define EN1 nINIT
1.91 +// #define BL nSEL
1.92 +
1.93 +// windows wiring
1.94 +// #define RS nINIT
1.95 +// #define RW nLF
1.96 +// #define EN1 nSTRB
1.97 +// #define BL nSEL
1.98 +
1.99 +
1.100 +cDriverGU140X32F::cDriverGU140X32F(cDriverConfig * config)
1.101 +: config(config),
1.102 + m_pDrawMem(0),
1.103 + m_pVFDMem(0)
1.104 +{
1.105 + oldConfig = new cDriverConfig(*config);
1.106 +
1.107 + port = new cParallelPort();
1.108 +
1.109 + m_nRefreshCounter = 0;
1.110 +}
1.111 +
1.112 +cDriverGU140X32F::~cDriverGU140X32F()
1.113 +{
1.114 + delete port;
1.115 + delete oldConfig;
1.116 +}
1.117 +
1.118 +int cDriverGU140X32F::Init()
1.119 +{
1.120 + int x;
1.121 + struct timeval tv1, tv2;
1.122 +
1.123 + // default values
1.124 + width = config->width;
1.125 + if (width <= 0)
1.126 + width = 140;
1.127 + height = config->height;
1.128 + if (height <= 0)
1.129 + height = 32;
1.130 + m_iSizeYb = ((height + 7) / 8); // 4
1.131 + m_WiringRS = nSTRB;
1.132 + m_WiringEN1 = nINIT;
1.133 +
1.134 + for (unsigned int i = 0; i < config->options.size(); i++)
1.135 + {
1.136 + if (config->options[i].name == "Wiring")
1.137 + {
1.138 + if (config->options[i].value == kWiringStandard)
1.139 + {
1.140 + m_WiringRS = nSTRB;
1.141 + m_WiringEN1 = nINIT;
1.142 + }
1.143 + else if (config->options[i].value == kWiringWindows)
1.144 + {
1.145 + m_WiringRS = nINIT;
1.146 + m_WiringEN1 = nSTRB;
1.147 + }
1.148 + else
1.149 + syslog(LOG_ERR, "%s error: wiring %s not supported, using default (Standard)!\n",
1.150 + config->name.c_str(), config->options[i].value.c_str());
1.151 + }
1.152 + }
1.153 +
1.154 + // setup the memory array for the drawing array gu140x32f
1.155 + m_pDrawMem = new unsigned char[width * m_iSizeYb];
1.156 + Clear();
1.157 +
1.158 + // setup the memory array for the display array gu140x32f
1.159 + m_pVFDMem = new unsigned char[width * m_iSizeYb];
1.160 + ClearVFDMem();
1.161 +
1.162 + if (config->device == "")
1.163 + {
1.164 + // use DirectIO
1.165 + if (port->Open(config->port) != 0)
1.166 + return -1;
1.167 + uSleep(10);
1.168 + }
1.169 + else
1.170 + {
1.171 + // use ppdev
1.172 + if (port->Open(config->device.c_str()) != 0)
1.173 + return -1;
1.174 + }
1.175 +
1.176 + if (nSleepInit() != 0)
1.177 + {
1.178 + syslog(LOG_ERR, "%s: INFO: cannot change wait parameters Err: %s (cDriver::Init)\n", config->name.c_str(), strerror(errno));
1.179 + m_bSleepIsInit = false;
1.180 + }
1.181 + else
1.182 + {
1.183 + m_bSleepIsInit = true;
1.184 + }
1.185 +
1.186 + syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
1.187 + gettimeofday(&tv1, 0);
1.188 + for (x = 0; x < 10000; x++)
1.189 + {
1.190 + port->WriteData(x % 0x100);
1.191 + }
1.192 + gettimeofday(&tv2, 0);
1.193 + nSleepDeInit();
1.194 + m_nTimingAdjustCmd = ((tv2.tv_sec - tv1.tv_sec) * 10000 + (tv2.tv_usec - tv1.tv_usec)) / 1000;
1.195 + syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), m_nTimingAdjustCmd);
1.196 +
1.197 +
1.198 + // setup the lcd in 8 bit mode
1.199 + Write(RS_CMD, FUNCSET | IF_8BIT, 4100);
1.200 + Write(RS_CMD, FUNCSET | IF_8BIT, 100);
1.201 + Write(RS_CMD, FUNCSET | IF_8BIT, 40);
1.202 +
1.203 + Write(RS_CMD, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK, 40);
1.204 + Write(RS_CMD, CLEAR, 1600);
1.205 + Write(RS_CMD, HOMECURSOR, 1600);
1.206 +
1.207 + port->Release();
1.208 +
1.209 + *oldConfig = *config;
1.210 +
1.211 + // Set Display SetBrightness
1.212 + SetBrightness(config->brightness);
1.213 + // clear display
1.214 + ClearVFDMem();
1.215 + Clear();
1.216 +
1.217 + syslog(LOG_INFO, "%s: gu140x32f initialized.\n", config->name.c_str());
1.218 + return 0;
1.219 +}
1.220 +
1.221 +int cDriverGU140X32F::DeInit()
1.222 +{
1.223 + if (m_pVFDMem)
1.224 + delete[] m_pVFDMem;
1.225 + if (m_pDrawMem)
1.226 + delete[] m_pDrawMem;
1.227 +
1.228 + if (port->Close() != 0)
1.229 + return -1;
1.230 + return 0;
1.231 +}
1.232 +
1.233 +int cDriverGU140X32F::CheckSetup()
1.234 +{
1.235 + if (config->device != oldConfig->device ||
1.236 + config->port != oldConfig->port ||
1.237 + config->width != oldConfig->width ||
1.238 + config->height != oldConfig->height)
1.239 + {
1.240 + DeInit();
1.241 + Init();
1.242 + return 0;
1.243 + }
1.244 +
1.245 + if (config->brightness != oldConfig->brightness)
1.246 + {
1.247 + oldConfig->brightness = config->brightness;
1.248 + SetBrightness(config->brightness);
1.249 + }
1.250 +
1.251 + if (config->upsideDown != oldConfig->upsideDown ||
1.252 + config->invert != oldConfig->invert)
1.253 + {
1.254 + oldConfig->upsideDown = config->upsideDown;
1.255 + oldConfig->invert = config->invert;
1.256 + return 1;
1.257 + }
1.258 + return 0;
1.259 +}
1.260 +
1.261 +void cDriverGU140X32F::ClearVFDMem()
1.262 +{
1.263 + for (int n = 0; m_pVFDMem && n < (width * m_iSizeYb); n++)
1.264 + m_pVFDMem[n] = 0x00;
1.265 +}
1.266 +
1.267 +void cDriverGU140X32F::Clear()
1.268 +{
1.269 + for (int n = 0; m_pDrawMem && n < (width * m_iSizeYb); n++)
1.270 + m_pDrawMem[n] = 0x00;
1.271 +}
1.272 +
1.273 +void cDriverGU140X32F::SetBrightness(unsigned int percent)
1.274 +{
1.275 + port->Claim();
1.276 +
1.277 + unsigned char level;
1.278 + if (percent > 100)
1.279 + percent = 100;
1.280 + level = percent / 25;
1.281 + if (level < 1)
1.282 + level = 1;
1.283 + level = (4 - level) & 0x03;
1.284 + // Set Brightness
1.285 + // 00 - 100%
1.286 + // 01 - 75%
1.287 + // 02 - 50%
1.288 + // 03 - 25%
1.289 + Write(RS_CMD, FUNCSET | IF_8BIT, 40);
1.290 + Write(RS_DAT, level, 40);
1.291 +
1.292 + port->Release();
1.293 +}
1.294 +
1.295 +void cDriverGU140X32F::Write(unsigned char nFlags, unsigned char bData, unsigned int nMicroSecBusyTime)
1.296 +{
1.297 + if (m_bSleepIsInit)
1.298 + nSleepInit();
1.299 +
1.300 + unsigned char enableLines = 0, portControl;
1.301 +
1.302 + // Only one controller is supported
1.303 + enableLines = m_WiringEN1;
1.304 +
1.305 + if (nFlags == RS_CMD)
1.306 + portControl = 0;
1.307 + else // if (nFlags == RS_DAT)
1.308 + portControl = m_WiringRS;
1.309 +
1.310 + // portControl |= m_WiringBL;
1.311 +
1.312 + port->WriteControl(portControl ^ OUTMASK); //Reset controlbits
1.313 + port->WriteData(bData); //Set data
1.314 + port->WriteControl((enableLines | portControl) ^ OUTMASK); //Set controlbits
1.315 +
1.316 + // How long hold the data active
1.317 + if (m_bSleepIsInit && (25 + (100 * config->adjustTiming) - m_nTimingAdjustCmd > 0))
1.318 + {
1.319 + // Wait 50ns
1.320 + nSleep(std::max(25L, 50 + (100 * config->adjustTiming) - m_nTimingAdjustCmd));
1.321 + }
1.322 +
1.323 + port->WriteControl(portControl ^ OUTMASK); //Reset controlbits
1.324 +
1.325 + nSleep((nMicroSecBusyTime * 1000) + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
1.326 +
1.327 + if (m_bSleepIsInit)
1.328 + nSleepDeInit();
1.329 +}
1.330 +
1.331 +void cDriverGU140X32F::SetPixel(int x, int y)
1.332 +{
1.333 + unsigned char c;
1.334 + int n;
1.335 +
1.336 + if (!m_pDrawMem)
1.337 + return;
1.338 +
1.339 + if (x >= width || x < 0)
1.340 + return;
1.341 + if (y >= height || y < 0)
1.342 + return;
1.343 +
1.344 + if (config->upsideDown)
1.345 + {
1.346 + x = width - 1 - x;
1.347 + y = height - 1 - y;
1.348 + }
1.349 +
1.350 + n = x + ((y / 8) * width);
1.351 + c = 0x80 >> (y % 8);
1.352 +
1.353 + m_pDrawMem[n] |= c;
1.354 +}
1.355 +
1.356 +void cDriverGU140X32F::Set8Pixels(int x, int y, unsigned char data)
1.357 +{
1.358 + int n;
1.359 +
1.360 + // x - pos is'nt mayby align to 8
1.361 + x &= 0xFFF8;
1.362 +
1.363 + for (n = 0; n < 8; ++n)
1.364 + {
1.365 + if (data & (0x80 >> n)) // if bit is set
1.366 + SetPixel(x + n, y);
1.367 + }
1.368 +}
1.369 +
1.370 +void cDriverGU140X32F::Refresh(bool refreshAll)
1.371 +{
1.372 + int n, x, yb;
1.373 +
1.374 + if (!m_pVFDMem || !m_pDrawMem)
1.375 + return;
1.376 +
1.377 + bool doRefresh = false;
1.378 + int minX = width;
1.379 + int maxX = 0;
1.380 + int minYb = m_iSizeYb;
1.381 + int maxYb = 0;
1.382 +
1.383 + if (CheckSetup() > 0)
1.384 + refreshAll = true;
1.385 +
1.386 + for (yb = 0; yb < m_iSizeYb; ++yb)
1.387 + for (x = 0; x < width; ++x)
1.388 + {
1.389 + n = x + (yb * width);
1.390 + if (m_pVFDMem[n] != m_pDrawMem[n])
1.391 + {
1.392 + m_pVFDMem[n] = m_pDrawMem[n];
1.393 + minX = std::min(minX, x);
1.394 + maxX = std::max(maxX, x);
1.395 + minYb = std::min(minYb, yb);
1.396 + maxYb = std::max(maxYb, yb + 1);
1.397 + doRefresh = true;
1.398 + }
1.399 + }
1.400 +
1.401 + m_nRefreshCounter = (m_nRefreshCounter + 1) % config->refreshDisplay;
1.402 +
1.403 + if (!refreshAll && !m_nRefreshCounter)
1.404 + refreshAll = true;
1.405 +
1.406 + if (refreshAll || doRefresh)
1.407 + {
1.408 + if (refreshAll)
1.409 + {
1.410 + minX = 0;
1.411 + maxX = width;
1.412 + minYb = 0;
1.413 + maxYb = m_iSizeYb;
1.414 + // and reset RefreshCounter
1.415 + m_nRefreshCounter = 0;
1.416 + }
1.417 +
1.418 + minX = std::max(minX, 0);
1.419 + maxX = std::min(maxX, width - 1);
1.420 + minYb = std::max(minYb, 0);
1.421 + maxYb = std::min(maxYb, m_iSizeYb);
1.422 +
1.423 + port->Claim();
1.424 + // send lcd data to display, controller
1.425 + Write(RS_CMD, 0xF1, 40);
1.426 + Write(RS_DAT, minX, 40);
1.427 + Write(RS_DAT, (minYb * 8) & 0xFFF8, 40);
1.428 + Write(RS_DAT, maxX, 40);
1.429 + Write(RS_DAT, (maxYb * 8), 40);
1.430 +
1.431 + Write(RS_DAT, 'v', 500);
1.432 +
1.433 + for (yb = minYb; yb <= maxYb; ++yb)
1.434 + for (x = minX; x <= maxX; ++x)
1.435 + {
1.436 + n = x + (yb * width);
1.437 +
1.438 + if (n >= (width * m_iSizeYb))
1.439 + break;
1.440 + Write(RS_DAT, (m_pVFDMem[n]) ^ (config->invert ? 0xff : 0x00), 40);
1.441 + }
1.442 + port->Release();
1.443 + }
1.444 +}
1.445 +
1.446 +} // end of namespace