1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/graphlcd-base/glcddrivers/gu256x64-3900.c Wed Feb 06 17:32:55 2008 +0000
1.3 @@ -0,0 +1,651 @@
1.4 +/*
1.5 + * GraphLCD driver library
1.6 + *
1.7 + * gu256x64-3900.c - 8-bit driver module for Noritake GU256X64x-3900
1.8 + * VFD displays. The VFD is either operating in
1.9 + * 8-bit mode connected to a single PC parallel
1.10 + * port or in serial mode connected to a single PC
1.11 + * serial port.
1.12 + *
1.13 + * based on:
1.14 + * gu256x64-372 driver module for graphlcd
1.15 + * (c) 2004 Andreas 'randy' Weinberger <randy AT smue.org>
1.16 + * gu256x32f driver module for graphlcd
1.17 + * (c) 2003 Andreas Brachold <vdr04 AT deltab.de>
1.18 + * HD61830 device
1.19 + * (c) 2001-2003 by Carsten Siebholz <c.siebholz AT t-online.de>
1.20 + * lcdproc 0.4 driver hd44780-ext8bit
1.21 + * (c) 1999, 1995 Benjamin Tse <blt AT comports.com>
1.22 + *
1.23 + * This file is released under the GNU General Public License. Refer
1.24 + * to the COPYING file distributed with this package.
1.25 + *
1.26 + * (c) 2004 Ralf Mueller (ralf AT bj-ig.de)
1.27 + */
1.28 +
1.29 +#include <errno.h>
1.30 +#include <fcntl.h>
1.31 +#include <syslog.h>
1.32 +#include <unistd.h>
1.33 +#include <termios.h>
1.34 +#include <sys/time.h>
1.35 +
1.36 +#include "common.h"
1.37 +#include "config.h"
1.38 +#include "gu256x64-3900.h"
1.39 +#include "port.h"
1.40 +
1.41 +
1.42 +namespace GLCD
1.43 +{
1.44 +
1.45 +static const unsigned char dSETSTART0 = 0x02; // Set display start address (CMD prefix)
1.46 +static const unsigned char dSETSTART1 = 0x44; // Set display start address (CMD)
1.47 +static const unsigned char dSETSTART2 = 0x00; // Set display start address
1.48 +static const unsigned char dSETSTART3 = 0x53; // Set display start address
1.49 +
1.50 +static const unsigned char nINITDISPLAY0 = 0x1b; // Initialize display (CMD prefix)
1.51 +static const unsigned char nINITDISPLAY1 = 0x40; // Initialize display (CMD)
1.52 +
1.53 +static const unsigned char nPOWER0 = 0x1f; // Power on/off
1.54 +static const unsigned char nPOWER1 = 0x28; // Power on/off
1.55 +static const unsigned char nPOWER2 = 0x61; // Power on/off
1.56 +static const unsigned char nPOWER3 = 0x40; // Power on/off
1.57 +
1.58 +static const unsigned char nSETBRIGHT0 = 0x1f; // Set brightness (CMD prefix)
1.59 +static const unsigned char nSETBRIGHT1 = 0x58; // Set brightness (CMD)
1.60 +
1.61 +static const unsigned char dSETBRIGHT0 = 0x02; // Set brightness (CMD prefix)
1.62 +static const unsigned char dSETBRIGHT1 = 0x44; // Set brightness (CMD)
1.63 +static const unsigned char dSETBRIGHT2 = 0x00; // Set brightness
1.64 +static const unsigned char dSETBRIGHT3 = 0x58; // Set brightness
1.65 +
1.66 +static const unsigned char BRIGHT_000 = 0x10; // Brightness 0%
1.67 +static const unsigned char BRIGHT_012 = 0x11; // Brightness 12.5%
1.68 +static const unsigned char BRIGHT_025 = 0x12; // Brightness 25%
1.69 +static const unsigned char BRIGHT_037 = 0x13; // Brightness 37.5%
1.70 +static const unsigned char BRIGHT_050 = 0x14; // Brightness 50%
1.71 +static const unsigned char BRIGHT_062 = 0x15; // Brightness 62.5%
1.72 +static const unsigned char BRIGHT_075 = 0x16; // Brightness 75%
1.73 +static const unsigned char BRIGHT_087 = 0x17; // Brightness 87.5%
1.74 +static const unsigned char BRIGHT_100 = 0x18; // Brightness 100%
1.75 +
1.76 +static const unsigned char nSETCURSOR0 = 0x1f; // Set cursor (CMD prefix)
1.77 +static const unsigned char nSETCURSOR1 = 0x24; // Set cursor (CMD)
1.78 +
1.79 +static const unsigned char nDISPLAYCURSOR0 = 0x1f; // display cursor
1.80 +static const unsigned char nDISPLAYCURSOR1 = 0x43; // display cursor
1.81 +
1.82 +static const unsigned char nBLITIMAGE0 = 0x1f; // Display image
1.83 +static const unsigned char nBLITIMAGE1 = 0x28; // Display image
1.84 +static const unsigned char nBLITIMAGE2 = 0x66; // Display image
1.85 +static const unsigned char nBLITIMAGE3 = 0x11; // Display image
1.86 +
1.87 +static const unsigned char dBLITIMAGE0 = 0x02; // Image write
1.88 +static const unsigned char dBLITIMAGE1 = 0x44; // Image write
1.89 +static const unsigned char dBLITIMAGE2 = 0x00; // Image write
1.90 +static const unsigned char dBLITIMAGE3 = 0x46; // Image write
1.91 +
1.92 +
1.93 +static const unsigned char WRHI = 0x0f; // any control pin to high
1.94 +static const unsigned char WRLO = 0x00;
1.95 +static const unsigned char RDYHI = 0x40; // RDY
1.96 +static const unsigned char RDYHIALT = 0x80; // RDY satyr wiring
1.97 +static const unsigned char RDYLO = 0x00;
1.98 +
1.99 +static const std::string kWiringStandard = "Standard";
1.100 +static const std::string kWiringSatyr = "Satyr";
1.101 +
1.102 +static const int kInterfaceParallel = 0; // parallel mode
1.103 +static const int kInterfaceSerial = 1; // serial mode
1.104 +
1.105 +
1.106 +cDriverGU256X64_3900::cDriverGU256X64_3900(cDriverConfig * config)
1.107 +: config(config)
1.108 +{
1.109 + oldConfig = new cDriverConfig(*config);
1.110 +
1.111 + portFd = -1;
1.112 + m_nRefreshCounter = 0;
1.113 +}
1.114 +
1.115 +cDriverGU256X64_3900::~cDriverGU256X64_3900()
1.116 +{
1.117 + delete oldConfig;
1.118 +}
1.119 +
1.120 +int cDriverGU256X64_3900::Init()
1.121 +{
1.122 + int x;
1.123 +
1.124 + width = config->width;
1.125 + if (width <= 0)
1.126 + width = 256;
1.127 + height = config->height;
1.128 + if (height <= 0)
1.129 + height = 64;
1.130 + m_iSizeYb = ((height + 7) / 8);
1.131 +
1.132 + // default values
1.133 + readyMask = RDYHI;
1.134 + readyHi = RDYHI;
1.135 + interface = kInterfaceParallel;
1.136 + useDMA = true;
1.137 +
1.138 + for (unsigned int i = 0; i < config->options.size(); i++)
1.139 + {
1.140 + if (config->options[i].name == "Wiring")
1.141 + {
1.142 + if (config->options[i].value == kWiringStandard)
1.143 + {
1.144 + readyMask = RDYHI;
1.145 + readyHi = RDYHI;
1.146 + }
1.147 + else if (config->options[i].value == kWiringSatyr)
1.148 + {
1.149 + readyMask = RDYHIALT;
1.150 + readyHi = RDYLO;
1.151 + }
1.152 + else
1.153 + syslog(LOG_ERR, "%s error: wiring %s not supported, using default (Standard)!\n",
1.154 + config->name.c_str(), config->options[i].value.c_str());
1.155 + }
1.156 + if (config->options[i].name == "Interface")
1.157 + {
1.158 + if (config->options[i].value == "Parallel")
1.159 + interface = kInterfaceParallel;
1.160 + else if (config->options[i].value == "Serial")
1.161 + interface = kInterfaceSerial;
1.162 + else
1.163 + syslog(LOG_ERR, "%s error: interface %s not supported, using default (Parallel)!\n",
1.164 + config->name.c_str(), config->options[i].value.c_str());
1.165 + }
1.166 + else if (config->options[i].name == "DMA")
1.167 + {
1.168 + if (config->options[i].value == "yes")
1.169 + useDMA = true;
1.170 + else if (config->options[i].value == "no")
1.171 + useDMA = false;
1.172 + else
1.173 + syslog(LOG_ERR, "%s error: unknown DMA setting %s, using default (%s)!\n",
1.174 + config->name.c_str(), config->options[i].value.c_str(), useDMA ? "yes" : "no");
1.175 + }
1.176 + }
1.177 +
1.178 + if (interface == kInterfaceParallel)
1.179 + port = new cParallelPort();
1.180 + else
1.181 + port = NULL;
1.182 +
1.183 + // setup linear lcd array
1.184 + m_pDrawMem = new unsigned char *[width];
1.185 + if (m_pDrawMem)
1.186 + {
1.187 + for (x = 0; x < width; x++)
1.188 + {
1.189 + m_pDrawMem[x] = new unsigned char[m_iSizeYb];
1.190 + memset(m_pDrawMem[x], 0, m_iSizeYb);
1.191 + }
1.192 + }
1.193 + Clear();
1.194 +
1.195 + // setup the lcd array for the "vertical" mem
1.196 + m_pVFDMem = new unsigned char *[width];
1.197 + if (m_pVFDMem)
1.198 + {
1.199 + for (x = 0; x < width; x++)
1.200 + {
1.201 + m_pVFDMem[x] = new unsigned char[m_iSizeYb];
1.202 + memset(m_pVFDMem[x], 0, m_iSizeYb);
1.203 + }
1.204 + }
1.205 + ClearVFDMem();
1.206 +
1.207 + if (interface == kInterfaceSerial)
1.208 + {
1.209 + if (InitSerialPort() < 0)
1.210 + return -1;
1.211 + }
1.212 + else
1.213 + {
1.214 + if (InitParallelPort() < 0)
1.215 + return -1;
1.216 + }
1.217 +
1.218 + if (useDMA)
1.219 + InitDMADisplay();
1.220 + else
1.221 + InitNormalDisplay();
1.222 +
1.223 + if (interface == kInterfaceParallel)
1.224 + {
1.225 + // claim is in InitParallelPort
1.226 + port->Release();
1.227 + }
1.228 +
1.229 + *oldConfig = *config;
1.230 +
1.231 + // Set Display SetBrightness
1.232 + SetBrightness(config->brightness);
1.233 + // clear display
1.234 + Clear();
1.235 + ClearVFDMem();
1.236 +
1.237 + syslog(LOG_INFO, "%s: gu256x64-3900 initialized.\n", config->name.c_str());
1.238 + return 0;
1.239 +}
1.240 +
1.241 +int cDriverGU256X64_3900::DeInit()
1.242 +{
1.243 + int x;
1.244 +
1.245 + if (m_pVFDMem)
1.246 + {
1.247 + for (x = 0; x < width; x++)
1.248 + {
1.249 + delete[] m_pVFDMem[x];
1.250 + }
1.251 + delete[] m_pVFDMem;
1.252 + }
1.253 + if (m_pDrawMem)
1.254 + {
1.255 + for (x = 0; x < width; x++)
1.256 + {
1.257 + delete[] m_pDrawMem[x];
1.258 + }
1.259 + delete[] m_pDrawMem;
1.260 + }
1.261 +
1.262 + if (interface == kInterfaceSerial)
1.263 + {
1.264 + if (portFd >= 0)
1.265 + {
1.266 + close(portFd);
1.267 + portFd =- 1;
1.268 + }
1.269 + }
1.270 + if (port)
1.271 + {
1.272 + if (port->Close() != 0)
1.273 + {
1.274 + return -1;
1.275 + }
1.276 + delete port;
1.277 + port = NULL;
1.278 + }
1.279 + return 0;
1.280 +}
1.281 +
1.282 +int cDriverGU256X64_3900::CheckSetup()
1.283 +{
1.284 + if (config->device != oldConfig->device ||
1.285 + config->port != oldConfig->port ||
1.286 + config->width != oldConfig->width ||
1.287 + config->height != oldConfig->height)
1.288 + {
1.289 + DeInit();
1.290 + Init();
1.291 + return 0;
1.292 + }
1.293 +
1.294 + if (config->brightness != oldConfig->brightness)
1.295 + {
1.296 + oldConfig->brightness = config->brightness;
1.297 + SetBrightness(config->brightness);
1.298 + }
1.299 + if (config->upsideDown != oldConfig->upsideDown ||
1.300 + config->invert != oldConfig->invert)
1.301 + {
1.302 + oldConfig->upsideDown = config->upsideDown;
1.303 + oldConfig->invert = config->invert;
1.304 + return 1;
1.305 + }
1.306 + return 0;
1.307 +}
1.308 +
1.309 +int cDriverGU256X64_3900::InitSerialPort()
1.310 +{
1.311 + if (config->device == "")
1.312 + {
1.313 + syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!\n", config->name.c_str());
1.314 + return -1;
1.315 + }
1.316 +
1.317 + portFd = open(config->device.c_str(), O_RDWR | O_NOCTTY);
1.318 + if (portFd >= 0)
1.319 + {
1.320 + struct termios options;
1.321 + tcgetattr(portFd, &options);
1.322 + cfsetispeed(&options, B38400);
1.323 + cfsetospeed(&options, B38400);
1.324 + options.c_cflag &= ~CSIZE;
1.325 + options.c_cflag &= ~PARENB;
1.326 + options.c_cflag &= ~CSTOPB;
1.327 + options.c_cflag |= CS8;
1.328 + tcsetattr(portFd, TCSANOW, &options);
1.329 + }
1.330 + else
1.331 + {
1.332 + syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!\n", config->name.c_str());
1.333 + return -1;
1.334 + }
1.335 + return 0;
1.336 +}
1.337 +
1.338 +int cDriverGU256X64_3900::InitParallelPort()
1.339 +{
1.340 + struct timeval tv1, tv2;
1.341 +
1.342 + if (config->device == "")
1.343 + {
1.344 + // use DirectIO
1.345 + if (port->Open(config->port) != 0)
1.346 + {
1.347 + syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!\n", config->name.c_str());
1.348 + return -1;
1.349 + }
1.350 + uSleep(10);
1.351 + }
1.352 + else
1.353 + {
1.354 + // use ppdev
1.355 + if (port->Open(config->device.c_str()) != 0)
1.356 + {
1.357 + syslog(LOG_ERR, "%s: unable to initialize gu256x64-3900!\n", config->name.c_str());
1.358 + return -1;
1.359 + }
1.360 + }
1.361 +
1.362 + if (nSleepInit() != 0)
1.363 + {
1.364 + syslog(LOG_ERR, "%s: INFO: cannot change wait parameters Err: %s (cDriver::Init)\n", config->name.c_str(), strerror(errno));
1.365 + m_bSleepIsInit = false;
1.366 + }
1.367 + else
1.368 + {
1.369 + m_bSleepIsInit = true;
1.370 + }
1.371 +
1.372 + port->Claim();
1.373 +
1.374 + syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
1.375 + gettimeofday(&tv1, 0);
1.376 + for (int x = 0; x < 1000; x++)
1.377 + {
1.378 + port->WriteData(x % 0x100);
1.379 + }
1.380 + gettimeofday(&tv2, 0);
1.381 + nSleepDeInit();
1.382 + m_nTimingAdjustCmd = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec);
1.383 + syslog(LOG_INFO, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), m_nTimingAdjustCmd);
1.384 +
1.385 + return 0;
1.386 +}
1.387 +
1.388 +void cDriverGU256X64_3900::InitNormalDisplay()
1.389 +{
1.390 + Write(nPOWER0);
1.391 + Write(nPOWER1);
1.392 + Write(nPOWER2);
1.393 + Write(nPOWER3);
1.394 + Write(1); // power on
1.395 +
1.396 + Write(nINITDISPLAY0);
1.397 + Write(nINITDISPLAY1);
1.398 +
1.399 + Write(nDISPLAYCURSOR0);
1.400 + Write(nDISPLAYCURSOR1);
1.401 + Write(0); // off
1.402 +
1.403 + Write(nSETCURSOR0);
1.404 + Write(nSETCURSOR1);
1.405 + Write(0); // low byte x
1.406 + Write(0); // high byte x
1.407 + Write(0); // low byte y
1.408 + Write(0); // high byte y
1.409 +}
1.410 +
1.411 +void cDriverGU256X64_3900::InitDMADisplay()
1.412 +{
1.413 + Write(dSETSTART0);
1.414 + Write(dSETSTART1);
1.415 + Write(dSETSTART2);
1.416 + Write(dSETSTART3);
1.417 + Write(0);
1.418 + Write(0);
1.419 +}
1.420 +
1.421 +void cDriverGU256X64_3900::ClearVFDMem()
1.422 +{
1.423 + for (int x = 0; x < width; x++)
1.424 + memset(m_pVFDMem[x], 0, m_iSizeYb);
1.425 +}
1.426 +
1.427 +void cDriverGU256X64_3900::Clear()
1.428 +{
1.429 + for (int x = 0; x < width; x++)
1.430 + memset(m_pDrawMem[x], 0, m_iSizeYb);
1.431 +}
1.432 +
1.433 +void cDriverGU256X64_3900::SetBrightness(unsigned int percent)
1.434 +{
1.435 + if (interface == kInterfaceParallel)
1.436 + port->Claim();
1.437 +
1.438 + if (interface == kInterfaceParallel && useDMA)
1.439 + {
1.440 + Write(dSETBRIGHT0);
1.441 + Write(dSETBRIGHT1);
1.442 + Write(dSETBRIGHT2);
1.443 + Write(dSETBRIGHT3);
1.444 + }
1.445 + else
1.446 + {
1.447 + Write(nSETBRIGHT0);
1.448 + Write(nSETBRIGHT1);
1.449 + }
1.450 + if (percent > 87) {
1.451 + Write(BRIGHT_100);
1.452 + } else if (percent > 75) {
1.453 + Write(BRIGHT_087);
1.454 + } else if (percent > 62) {
1.455 + Write(BRIGHT_075);
1.456 + } else if (percent > 50) {
1.457 + Write(BRIGHT_062);
1.458 + } else if (percent > 37) {
1.459 + Write(BRIGHT_050);
1.460 + } else if (percent > 25) {
1.461 + Write(BRIGHT_037);
1.462 + } else if (percent > 12) {
1.463 + Write(BRIGHT_025);
1.464 + } else if (percent > 1) {
1.465 + Write(BRIGHT_012);
1.466 + } else {
1.467 + Write(BRIGHT_000);
1.468 + }
1.469 + if (interface == kInterfaceParallel)
1.470 + port->Release();
1.471 +}
1.472 +
1.473 +void cDriverGU256X64_3900::WriteParallel(unsigned char data)
1.474 +{
1.475 + if (m_bSleepIsInit)
1.476 + nSleepInit();
1.477 + if ((port->ReadStatus() & readyMask) != readyHi)
1.478 + {
1.479 + int i = 0;
1.480 + int status = port->ReadStatus();
1.481 + for (; ((status&readyMask) != readyHi) && i < 1000; i++)
1.482 + {
1.483 + // wait until display ack's write but not forever
1.484 + status=port->ReadStatus();
1.485 + }
1.486 + }
1.487 +
1.488 + port->WriteControl(WRLO);
1.489 + port->WriteData(data);
1.490 + nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
1.491 + port->WriteControl(WRHI);
1.492 + nSleep(500 + (100 * config->adjustTiming) - m_nTimingAdjustCmd);
1.493 +}
1.494 +
1.495 +void cDriverGU256X64_3900::WriteSerial(unsigned char data)
1.496 +{
1.497 + write(portFd, &data, 1);
1.498 +}
1.499 +
1.500 +void cDriverGU256X64_3900::Write(unsigned char data)
1.501 +{
1.502 + if (interface == kInterfaceSerial)
1.503 + WriteSerial(data);
1.504 + else
1.505 + WriteParallel(data);
1.506 +}
1.507 +
1.508 +void cDriverGU256X64_3900::SetPixel(int x, int y)
1.509 +{
1.510 + unsigned char c;
1.511 +
1.512 + if (!m_pDrawMem)
1.513 + return;
1.514 +
1.515 + if (x >= width || x < 0)
1.516 + return;
1.517 + if (y >= height || y < 0)
1.518 + return;
1.519 +
1.520 + if (config->upsideDown)
1.521 + {
1.522 + x = width - 1 - x;
1.523 + y = height - 1 - y;
1.524 + }
1.525 +
1.526 + c = 0x80 >> (y % 8);
1.527 +
1.528 + m_pDrawMem[x][y/8] = m_pDrawMem[x][y/8] | c;
1.529 +}
1.530 +
1.531 +void cDriverGU256X64_3900::Set8Pixels(int x, int y, unsigned char data)
1.532 +{
1.533 + int n;
1.534 +
1.535 + // x - pos is'nt maybe align to 8
1.536 + x &= 0xFFF8;
1.537 +
1.538 + for (n = 0; n < 8; ++n)
1.539 + {
1.540 + if (data & (0x80 >> n)) // if bit is set
1.541 + SetPixel(x + n, y);
1.542 + }
1.543 +}
1.544 +
1.545 +void cDriverGU256X64_3900::Refresh(bool refreshAll)
1.546 +{
1.547 + int xb, yb;
1.548 +
1.549 + if (!m_pVFDMem || !m_pDrawMem)
1.550 + return;
1.551 +
1.552 + bool doRefresh = false;
1.553 + int minX = width;
1.554 + int maxX = 0;
1.555 + int minYb = m_iSizeYb;
1.556 + int maxYb = 0;
1.557 +
1.558 + if (CheckSetup() > 0)
1.559 + refreshAll = true;
1.560 +
1.561 + for (xb = 0; xb < width; ++xb)
1.562 + {
1.563 + for (yb = 0; yb < m_iSizeYb; ++yb)
1.564 + {
1.565 + if (m_pVFDMem[xb][yb] != m_pDrawMem[xb][yb])
1.566 + {
1.567 + m_pVFDMem[xb][yb] = m_pDrawMem[xb][yb];
1.568 + minX = std::min(minX, xb);
1.569 + maxX = std::max(maxX, xb);
1.570 + minYb = std::min(minYb, yb);
1.571 + maxYb = std::max(maxYb, yb + 1);
1.572 + doRefresh = true;
1.573 + }
1.574 + }
1.575 + }
1.576 +
1.577 + if (config->refreshDisplay > 0)
1.578 + {
1.579 + m_nRefreshCounter = (m_nRefreshCounter + 1) % config->refreshDisplay;
1.580 + if (!refreshAll && !m_nRefreshCounter)
1.581 + refreshAll = true;
1.582 + }
1.583 +
1.584 + if (refreshAll || doRefresh)
1.585 + {
1.586 + if (refreshAll)
1.587 + {
1.588 + minX = 0;
1.589 + maxX = width;
1.590 + minYb = 0;
1.591 + maxYb = m_iSizeYb;
1.592 + // and reset RefreshCounter
1.593 + m_nRefreshCounter = 0;
1.594 + }
1.595 +
1.596 + minX = std::max(minX, 0);
1.597 + maxX = std::min(maxX, width - 1);
1.598 + minYb = std::max(minYb, 0);
1.599 + maxYb = std::min(maxYb, m_iSizeYb);
1.600 +
1.601 + if (interface == kInterfaceParallel)
1.602 + port->Claim();
1.603 +
1.604 + if (interface == kInterfaceParallel && useDMA)
1.605 + {
1.606 + Write(dBLITIMAGE0);
1.607 + Write(dBLITIMAGE1);
1.608 + Write(dBLITIMAGE2);
1.609 + Write(dBLITIMAGE3);
1.610 + Write(0); // low byte address
1.611 + Write(0); // high byte address
1.612 + Write((m_iSizeYb*width)&0xff); // low byte size
1.613 + Write((m_iSizeYb*width)>>8); // high byte size
1.614 + }
1.615 + else
1.616 + {
1.617 + Write(nSETCURSOR0);
1.618 + Write(nSETCURSOR1);
1.619 + Write(0); // low byte x
1.620 + Write(0); // high byte x
1.621 + Write(0); // low byte y
1.622 + Write(0); // high byte y
1.623 +
1.624 + Write(nBLITIMAGE0);
1.625 + Write(nBLITIMAGE1);
1.626 + Write(nBLITIMAGE2);
1.627 + Write(nBLITIMAGE3);
1.628 + Write(width&0xff); // low byte width
1.629 + Write(width>>8); // high byte width
1.630 + Write(m_iSizeYb); // low byte height
1.631 + Write(0); // high byte height
1.632 + Write(1); // end header
1.633 + }
1.634 +
1.635 + for (xb = 0; xb < width; xb++)
1.636 + {
1.637 + for (yb = 0; yb < m_iSizeYb; yb++)
1.638 + {
1.639 + Write((m_pVFDMem[xb][yb]) ^ (config->invert ? 0xff : 0x00));
1.640 + }
1.641 + // parallel port writing is busy waiting - with realtime priority you
1.642 + // can lock the system - so don't be so greedy ;)
1.643 + if ((xb % 32) == 31)
1.644 + {
1.645 + uSleep(1000);
1.646 + }
1.647 + }
1.648 +
1.649 + if (interface == kInterfaceParallel)
1.650 + port->Release();
1.651 + }
1.652 +}
1.653 +
1.654 +} // end of namespace