2 * GraphLCD driver library
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.
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>
14 * This file is released under the GNU General Public License. Refer
15 * to the COPYING file distributed with this package.
17 * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
27 #include "gu140x32f.h"
34 // Defines for hd44780 Displays
40 #define HOMECURSOR 0x02
42 #define ENTRYMODE 0x04
43 #define E_MOVERIGHT 0x02
44 #define E_MOVELEFT 0x00
45 #define EDGESCROLL 0x01
48 #define ONOFFCTRL 0x08
52 #define CURSOROFF 0x00
53 #define CURSORBLINK 0x01
54 #define CURSORNOBLINK 0x00
56 #define CURSORSHIFT 0x10
57 #define SCROLLDISP 0x08
58 #define MOVECURSOR 0x00
59 #define MOVERIGHT 0x04
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)
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 )
81 static const std::string kWiringStandard = "Standard";
82 static const std::string kWiringWindows = "Windows";
97 cDriverGU140X32F::cDriverGU140X32F(cDriverConfig * config)
102 oldConfig = new cDriverConfig(*config);
104 port = new cParallelPort();
106 m_nRefreshCounter = 0;
109 cDriverGU140X32F::~cDriverGU140X32F()
115 int cDriverGU140X32F::Init()
118 struct timeval tv1, tv2;
121 width = config->width;
124 height = config->height;
127 m_iSizeYb = ((height + 7) / 8); // 4
131 for (unsigned int i = 0; i < config->options.size(); i++)
133 if (config->options[i].name == "Wiring")
135 if (config->options[i].value == kWiringStandard)
140 else if (config->options[i].value == kWiringWindows)
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());
151 // setup the memory array for the drawing array gu140x32f
152 m_pDrawMem = new unsigned char[width * m_iSizeYb];
155 // setup the memory array for the display array gu140x32f
156 m_pVFDMem = new unsigned char[width * m_iSizeYb];
159 if (config->device == "")
162 if (port->Open(config->port) != 0)
169 if (port->Open(config->device.c_str()) != 0)
173 if (nSleepInit() != 0)
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;
180 m_bSleepIsInit = true;
183 syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
184 gettimeofday(&tv1, 0);
185 for (x = 0; x < 10000; x++)
187 port->WriteData(x % 0x100);
189 gettimeofday(&tv2, 0);
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);
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);
200 Write(RS_CMD, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK, 40);
201 Write(RS_CMD, CLEAR, 1600);
202 Write(RS_CMD, HOMECURSOR, 1600);
206 *oldConfig = *config;
208 // Set Display SetBrightness
209 SetBrightness(config->brightness);
214 syslog(LOG_INFO, "%s: gu140x32f initialized.\n", config->name.c_str());
218 int cDriverGU140X32F::DeInit()
225 if (port->Close() != 0)
230 int cDriverGU140X32F::CheckSetup()
232 if (config->device != oldConfig->device ||
233 config->port != oldConfig->port ||
234 config->width != oldConfig->width ||
235 config->height != oldConfig->height)
242 if (config->brightness != oldConfig->brightness)
244 oldConfig->brightness = config->brightness;
245 SetBrightness(config->brightness);
248 if (config->upsideDown != oldConfig->upsideDown ||
249 config->invert != oldConfig->invert)
251 oldConfig->upsideDown = config->upsideDown;
252 oldConfig->invert = config->invert;
258 void cDriverGU140X32F::ClearVFDMem()
260 for (int n = 0; m_pVFDMem && n < (width * m_iSizeYb); n++)
264 void cDriverGU140X32F::Clear()
266 for (int n = 0; m_pDrawMem && n < (width * m_iSizeYb); n++)
267 m_pDrawMem[n] = 0x00;
270 void cDriverGU140X32F::SetBrightness(unsigned int percent)
277 level = percent / 25;
280 level = (4 - level) & 0x03;
286 Write(RS_CMD, FUNCSET | IF_8BIT, 40);
287 Write(RS_DAT, level, 40);
292 void cDriverGU140X32F::Write(unsigned char nFlags, unsigned char bData, unsigned int nMicroSecBusyTime)
297 unsigned char enableLines = 0, portControl;
299 // Only one controller is supported
300 enableLines = m_WiringEN1;
302 if (nFlags == RS_CMD)
304 else // if (nFlags == RS_DAT)
305 portControl = m_WiringRS;
307 // portControl |= m_WiringBL;
309 port->WriteControl(portControl ^ OUTMASK); //Reset controlbits
310 port->WriteData(bData); //Set data
311 port->WriteControl((enableLines | portControl) ^ OUTMASK); //Set controlbits
313 // How long hold the data active
314 if (m_bSleepIsInit && (25 + (100 * config->adjustTiming) - m_nTimingAdjustCmd > 0))
317 nSleep(std::max(25L, 50 + (100 * config->adjustTiming) - m_nTimingAdjustCmd));
320 port->WriteControl(portControl ^ OUTMASK); //Reset controlbits
322 nSleep((nMicroSecBusyTime * 1000) + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
328 void cDriverGU140X32F::SetPixel(int x, int y)
336 if (x >= width || x < 0)
338 if (y >= height || y < 0)
341 if (config->upsideDown)
347 n = x + ((y / 8) * width);
353 void cDriverGU140X32F::Set8Pixels(int x, int y, unsigned char data)
357 // x - pos is'nt mayby align to 8
360 for (n = 0; n < 8; ++n)
362 if (data & (0x80 >> n)) // if bit is set
367 void cDriverGU140X32F::Refresh(bool refreshAll)
371 if (!m_pVFDMem || !m_pDrawMem)
374 bool doRefresh = false;
377 int minYb = m_iSizeYb;
380 if (CheckSetup() > 0)
383 for (yb = 0; yb < m_iSizeYb; ++yb)
384 for (x = 0; x < width; ++x)
386 n = x + (yb * width);
387 if (m_pVFDMem[n] != m_pDrawMem[n])
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);
398 m_nRefreshCounter = (m_nRefreshCounter + 1) % config->refreshDisplay;
400 if (!refreshAll && !m_nRefreshCounter)
403 if (refreshAll || doRefresh)
411 // and reset RefreshCounter
412 m_nRefreshCounter = 0;
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);
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);
428 Write(RS_DAT, 'v', 500);
430 for (yb = minYb; yb <= maxYb; ++yb)
431 for (x = minX; x <= maxX; ++x)
433 n = x + (yb * width);
435 if (n >= (width * m_iSizeYb))
437 Write(RS_DAT, (m_pVFDMem[n]) ^ (config->invert ? 0xff : 0x00), 40);
443 } // end of namespace