From 2aecdd4c59213c94f7709983a7824a9d8fa4e79c Mon Sep 17 00:00:00 2001 From: marschap Date: Tue, 25 Sep 2007 16:19:42 +0000 Subject: [PATCH] overhaul for the NoritakeVFD driver (idea by Richard Moratti): - Fixed vbar & hbar - Allowed for displays with 2 custom characters - Fixed cursor off - 16H - Data sheet for CU20045SCPB has error -> Cursor Off 14,16,17H - Tested with CU40026SCPB-T20A - 40x2 - Hardware Defaults to 19200 8E1 - Added new config parameter [Parity] to set serial data parity 0(none),1(odd),2(even) - Added config parameter OffBrightness - added support for big numbers --- ChangeLog | 1 + LCDd.conf | 17 +- docs/lcdproc-user/drivers/NoritakeVFD.docbook | 14 + server/drivers/Makefile.am | 4 +- server/drivers/NoritakeVFD.c | 955 ++++++++++-------- server/drivers/NoritakeVFD.h | 19 +- 6 files changed, 563 insertions(+), 447 deletions(-) diff --git a/ChangeLog b/ChangeLog index a700518..b48ecd3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,7 @@ v.0.5dev (ongoing development) * fixes for the lcpdroc client iface screen on *BSD (M.Dolze) + key support for hd44780/lcd2usb (M. Dolze) + option Priority for NoritakeVFD (idea: Richard Muratti) + * overhauled NoritakeVFD driver (idea: Richard Muratti) v.0.5.2 * fix switching on/off the Load screen in lcdproc client using the menu diff --git a/LCDd.conf b/LCDd.conf index c3a384e..fe57113 100644 --- a/LCDd.conf +++ b/LCDd.conf @@ -734,21 +734,20 @@ keypad_test_mode=no [NoritakeVFD] # device where the VFD is. Usual values are /dev/ttyS0 and /dev/ttyS1 [default: /dev/lcd] Device=/dev/ttyS0 - # Specifies the size of the LCD. Size=20x4 - -# set the brightness -Brightness=255 - +# Set the initial brightness [default: 1000; legal: 0 - 1000] +Brightness=1000 +# Set the initial off-brightness [default: 0; legal: 0 - 1000] +# This value is used when the display is normally +# switched off in case LCDd is inactive +OffBrightness=50 # set the serial port speed [default: 9600, legal: 1200, 2400, 9600, 19200, 115200] Speed=9600 - # Set serial data parity [default: 0 (None), legal: 0(=none), 1(=odd), 2(=even)] Parity=0 - -# re-initialize VFD ? -#Reboot=yes +# re-initialize the VFD [default: no; legal: yes, no] +Reboot=no diff --git a/docs/lcdproc-user/drivers/NoritakeVFD.docbook b/docs/lcdproc-user/drivers/NoritakeVFD.docbook index 1416d12..fcf44f5 100644 --- a/docs/lcdproc-user/drivers/NoritakeVFD.docbook +++ b/docs/lcdproc-user/drivers/NoritakeVFD.docbook @@ -46,6 +46,19 @@ This section talks about using LCDproc with text mode VFD displays from BRIGHTNESS + Set the initial brightness [default: 1000; legal: 0 - 1000] + + + + + + OffBrightness= + BRIGHTNESS + + + Set the initial off-brightness [default: 0; legal: 0 - 1000] + This value is used when the display is normally + switched off in case LCDd is inactive @@ -97,6 +110,7 @@ This section talks about using LCDproc with text mode VFD displays from + Reinitialize the VFD [default: no; legal: yes, no] diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am index 2b6d347..23f8e75 100644 --- a/server/drivers/Makefile.am +++ b/server/drivers/Makefile.am @@ -47,7 +47,7 @@ lis_LDADD = libLCD.a @LIBFTDI@ libbignum.a MD8800_LDADD = libLCD.a mtc_s16209x_LDADD = libLCD.a MtxOrb_LDADD = libLCD.a libbignum.a -NoritakeVFD_LDADD = libLCD.a +NoritakeVFD_LDADD = libLCD.a libbignum.a picolcd_LDADD = @libusb_libs@ libLCD.a libbignum.a pyramid_LDADD = libLCD.a serialPOS_LDADD = libLCD.a libbignum.a @@ -91,7 +91,7 @@ MD8800_SOURCES = lcd.h lcd_lib.h MD8800.c MD8800.h report.h ms6931_SOURCES = lcd.h lcd_lib.h ms6931.h ms6931.c report.h mtc_s16209x_SOURCES = lcd.h lcd_lib.h mtc_s16209x.c mtc_s16209x.h report.h MtxOrb_SOURCES = lcd.h lcd_lib.h MtxOrb.c MtxOrb.h report.h adv_bignum.h -NoritakeVFD_SOURCES = lcd.h lcd_lib.h NoritakeVFD.c NoritakeVFD.h report.h +NoritakeVFD_SOURCES = lcd.h lcd_lib.h NoritakeVFD.c NoritakeVFD.h report.h adv_bignum.h picolcd_SOURCES = lcd.h picolcd.h picolcd.c report.h pyramid_SOURCES = lcd.h pylcd.c pylcd.h sed1330_SOURCES = lcd.h sed1330.h sed1330.c port.h lpt-port.h timing.h report.h diff --git a/server/drivers/NoritakeVFD.c b/server/drivers/NoritakeVFD.c index 986b17d..cea6fac 100644 --- a/server/drivers/NoritakeVFD.c +++ b/server/drivers/NoritakeVFD.c @@ -1,10 +1,34 @@ /* This is the LCDproc driver for Noritake VFD Device CU20045SCPB-T28A Copyright (C) 2005 Simon Funke + Copyright (C) 2007 Richard Muratti ricacho@gmail.com + Copyright (C) 2007 Peter Marschall + This source Code is based on CFontz Driver of this package. 2005-08-01 Version 0.1: mostly everything should work (vbar, hbar never tested) + 2007-09-16 Version 0.2: + - Fixed vbar & hbar - Allowed for displays with 2 custom characters + - Fixed cursor off - 16H - Data sheet for CU20045SCPB has error -> Cursor Off 14,16,17H + - Tested with CU40026SCPB-T20A - 40x2 - Hardware Defaults to 19200 8E1 + - Added new config parameter [Parity] to set serial data parity 0(none),1(odd),2(even) + - Added config parameter OffBrightness + - added support for big numbers + + CU40026SCPB-T20A SOFTWARE COMMANDS + Back Space 08H International Font 18H + Horizontal Tab 09H Katakana Font 19H + Line Feed 0AH Escape 1BH + Form Feed 0CH Send User Font +43H + Carriage Return 0DH Position cursor +48H + Clear Display 0EH Software Reset +49H + Increment Write Mode 11H Luminance +4CH + Vertical Scroll Mode 12H Flickerless Write +53H + Underline Cursor On 14H Cursor Blink Speed +54H + 5x7 Block Cursor On 15H Character Data 20H+ + Cursor Off 16H User Character Data 00H+ + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -35,18 +59,20 @@ #include "lcd.h" #include "NoritakeVFD.h" - #include "report.h" #include "lcd_lib.h" +#include "adv_bignum.h" + /* Constants for userdefchar_mode */ -#define NUM_CCs 8 /* max. number of custom characters */ +#define NUM_CCs 2 /* max. number of custom characters */ typedef enum { standard, /* only char 0 is used for heartbeat */ vbar, /* vertical bars */ hbar, /* horizontal bars */ custom, /* custom settings */ + bignum, /* big numbers */ } CGmode; typedef struct driver_private_data { @@ -63,6 +89,7 @@ typedef struct driver_private_data { /* defineable characters */ CGmode ccmode; int brightness; + int offbrightness; } PrivateData; /* Vars for the server core */ @@ -71,18 +98,20 @@ MODULE_EXPORT int stay_in_foreground = 0; MODULE_EXPORT int supports_multiple = 0; MODULE_EXPORT char *symbol_prefix = "NoritakeVFD_"; + /* Internal functions */ static void NoritakeVFD_autoscroll (Driver *drvthis, int on); static void NoritakeVFD_hidecursor (Driver *drvthis); static void NoritakeVFD_reboot (Driver *drvthis); -static void NoritakeVFD_init_vbar (Driver *drvthis); -static void NoritakeVFD_init_hbar (Driver *drvthis); -static void NoritakeVFD_draw_frame (Driver *drvthis, unsigned char *dat); -//static void NoritakeVFD_heartbeat (Driver *drvthis, int type); +static void NoritakeVFD_cursor_goto (Driver *drvthis, int x, int y); -// Opens com port and sets baud correctly... -// +/** + * Initialize the driver. + * \param drvthis Pointer to driver structure. + * \retval 0 Success. + * \retval <0 Error. + */ MODULE_EXPORT int NoritakeVFD_init (Driver *drvthis) { @@ -136,6 +165,15 @@ NoritakeVFD_init (Driver *drvthis) } p->brightness = tmp; + /* Which backlight-off "brightness" */ + tmp = drvthis->config_get_int(drvthis->name, "OffBrightness", 0, DEFAULT_OFFBRIGHTNESS); + debug(RPT_INFO, "%s: OffBrightness (in config) is '%d'", __FUNCTION__, tmp); + if ((tmp < 0) || (tmp > 1000)) { + report(RPT_WARNING, "%s: OffBrightness must be between 0 and 1000; using default %d", + drvthis->name, DEFAULT_OFFBRIGHTNESS); + tmp = DEFAULT_OFFBRIGHTNESS; + } + p->offbrightness = tmp; /* Which speed */ tmp = drvthis->config_get_int(drvthis->name, "Speed", 0, DEFAULT_SPEED); @@ -150,7 +188,6 @@ NoritakeVFD_init (Driver *drvthis) else if (tmp == 19200) p->speed = B19200; else if (tmp == 115200) p->speed = B115200; - /* Which parity */ tmp = drvthis->config_get_int(drvthis->name, "Parity", 0, DEFAULT_PARITY); if ((tmp != 0) && (tmp != 1) && (tmp != 2) ) { @@ -159,7 +196,7 @@ NoritakeVFD_init (Driver *drvthis) tmp = DEFAULT_PARITY; } if (tmp != 0) - p->parity = (tmp & 1) ? (PARENB | PARODD) : PARENB; + p->parity = (tmp & 1) ? (PARENB | PARODD) : PARENB; /* Reboot display? */ @@ -223,8 +260,8 @@ NoritakeVFD_init (Driver *drvthis) sleep(4); } NoritakeVFD_hidecursor(drvthis); - NoritakeVFD_set_brightness(drvthis, 1, p->brightness); NoritakeVFD_autoscroll(drvthis, 0); + NoritakeVFD_set_brightness(drvthis, 1, p->brightness); report(RPT_DEBUG, "%s: init() done", drvthis->name); @@ -232,9 +269,11 @@ NoritakeVFD_init (Driver *drvthis) } -///////////////////////////////////////////////////////////////// -// Clean-up -// + +/** + * Close the driver (do necessary clean-up). + * \param drvthis Pointer to driver structure. + */ MODULE_EXPORT void NoritakeVFD_close (Driver *drvthis) { @@ -253,8 +292,11 @@ NoritakeVFD_close (Driver *drvthis) drvthis->store_private_ptr(drvthis, NULL); } -/* - * Returns the display width in characters + +/** + * Return the display width in characters. + * \param drvthis Pointer to driver structure. + * \return Number of characters the display is wide. */ MODULE_EXPORT int NoritakeVFD_width (Driver *drvthis) @@ -265,8 +307,10 @@ NoritakeVFD_width (Driver *drvthis) } -/* - * Returns the display height in characters +/** + * Return the display height in characters. + * \param drvthis Pointer to driver structure. + * \return Number of characters the display is high. */ MODULE_EXPORT int NoritakeVFD_height (Driver *drvthis) @@ -277,8 +321,10 @@ NoritakeVFD_height (Driver *drvthis) } -/* - * Returns the width of a character in pixels +/** + * Return the width of a character in pixels. + * \param drvthis Pointer to driver structure. + * \return Number of pixel columns a character cell is wide. */ MODULE_EXPORT int NoritakeVFD_cellwidth (Driver *drvthis) @@ -289,8 +335,10 @@ NoritakeVFD_cellwidth (Driver *drvthis) } -/* - * Returns the height of a character in pixels +/** + * Return the height of a character in pixels. + * \param drvthis Pointer to driver structure. + * \return Number of pixel lines a character cell is high. */ MODULE_EXPORT int NoritakeVFD_cellheight (Driver *drvthis) @@ -301,394 +349,35 @@ NoritakeVFD_cellheight (Driver *drvthis) } +/** + * Flush data on screen to the LCD. + * \param drvthis Pointer to driver structure. + */ MODULE_EXPORT void NoritakeVFD_flush (Driver *drvthis) { PrivateData *p = drvthis->private_data; - NoritakeVFD_draw_frame(drvthis, p->framebuf); -} - - -///////////////////////////////////////////////////////////////// -// Prints a character on the lcd display, at position (x,y). The -// upper-left is (1,1), and the lower right should be (20,4). -// -MODULE_EXPORT void -NoritakeVFD_chr (Driver *drvthis, int x, int y, char c) -{ - PrivateData *p = drvthis->private_data; - - y--; - x--; - /*if (c < 32 && (int)c >= 0) - c += 128;*/ - p->framebuf[(y * p->width) + x ] = c; - //NoritakeVFD->framebuf[ 19 ] = c; -} - -///////////////////////////////////////////////////////////////// -/* - * Retrieves brightness - */ -MODULE_EXPORT int -NoritakeVFD_get_brightness(Driver *drvthis, int state) -{ - PrivateData *p = drvthis->private_data; - - return p->brightness; -} - -///////////////////////////////////////////////////////////////// -// Changes screen brightness (0-255; 140 seems good) -// -MODULE_EXPORT void -NoritakeVFD_set_brightness (Driver *drvthis, int state, int brightness) -{ - PrivateData *p = drvthis->private_data; - int realbrightness = -1; - char out[5]; - - if (brightness > 0) { - realbrightness = (int) (140 * 100 / 255); - snprintf(out, sizeof(out), "%c%c%c", 0x1B, 'L', brightness); - write(p->fd, out, 3); - } - p->brightness = brightness; -} - - -///////////////////////////////////////////////////////////////// -// Toggle the built-in automatic scrolling feature -// -static void -NoritakeVFD_autoscroll (Driver *drvthis, int on) -{ - PrivateData *p = drvthis->private_data; - char out[4]; - - snprintf(out, sizeof(out), "%c", (on) ? 0x12 : 0x11); - write(p->fd, out, 1); -} - -///////////////////////////////////////////////////////////////// -// Get rid of the blinking cursor -// -static void -NoritakeVFD_hidecursor (Driver *drvthis) -{ - PrivateData *p = drvthis->private_data; - char out[4]; - - snprintf(out, sizeof(out), "%c", 0x14); - write(p->fd, out, 1); -} - -///////////////////////////////////////////////////////////////// -// Reset the display bios -// -static void -NoritakeVFD_reboot (Driver *drvthis) -{ - PrivateData *p = drvthis->private_data; - char out[4]; - - snprintf(out, sizeof(out), "%c%c", 0x1B, 'I'); - write(p->fd, out, 2); -} - -///////////////////////////////////////////////////////////////// -// Sets up for vertical bars. Call before NoritakeVFD->vbar() -// -static void -NoritakeVFD_init_vbar (Driver *drvthis) -{ - PrivateData *p = drvthis->private_data; - char a[] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, - }; - char b[] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - }; - char c[] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - }; - char d[] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - }; - char e[] = { - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - }; - char f[] = { - 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - }; - - if (p->ccmode != hbar) { - p->ccmode = hbar; - NoritakeVFD_set_char(drvthis, 2, a); - NoritakeVFD_set_char(drvthis, 3, b); - NoritakeVFD_set_char(drvthis, 4, c); - NoritakeVFD_set_char(drvthis, 5, d); - NoritakeVFD_set_char(drvthis, 6, e); - NoritakeVFD_set_char(drvthis, 7, f); - } -} - -///////////////////////////////////////////////////////////////// -// Inits horizontal bars... -// -static void -NoritakeVFD_init_hbar (Driver *drvthis) -{ - PrivateData *p = drvthis->private_data; - char a[] = { - 1, 0, 0, 0, 0, - 1, 0, 0, 0, 0, - 1, 0, 0, 0, 0, - 1, 0, 0, 0, 0, - 1, 0, 0, 0, 0, - 1, 0, 0, 0, 0, - 1, 0, 0, 0, 0, - }; - char b[] = { - 1, 1, 0, 0, 0, - 1, 1, 0, 0, 0, - 1, 1, 0, 0, 0, - 1, 1, 0, 0, 0, - 1, 1, 0, 0, 0, - 1, 1, 0, 0, 0, - 1, 1, 0, 0, 0, - }; - char c[] = { - 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, - }; - char d[] = { - 1, 1, 1, 1, 0, - 1, 1, 1, 1, 0, - 1, 1, 1, 1, 0, - 1, 1, 1, 1, 0, - 1, 1, 1, 1, 0, - 1, 1, 1, 1, 0, - 1, 1, 1, 1, 0, - }; - - if (p->ccmode != hbar) { - p->ccmode = hbar; - NoritakeVFD_set_char(drvthis, 2, a); - NoritakeVFD_set_char(drvthis, 3, b); - NoritakeVFD_set_char(drvthis, 4, c); - NoritakeVFD_set_char(drvthis, 5, d); - } -} - -///////////////////////////////////////////////////////////////// -// Draws a vertical bar... -// -MODULE_EXPORT void -NoritakeVFD_vbar (Driver *drvthis, int x, int y, int len, int promille, int options) -{ -/* PrivateData *p = drvthis->private_data; - char map[8] = { 32, 1, 2, 3, 4, 5, 6, 255 }; - - int y; - for (y = p->height; y > 0 && len > 0; y--) { - if (len >= p->cellheight) - NoritakeVFD_chr (drvthis, x, y, 255); - else - NoritakeVFD_chr (drvthis, x, y, map[len]); - - len -= p->cellheight; - }*/ - - NoritakeVFD_init_vbar(drvthis); - //lib_vbar_static(drvthis, x, y, len, promille, options, p->cellwidth, 0); -} - -///////////////////////////////////////////////////////////////// -// Draws a horizontal bar to the right. -// -MODULE_EXPORT void -NoritakeVFD_hbar (Driver *drvthis, int x, int y, int len, int promille, int options) -{ -/* PrivateData *p = drvthis->private_data; - char map[5] = { 32, 1, 2, 3, 4 }; - - for (; x <= p->width && len > 0; x++) { - if (len >= p->cellwidth) - NoritakeVFD_chr (drvthis, x, y, map[4]); - else - NoritakeVFD_chr (drvthis, x, y, map[len]); - - len -= p->cellwidth; - - }*/ - - NoritakeVFD_init_hbar(drvthis); - //lib_hbar_static(drvthis, x, y, len, promille, options, p->cellheight, 0); -} - - -///////////////////////////////////////////////////////////////// -// Sets a custom character from 0-7... -// -// For input, value 1 mean "on" and 0 is "off". -// -// The input is just an array of characters... -// -MODULE_EXPORT void -NoritakeVFD_set_char (Driver *drvthis, int n, char *dat) -{ - PrivateData *p = drvthis->private_data; - char out[4]; - int byte, bit; - char letter; - - if (n < 0 || n > 7) - return; - if (!dat) - return; - - snprintf(out, sizeof(out), "%c%c%c", 0x1B, 'C', n); - write(p->fd, out, 3); - - for (byte = 0; byte < 5; byte++) { - letter = dat[(byte+1) * 8 - 1]; - for (bit = 7; bit > 0; bit--) { - letter <<= 1; - if ((byte * 8) + bit < 36) - letter |= dat[(byte * 8) - 1 + bit]; - } - write(p->fd, &letter, 1); - } -} - -/* - * Places an icon on screen - */ -MODULE_EXPORT int -NoritakeVFD_icon (Driver *drvthis, int x, int y, int icon) -{ - PrivateData *p = drvthis->private_data; - char icons[2][5 * 7] = { - { - 0, 0, 0, 0, 0, // Empty Heart - 0, 1, 0, 1, 0, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, - 0, 1, 1, 1, 0, - 0, 0, 1, 0, 0, - }, - - { - 0, 0, 0, 0, 0, // Filled Heart - 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, - 1, 0, 0, 0, 1, - 1, 0, 0, 0, 1, - 0, 1, 0, 1, 0, - 0, 0, 1, 0, 0, - }, - }; - - /* Yes we know, this is a VERY BAD implementation :-) */ - switch (icon) { - case ICON_HEART_FILLED: - p->ccmode = custom; - NoritakeVFD_set_char(drvthis, 0, icons[1]); - NoritakeVFD_chr(drvthis, x, y, 0); - break; - case ICON_HEART_OPEN: - p->ccmode = custom; - NoritakeVFD_set_char(drvthis, 0, icons[0]); - NoritakeVFD_chr(drvthis, x, y, 0); - break; - default: - return -1; /* Let the core do other icons */ - } - return 0; -} - -///////////////////////////////////////////////////////////// -// Blasts a single frame onscreen, to the lcd... -// -// Input is a character array, sized NoritakeVFD->width*NoritakeVFD->height -// -static void -NoritakeVFD_draw_frame (Driver *drvthis, unsigned char *dat) -{ - PrivateData *p = drvthis->private_data; - char out[p->width * p->height]; - unsigned char *row, *b_row; int i; - if (!dat) - return; - for (i = 0; i < p->height; i++) { - row = dat + (p->width * i); - b_row = p->backingstore + (p->width * i); + int offset = i * p->width; - /* Backing-store implementation. If it's already - * on the screen, don't put it there again - */ - if (memcmp(b_row, row, p->width) == 0) - continue; + /* Backing-store based implementation: + * Only put it on the screen if it's not already there */ + if (memcmp(p->backingstore+offset, p->framebuf+offset, p->width) != 0) { + memcpy(p->backingstore+offset, p->framebuf+offset, p->width); - /* else, write out the entire row */ - memcpy(b_row, row, p->width); - int pos = i * p->width; - snprintf(out, sizeof(out), "%c%c%c", 0x1B, 'H', pos); - write(p->fd, out, 3); - write(p->fd, row, p->width); + NoritakeVFD_cursor_goto(drvthis, 1, i+1); + write(p->fd, p->framebuf+offset, p->width); + } } - } -///////////////////////////////////////////////////////////////// -// Clears the LCD screen -// + +/** + * Clear the screen. + * \param drvthis Pointer to driver structure. + */ MODULE_EXPORT void NoritakeVFD_clear (Driver *drvthis) { @@ -698,10 +387,35 @@ NoritakeVFD_clear (Driver *drvthis) } -///////////////////////////////////////////////////////////////// -// Prints a string on the lcd display, at position (x,y). The -// upper-left is (1,1), and the lower right should be (20,4). -// +/** + * Print a character on the screen at position (x,y). + * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height). + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param c Character that gets written. + */ +MODULE_EXPORT void +NoritakeVFD_chr (Driver *drvthis, int x, int y, char c) +{ + PrivateData *p = drvthis->private_data; + + y--; + x--; + + if ((x >= 0) && (y >= 0) && (x < p->width) && (y < p->height)) + p->framebuf[(y * p->width) + x] = c; +} + + +/** + * Print a string on the screen at position (x,y). + * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height). + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param string String that gets written. + */ MODULE_EXPORT void NoritakeVFD_string (Driver *drvthis, int x, int y, const char string[]) { @@ -710,43 +424,426 @@ NoritakeVFD_string (Driver *drvthis, int x, int y, const char string[]) x--; y--; - for (i = 0; string[i] != '\0'; i++) { - // Check for buffer overflows... - if ((y * p->width) + x + i > (p->width * p->height)) - break; - p->framebuf[(y * p->width) + x + i] = string[i]; + + if ((y < 0) || (y >= p->height)) + return; + + for (i = 0; (string[i] != '\0') && (x < p->width); i++, x++) { + if (x >= 0) // no write left of left border + p->framebuf[(y * p->width) + x] = string[i]; } } -/* -///////////////////////////////////////////////////////////// -// Does the heartbeat... -// -static void -NoritakeVFD_heartbeat (Driver *drvthis, int type) + + +/** + * Draw a vertical bar bottom-up. + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column) of the starting point. + * \param y Vertical character position (row) of the starting point. + * \param len Number of characters that the bar is high at 100% + * \param promille Current height level of the bar in promille. + * \param options Options (currently unused). + */ +MODULE_EXPORT void +NoritakeVFD_vbar (Driver *drvthis, int x, int y, int len, int promille, int options) { PrivateData *p = drvthis->private_data; - static int timer = 0; - int whichIcon; - static int saved_type = HEARTBEAT_ON; + int pixels = ((long) 2 * len * p->cellheight) * promille / 2000; + int pos; + static unsigned char half[] = + { b_______, + b_______, + b_______, + b_______, + b__XXXXX, + b__XXXXX, + b__XXXXX }; - NoritakeVFD_icon(drvthis, 0, 0); - NoritakeVFD_icon(drvthis, 1, 1); + if (p->ccmode != vbar) { + if (p->ccmode != standard) { + /* Not supported(yet) */ + report(RPT_WARNING, "%s: vbar: cannot combine two modes using user-defined characters", + drvthis->name); + return; + } - if (type) - saved_type = type; + p->ccmode = vbar; - if (type == HEARTBEAT_ON) { - // Set this to pulsate like a real heart beat... - whichIcon = (! ((timer + 4) & 5)); + /* define half full block at position 1 */ + NoritakeVFD_set_char(drvthis, 1, half); + } - // Put character on screen... - NoritakeVFD_chr(p->width, 1, whichIcon); + for (pos = 0; pos < len; pos++) { + /* if pixels > 2/3 cellheight [in integer arithmetics] ... */ + if (3 * pixels >= p->cellheight * 2) { + /* ... write a full block to the screen */ + NoritakeVFD_chr(drvthis, x+pos, y, 0xBE); + } + /* if pixels > 1/3 cellheight [in integer arithmetics] ... */ + else if (3 * pixels > p->cellheight * 1) { + /* ... write a partial block */ + NoritakeVFD_chr(drvthis, x+pos, y, 1); + break; + } + else { + ; // write nothing (not even a space) + } + pixels -= p->cellheight; + } +} - // change display... - NoritakeVFD_flush (); + +/** + * Draw a horizontal bar to the right. + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column) of the starting point. + * \param y Vertical character position (row) of the starting point. + * \param len Number of characters that the bar is long at 100% + * \param promille Current length level of the bar in promille. + * \param options Options (currently unused). + */ +MODULE_EXPORT void +NoritakeVFD_hbar (Driver *drvthis, int x, int y, int len, int promille, int options) +{ + PrivateData *p = drvthis->private_data; + int pixels = ((long) 2 * len * p->cellwidth) * promille / 2000; + int pos; + static unsigned char half[] = + { b__XX___, + b__XX___, + b__XX___, + b__XX___, + b__XX___, + b__XX___, + b__XX___ }; + + if (p->ccmode != hbar) { + if (p->ccmode != standard) { + /* Not supported(yet) */ + report(RPT_WARNING, "%s: hbar: cannot combine two modes using user-defined characters", + drvthis->name); + return; + } + + p->ccmode = hbar; + + /* define half full block at position 1 */ + NoritakeVFD_set_char(drvthis, 1, half); + } + + for (pos = 0; pos < len; pos++) { + /* if pixels > 2/3 cellwidth [in integer arithmetics] ... */ + if (3 * pixels >= p->cellwidth * 2) { + /* ... write a full block to the screen */ + NoritakeVFD_chr(drvthis, x+pos, y, 0xBE); + } + /* if pixels > 1/3 cellwidth [in integer arithmetics] ... */ + else if (3 * pixels > p->cellwidth * 1) { + /* ... write a partial block */ + NoritakeVFD_chr(drvthis, x+pos, y, 1); + break; + } + else { + ; // write nothing (not even a space) + } + pixels -= p->cellwidth; + } +} + + +/** + * Write a big number to the screen. + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param num Character to write (0 - 10 with 10 representing ':') + */ +MODULE_EXPORT void +NoritakeVFD_num(Driver *drvthis, int x, int num) +{ +PrivateData *p = drvthis->private_data; +int do_init = 0; + + if ((num < 0) || (num > 10)) + return; + + if (p->ccmode != bignum) { + if (p->ccmode != standard) { + /* Not supported (yet) */ + report(RPT_WARNING, "%s: num: cannot combine two modes using user-defined characters", + drvthis->name); + return; + } + + p->ccmode = bignum; + + do_init = 1; } - timer++; - timer &= 0x0f; + // Lib_adv_bignum does everything needed to show the bignumbers. + lib_adv_bignum(drvthis, x, num, 0, do_init); +} + + +/** + * Place an icon on the screen. + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param icon synbolic value representing the icon. + * \return Information whether the icon is handled here or needs to be handled by the server core. + */ +MODULE_EXPORT int +NoritakeVFD_icon (Driver *drvthis, int x, int y, int icon) +{ + //PrivateData *p = drvthis->private_data; + static unsigned char heart_open[] = + { b_______, + b___X_X_, + b__X_X_X, + b__X___X, + b__X___X, + b___X_X_, + b____X__ }; + static unsigned char heart_filled[] = + { b_______, + b___X_X_, + b__XXXXX, + b__XXXXX, + b__XXXXX, + b___XXX_, + b____X__ }; + + /* Yes we know, this is a VERY BAD implementation :-) */ + switch (icon) { + case ICON_BLOCK_FILLED: + NoritakeVFD_chr(drvthis, x, y, 0xBE); + break; + case ICON_HEART_FILLED: + NoritakeVFD_set_char(drvthis, 0, heart_filled); + NoritakeVFD_chr(drvthis, x, y, 0); + break; + case ICON_HEART_OPEN: + NoritakeVFD_set_char(drvthis, 0, heart_open); + NoritakeVFD_chr(drvthis, x, y, 0); + break; + default: + return -1; /* Let the core do other icons */ + } + return 0; +} + + +/* + * Set cursor position and state. + * \param drvthis Pointer to driver structure. + * \param x Horizontal cursor position (column). + * \param y Vertical cursor position (row). + * \param state New cursor state. + */ +/* +MODULE_EXPORT void +CFontzPacket_cursor (Driver *drvthis, int x, int y, int state) +{ + PrivateData *p = drvthis->private_data; + char out[2] = { 0x15 }; + + // set cursor state + switch (state) { + case CURSOR_OFF: // no cursor + out[0] = 0x16; + break; + case CURSOR_UNDER: // underline cursor + out[0] = 0x14; + break; + case CURSOR_BLOCK: // inverting blinking block + case CURSOR_DEFAULT_ON: // blinking block + default: + out[0] = 0x15; + break; + } + write(p->fd, out, 1); + + NoritakeVFD_cursor_goto(x, y); } */ + + +/** + * Get total number of custom characters available. + * \param drvthis Pointer to driver structure. + * \return Number of custom characters (always NUM_CCs). + */ +MODULE_EXPORT int +NoritakeVFD_get_free_chars (Driver *drvthis) +{ + //PrivateData *p = drvthis->private_data; + + return NUM_CCs; +} + + +/** + * Define a custom character and write it to the LCD. + * \param drvthis Pointer to driver structure. + * \param n Custom character to define [0 - (NUM_CCs-1)]. + * \param dat Array of 8(=cellheight) bytes, each representing a pixel row + * starting from the top to bottom. + * The bits in each byte represent the pixels where the LSB + * (least significant bit) is the rightmost pixel in each pixel row. + */ +MODULE_EXPORT void +NoritakeVFD_set_char (Driver *drvthis, int n, unsigned char *dat) +{ + PrivateData *p = drvthis->private_data; + char out[9] = { 0x1B, 0x43, 0, 0, 0, 0, 0, 0, 0 }; + int i; + + if ((n < 0) || (n >= NUM_CCs)) + return; + if (dat == NULL) + return; + + out[2] = n; + + /* mangle the character data bits so that the VFD can chew them ;-) */ + for (i = 0; i < 35; i++) { + out[3 + i/8] |= ((dat[i/5] >> (4 - i%5)) & 1) << i%8; + } + + write(p->fd, out, 8); +} + + +/** + * Retrieve brightness. + * \param drvthis Pointer to driver structure. + * \param state Brightness state (on/off) for which we want the value. + * \return Stored brightness in promille. + */ +MODULE_EXPORT int +NoritakeVFD_get_brightness(Driver *drvthis, int state) +{ + PrivateData *p = drvthis->private_data; + + return (state == BACKLIGHT_ON) ? p->brightness : p->offbrightness; +} + + +/** + * Set on/off brightness. + * \param drvthis Pointer to driver structure. + * \param state Brightness state (on/off) for which we want to store the value. + * \param promille New brightness in promille. + */ +MODULE_EXPORT void +NoritakeVFD_set_brightness(Driver *drvthis, int state, int promille) +{ + PrivateData *p = drvthis->private_data; + + /* Check it */ + if (promille < 0 || promille > 1000) + return; + + /* store the software value since there is not get */ + if (state == BACKLIGHT_ON) { + p->brightness = promille; + //Noritake_backlight(drvthis, BACKLIGHT_ON); + } + else { + p->offbrightness = promille; + //Noritake_backlight(drvthis, BACKLIGHT_OFF); + } +} + + +/** + * Turn the LCD backlight on or off. + * \param drvthis Pointer to driver structure. + * \param on New backlight status. + */ +MODULE_EXPORT void +NoritakeVFD_backlight (Driver *drvthis, int on) +{ + PrivateData *p = drvthis->private_data; + char out[4] = { 0x1B, 0x4C, 0 }; + int hardware_value = (on == BACKLIGHT_ON) + ? p->brightness + : p->offbrightness; + + // Changes screen brightness (0-255; 140 seems good) + /* not sure if the formula is correct: + * What is the allowed range for the brightness value ? */ + out[2] = (int) (hardware_value * 255 / 1000); + write(p->fd, out, 3); +} + + +/** + * Toggle the built-in automatic scrolling feature. + * \param drvthis Pointer to driver structure. + * \param on New scrolling status. + */ +static void +NoritakeVFD_autoscroll (Driver *drvthis, int on) +{ + PrivateData *p = drvthis->private_data; + char out[2]; + + out[0] = (on) ? 0x12 : 0x11; + write(p->fd, out, 1); +} + + +/** + * Get rid of the blinking cursor. + * \param drvthis Pointer to driver structure. + */ +static void +NoritakeVFD_hidecursor (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + char out[2] = { 0x16 }; + + write(p->fd, out, 1); +} + + +/** + * Reset the display bios. + * \param drvthis Pointer to driver structure. + */ +static void +NoritakeVFD_reboot (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + char reset_out[3] = { 0x1B, 0x49 }; + char flickerless_out[3] = { 0x1B, 0x53 }; + + /* reset display */ + write(p->fd, reset_out, 2); + + /* switch on flickerless write */ + write(p->fd, flickerless_out, 2); +} + + +/** + * Move cursor to position (x,y). + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + */ +static void +NoritakeVFD_cursor_goto(Driver *drvthis, int x, int y) +{ + PrivateData *p = drvthis->private_data; + unsigned char out[4] = { 0x1B, 0x48, 0 }; + + /* set cursor position */ + if ((x > 0) && (x <= p->width) && (y > 0) && (y <= p->height)) + out[2] = (x-1) * p->width + (y-1); + write(p->fd, out, 3); +} + + +/* EOF */ diff --git a/server/drivers/NoritakeVFD.h b/server/drivers/NoritakeVFD.h index edbdb3c..c2ea4ef 100644 --- a/server/drivers/NoritakeVFD.h +++ b/server/drivers/NoritakeVFD.h @@ -23,11 +23,12 @@ #define NORITAKEVFD_H #include "lcd.h" -#define DEFAULT_CELL_WIDTH 6 -#define DEFAULT_CELL_HEIGHT 8 +#define DEFAULT_CELL_WIDTH 5 +#define DEFAULT_CELL_HEIGHT 7 #define DEFAULT_DEVICE "/dev/lcd" #define DEFAULT_SPEED 9600 #define DEFAULT_BRIGHTNESS 140 +#define DEFAULT_OFFBRIGHTNESS 100 #define DEFAULT_SIZE "20x4" #define DEFAULT_PARITY 0 @@ -44,12 +45,16 @@ MODULE_EXPORT void NoritakeVFD_chr (Driver *drvthis, int x, int y, char c); MODULE_EXPORT void NoritakeVFD_vbar (Driver *drvthis, int x, int y, int len, int promille, int options); MODULE_EXPORT void NoritakeVFD_hbar (Driver *drvthis, int x, int y, int len, int promille, int options); -MODULE_EXPORT int NoritakeVFD_icon(Driver *drvthis, int x, int y, int icon); +MODULE_EXPORT void NoritakeVFD_num(Driver *drvthis, int x, int num); +MODULE_EXPORT int NoritakeVFD_icon (Driver *drvthis, int x, int y, int icon); +MODULE_EXPORT void NoritakeVFD_cursor (Driver *drvthis, int x, int y, int state); -MODULE_EXPORT void NoritakeVFD_set_char (Driver *drvthis, int n, char *dat); +MODULE_EXPORT int NoritakeVFD_get_free_chars (Driver *drvthis); +MODULE_EXPORT void NoritakeVFD_set_char (Driver *drvthis, int n, unsigned char *dat); -MODULE_EXPORT int NoritakeVFD_get_brightness (Driver *drvthis, int state); -MODULE_EXPORT void NoritakeVFD_set_brightness (Driver *drvthis, int state, int promille); -MODULE_EXPORT void NoritakeVFD_output (Driver *drvthis, int state); +MODULE_EXPORT int NoritakeVFD_get_brightness(Driver *drvthis, int state); +MODULE_EXPORT void NoritakeVFD_set_brightness(Driver *drvthis, int state, int promille); +MODULE_EXPORT void NoritakeVFD_backlight (Driver *drvthis, int on); #endif +