diff --git a/ChangeLog b/ChangeLog index 6f79bab..2bd5665 100644 --- a/ChangeLog +++ b/ChangeLog @@ -27,6 +27,7 @@ v.0.5dev (ongoing development) * CFontzPacket: Use cellwidth = 5 on CFA-631 and CFA-635 too * t6963: Convert font to 8 byte bitmap * convert i2500vfd and mdm166a driver to use 8 byte bitmap custom character + * ula200: convert custom characters to 8 byte bitmap v0.5.4 * Update driver includes and LDFLAGS (fixed glk and bayrad binding error) diff --git a/docs/lcdproc-user/drivers/ula200.docbook b/docs/lcdproc-user/drivers/ula200.docbook index 588a170..71d70e0 100644 --- a/docs/lcdproc-user/drivers/ula200.docbook +++ b/docs/lcdproc-user/drivers/ula200.docbook @@ -84,7 +84,7 @@ So in theory, it would be possible to write a connection type for the I tried this. It was slow and didn't work with user-specific characters (the hd44780 frequently changes this characters which seems to confuse the microcontroller, at least I cannot explain why it didn't work, there was -garbare). +garbage). diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am index 7be44c9..b4aaa3c 100644 --- a/server/drivers/Makefile.am +++ b/server/drivers/Makefile.am @@ -124,7 +124,7 @@ svga_SOURCES = lcd.h svgalib_drv.c svgalib_drv.h report.h t6963_SOURCES = lcd.h lcd_lib.h t6963.c t6963.h t6963_font.h report.h text_SOURCES = lcd.h text.h text.c report.h tyan_SOURCES = lcd.h lcd_lib.h tyan_lcdm.h tyan_lcdm.c report.h adv_bignum.h -ula200_SOURCES = lcd.h lcd_lib.h ula200.h ula200.c report.h +ula200_SOURCES = lcd.h adv_bignum.h ula200.h ula200.c report.h xosd_SOURCES = lcd.h xosdlib_drv.c xosdlib_drv.h report.h adv_bignum.h AM_CPPFLAGS = -I$(top_srcdir) diff --git a/server/drivers/ula200.c b/server/drivers/ula200.c index 4a6532f..5ef10cc 100644 --- a/server/drivers/ula200.c +++ b/server/drivers/ula200.c @@ -2,96 +2,27 @@ * LCDd \c ula200 driver for the ULA-200 from ELV (http://www.elv.de). */ -// Description: -// -// This is a driver for the ULA-200 from ELV (http://www.elv.de). It's a small -// board which can be connected to the PC via USB interface and that allows to -// connect a HD44780-compatible display. It also has a connection for up to 6 -// input buttons. -// -// It uses libftdi (which uses libusb) for communication, so no kernel driver -// is needed. You have to take care that ftdi_sio module doesn't claim the ELV -// device. If you didn't change the ids in the driver (ftdi_sio.c), you don't -// have to matter. -// -// -// Features: -// -// - text display is supported -// - standard symbols (heart, checkbox) are supported -// - backlight is supported -// - input buttons are supported -// - bars are NOT supported -// -// -// Configuration options (the values are the default values): -// -// - Size=20x4 -// - KeyMap_A=Up -// - KeyMap_B=Down -// - KeyMap_C=Left -// - KeyMap_D=Right -// - KeyMap_E=Enter -// - KeyMap_F=Escape -// -// -// Known problems: -// -// Sometimes the display hangs (the ACK response is not received) on shutdown. -// Reconnect the display in that case. The same if it hangs while starting -// up (only happens if it was not the first time lcdproc talked to the -// display). -// -// I tried several hours to fix this, I simply find the reason for this problem. -// -// -// Implementation note: -// -// The ULA-200 talks a text protocol which allows to display text using a -// high-level language, i.e. STX 's' ... ETX. It also -// allows low-level register access to the HD44780. So in theory, it would be -// possible to write a hd44780 extension and let the hd44780 core do the rest. -// I tried this. It was slow and didn't work with user-specific characters -// (the hd44780 frequently changes this characters which seems to confuse the -// microcontroller, at least I cannot explain why it didn't work, there was -// garbare). -// -// So I wrote a own driver (this here) which uses the high-level language and -// should work for displays with all sizes. I only tested 20x4, so maybe for -// other sizes the positioning code may be adapted. -// -// As I mentioned, there were problems with frequently changing the -// user-definable characters. I also tried to implement bar code in the ula200 -// driver with similar effects. I gave it up because I don't need it personally -// and it can be done later. However, standard icons are implemented. The -// user-definable characters are set in startup and are not changed. This -// works like a charm. It is not possible to use character 0 with the -// high-level language (or at least it isn't documented how to escape it). -// It could be done with hd44780 code, but I replaced the character with -// a standard character which looks good. -// -// -// Author -// -// Bernhard Walle -// Feel free to contact me if there are problems with this driver. -// +/*- + * Copyright (C) 2006 Bernhard Walle + * + * 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 + * any later version. -/* Copyright (C) 2006 Bernhard Walle + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. - 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 - any later version. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include #include @@ -105,15 +36,11 @@ #include #include -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - #include "hd44780-charmap.h" #include "lcd.h" #include "ula200.h" #include "report.h" -#include "timing.h" +#include "adv_bignum.h" /* Vars for the server core */ @@ -123,9 +50,7 @@ MODULE_EXPORT int supports_multiple = 1; MODULE_EXPORT char *symbol_prefix = "ula200_"; -/////////////////////////////////////////////////////////////////////////////// -// constants -// +/* -------------------------- constants ---------------------------------- */ #define DISPLAY_VENDOR_ID 0x0403 #define DISPLAY_PRODUCT_ID 0xf06d @@ -138,7 +63,7 @@ MODULE_EXPORT char *symbol_prefix = "ula200_"; #define CH_DC3 0x13 #define MAX_KEY_MAP 6 -static char *default_key_map[MAX_KEY_MAP] = { "Up", "Down", "Left", "Right", "Enter", "Escape" }; +static char *default_key_map[MAX_KEY_MAP] = {"Up", "Down", "Left", "Right", "Enter", "Escape"}; #define CELLWIDTH 5 #define CELLHEIGHT 8 @@ -146,10 +71,19 @@ static char *default_key_map[MAX_KEY_MAP] = { "Up", "Down", "Left", "Right", "En /* repeat conts for responses */ #define MAX_REPEATS 20 +/* commands for senddata */ +#define RS_DATA 0x00 +#define RS_INSTR 0x01 +#define SETCHAR 0x40 -/////////////////////////////////////////////////////////////////////////////// -// Key ring implementation from CFontz633io -// +/* boolean data type */ +#ifndef bool +# define bool short +# define true 1 +# define false 0 +#endif + +/* ----------- Key ring implementation from CFontz633io ------------------ */ /* KeyRing management */ #define KEYRINGSIZE 16 @@ -160,29 +94,27 @@ typedef struct ula200_keyring { int tail; } KeyRing; - - /* - * KeyRing handling functions. - * This separates the producer from the consumer. + * KeyRing handling functions. This separates the producer from the consumer. * It is just a small fifo of unsigned char. */ /** initialize/empty key ring by resetting its read & write pointers */ -void EmptyKeyRing(KeyRing *kr) +void +EmptyKeyRing(KeyRing *kr) { kr->head = kr->tail = 0; } /** add byte to key ring; return success (byte added) / failure (key ring is full) */ -int AddKeyToKeyRing(KeyRing *kr, unsigned char key) +int +AddKeyToKeyRing(KeyRing *kr, unsigned char key) { if (((kr->head + 1) % KEYRINGSIZE) != (kr->tail % KEYRINGSIZE)) { - /* fprintf(stderr, "We add key: %d\n", key); */ - kr->contents[kr->head % KEYRINGSIZE] = key; - kr->head = (kr->head + 1) % KEYRINGSIZE; + kr->contents[kr->head % KEYRINGSIZE] = key; + kr->head = (kr->head + 1) % KEYRINGSIZE; return 1; } @@ -192,7 +124,8 @@ int AddKeyToKeyRing(KeyRing *kr, unsigned char key) /** get byte from key ring (or '\\0' if key ring is empty) */ -unsigned char GetKeyFromKeyRing(KeyRing *kr) +unsigned char +GetKeyFromKeyRing(KeyRing *kr) { unsigned char retval = '\0'; @@ -200,401 +133,413 @@ unsigned char GetKeyFromKeyRing(KeyRing *kr) if ((kr->head % KEYRINGSIZE) != kr->tail) { retval = kr->contents[kr->tail]; - kr->tail = (kr->tail + 1) % KEYRINGSIZE; + kr->tail = (kr->tail + 1) % KEYRINGSIZE; } - /* if (retval) fprintf(stderr, "We remove key: %d\n", retval); */ return retval; } -/////////////////////////////////////////////////////////////////////////////// -// for HD 44780 compatibility -// - -// commands for senddata -#define RS_DATA 0x00 -#define RS_INSTR 0x01 - -#define SETCHAR 0x40 /* Only reachable with EXTREG clear */ +/* ---------------------- ULA-200 specific functions --------------------- */ /** private data for the \c ula200 driver */ typedef struct ula200_private_data { - struct ftdi_context ftdic; /**< handle for the USB FTDI library */ - - // the width and the height (in number of characters) of the library - int width, height; - - // The framebuffer and the framebuffer for the last contents (incr. update) - unsigned char *framebuf, *lcd_contents; - - unsigned char all_dirty; /**< first time => all is dirty */ - - int backlight; /**< backlight: -1=unset, 0=off, 1=on */ - - KeyRing keyring; /**< input key ring */ - - char *key_map[MAX_KEY_MAP]; /**< mapping of input keys */ + struct ftdi_context ftdic; /**< handle for the USB FTDI library */ + int width; /**< display width in characters */ + int height; /**< display height in characters */ + unsigned char *framebuf; /**< framebuffer LCDd writes to */ + unsigned char *lcd_contents; /**< content of screen for incr. upd. */ + unsigned char all_dirty; /**< first time => all is dirty */ + int backlight; /**< backlight: -1=unset, 0=off, 1=on */ + KeyRing keyring; /**< input key ring */ + char *key_map[MAX_KEY_MAP]; /**< mapping of input keys */ } PrivateData; -/////////////////////////////////////////////////////////////////////////////// -// Reads a USB characters +/** + * Reads a character from USB. + * \param p Pointer to drivers private data + * \return Character read from USB. + */ static inline int ula200_ftdi_usb_read(PrivateData *p) { - unsigned char buffer[1]; - int err; + unsigned char buffer[1]; + int err; - while ((err = ftdi_read_data(&p->ftdic, buffer, 1)) == 0); + while ((err = ftdi_read_data(&p->ftdic, buffer, 1)) == 0); - if (err < 0) { - return -1; - } - else { - return buffer[0]; - } + if (err < 0) { + return -1; + } + else { + return buffer[0]; + } } -/////////////////////////////////////////////////////////////////////////////// -// Reads the response -// -// @return true if ACK was responded, false if NACk was responded -// +/** + * Reads the response. + * + * \return true if ACK was responded + * \return false if NAK was responded + */ static bool ula200_ftdi_read_response(Driver *drvthis) { PrivateData *p = (PrivateData *) drvthis->private_data; - bool result = false; - bool answer_read = false; - int ret; - int ch; + bool result = false; + bool answer_read = false; + int ret; + int ch; - while (!answer_read) - { - /* wait until STX */ - while (((ret = ula200_ftdi_usb_read(p)) != CH_STX) && (ret > 0)); - if (ret < 0) { - return false; - } + while (!answer_read) { + /* wait until STX */ + while (((ret = ula200_ftdi_usb_read(p)) != CH_STX) && (ret > 0)); + if (ret < 0) { + return false; + } - /* read next char */ - ch = ula200_ftdi_usb_read(p); + /* read next char */ + ch = ula200_ftdi_usb_read(p); - switch (ch) { - case 't': - ch = ula200_ftdi_usb_read(p); - AddKeyToKeyRing(&p->keyring, (unsigned char)(ch - 0x40)); - break; + switch (ch) { + case 't': + ch = ula200_ftdi_usb_read(p); + AddKeyToKeyRing(&p->keyring, (unsigned char)(ch - 0x40)); + break; - case CH_ACK: - answer_read = true; - result = true; - break; + case CH_ACK: + answer_read = true; + result = true; + break; - case CH_NAK: - answer_read = true; - break; + case CH_NAK: + answer_read = true; + break; - default: - answer_read = true; - report(RPT_INFO, "%s: read invalid answer (0x%02X)", drvthis->name, ch); - } + default: + answer_read = true; + report(RPT_INFO, "%s: read invalid answer (0x%02X)", drvthis->name, ch); + } - /* wait until ETX */ - while (((ret = ula200_ftdi_usb_read(p)) != CH_ETX) && (ret > 0)); - if (ret < 0) { - return false; - } - } + /* wait until ETX */ + while (((ret = ula200_ftdi_usb_read(p)) != CH_ETX) && (ret > 0)); + if (ret < 0) { + return false; + } + } - return result; + return result; } -/////////////////////////////////////////////////////////////////////////////// -// Write a command to the display. Adds the STX and ETX header/trailer. -// -// @param p the private data -// @param data the data bytes -// @param length the number of bytes in @p data which are valid -// @param escape if the data should be escaped (see the User's Guide of the -// ULA-200) -// @return 0 on success, negative value on error -// +/** + * Write a command to the display. Adds the STX and ETX header/trailer. + * + * \param p the private data + * \param data the data bytes + * \param length the number of bytes in @p data which are valid + * \param escape if the data should be escaped (see the User's Guide of the + * ULA-200) + * \return 0 on success, negative value on error + */ static int ula200_ftdi_write_command(Driver *drvthis, unsigned char *data, int length, bool escape) { PrivateData *p = (PrivateData *) drvthis->private_data; - int i, err; - int repeat_count = 0; - int pos = 0; - unsigned char buffer[1024]; + int i, err; + int repeat_count = 0; + int pos = 0; + unsigned char buffer[1024]; - if (length > 512) { - return -EINVAL; - } + if (length > 512) { + return -EINVAL; + } - /* fill the array */ - buffer[pos++] = CH_STX; - for (i = 0; i < length; i++) { - if (escape) { - if (data[i] == CH_STX) { - buffer[pos++] = CH_ENQ; - buffer[pos++] = CH_DC2; - } - else if (data[i] == CH_ETX) { - buffer[pos++] = CH_ENQ; - buffer[pos++] = CH_DC3; - } - else if (data[i] == CH_ENQ) { - buffer[pos++] = CH_ENQ; - buffer[pos++] = CH_NAK; - } - else { - buffer[pos++] = data[i]; - } - } - else { - buffer[pos++] = data[i]; - } - } - buffer[pos++] = CH_ETX; + /* fill the array */ + buffer[pos++] = CH_STX; + for (i = 0; i < length; i++) { + if (escape) { + if (data[i] == CH_STX) { + buffer[pos++] = CH_ENQ; + buffer[pos++] = CH_DC2; + } + else if (data[i] == CH_ETX) { + buffer[pos++] = CH_ENQ; + buffer[pos++] = CH_DC3; + } + else if (data[i] == CH_ENQ) { + buffer[pos++] = CH_ENQ; + buffer[pos++] = CH_NAK; + } + else { + buffer[pos++] = data[i]; + } + } + else { + buffer[pos++] = data[i]; + } + } + buffer[pos++] = CH_ETX; - do { - /* bytes */ - err = ftdi_write_data(&p->ftdic, buffer, pos); - if (err < 0) { - report(RPT_WARNING, "%s: ftdi_write_data failed", drvthis->name); - return -1; - } - } - while (!ula200_ftdi_read_response(drvthis) && (repeat_count++ < MAX_REPEATS)); + do { + /* bytes */ + err = ftdi_write_data(&p->ftdic, buffer, pos); + if (err < 0) { + report(RPT_WARNING, "%s: ftdi_write_data failed", drvthis->name); + return -1; + } + } + while (!ula200_ftdi_read_response(drvthis)&&(repeat_count++ < MAX_REPEATS)); - return 0; + return 0; } -/////////////////////////////////////////////////////////////////////////////// -// Clear the display -// +/** + * Clear the display using display command. + * \return Error code from ula200_ftdi_write_command. + */ static int ula200_ftdi_clear(Driver *drvthis) { - //PrivateData *p = (PrivateData *) drvthis->private_data; - unsigned char command[1]; - int err; + unsigned char command[1]; + int err; - command[0] = 'l'; - err = ula200_ftdi_write_command(drvthis, command, 1, true); - if (err < 0) { - report(RPT_WARNING, "%s: ula200_ftdi_clear: " - "ula200_ftdi_write_command failed", drvthis->name); - } + command[0] = 'l'; + err = ula200_ftdi_write_command(drvthis, command, 1, true); + if (err < 0) { + report(RPT_WARNING, "%s: ula200_ftdi_clear: " + "ula200_ftdi_write_command failed", drvthis->name); + } - return err; + return err; } -/////////////////////////////////////////////////////////////////////////////// -// Set the position -// +/** + * Set the position. + */ static int ula200_ftdi_position(Driver *drvthis, int x, int y) { - PrivateData *p = (PrivateData *) drvthis->private_data; - unsigned char command[5]; - int err; + PrivateData *p = (PrivateData *) drvthis->private_data; + unsigned char command[5]; + int err; - if (y >= 2) { - y -= 2; - x += p->width; - } + if (y >= 2) { + y -= 2; + x += p->width; + } - command[0] = 'p'; - command[1] = x; - command[2] = y; - err = ula200_ftdi_write_command(drvthis, command, 3, true); - if (err < 0) { - report(RPT_WARNING, "%s: ula200_ftdi_position(%d,%d): " - "ula200_ftdi_write_command failed", - drvthis->name, x, y); - } + command[0] = 'p'; + command[1] = x; + command[2] = y; + err = ula200_ftdi_write_command(drvthis, command, 3, true); + if (err < 0) { + report(RPT_WARNING, "%s: ula200_ftdi_position(%d,%d): " + "ula200_ftdi_write_command failed", + drvthis->name, x, y); + } - return err; + return err; } -/////////////////////////////////////////////////////////////////////////////// -// Send raw data -// +/** + * Send raw data. + * + * \param drvthis Pointer to driver + * \param flags Flag indicating byte is command or data + * \param ch Data byte to send + * \return Error code from ula200_ftdi_write_command. + */ static int ula200_ftdi_rawdata(Driver *drvthis, unsigned char flags, unsigned char ch) { - //PrivateData *p = (PrivateData *) drvthis->private_data; - unsigned char command[3]; - int err; + unsigned char command[3]; + int err; - command[0] = 'R'; - command[1] = flags == (RS_DATA) ? '2' : '0'; - command[2] = ch; - err = ula200_ftdi_write_command(drvthis, command, 3, false); - if (err < 0) { + command[0] = 'R'; + command[1] = flags == (RS_DATA) ? '2' : '0'; + command[2] = ch; + err = ula200_ftdi_write_command(drvthis, command, 3, false); + if (err < 0) { report(RPT_ERR, "%s: ftdi_write_command() failed", drvthis->name); - } + } - return err; + return err; } -/////////////////////////////////////////////////////////////////////////////// -// Displays a string -// +/** + * Writes a string to the display. + * + * \param drvthis Pointer to driver + * \param string Pointer to string + * \param len Length of the string + * \return -EINVAL If the string is to long (max 80 characters) + * \return err Error code from ula200_ftdi_write_command + */ static int ula200_ftdi_string(Driver *drvthis, const unsigned char *string, int len) { - //PrivateData *p = (PrivateData *) drvthis->private_data; - unsigned char buffer[128]; - int err; - int i; + unsigned char buffer[128]; + int err; + int i; - if (len > 80) { - return -EINVAL; - } + if (len > 80) { + return -EINVAL; + } - buffer[0] = 's'; - buffer[1] = len; - for (i = 0; i < len; i++) { - buffer[i+2] = HD44780_charmap[(unsigned char)string[i]]; - } + buffer[0] = 's'; + buffer[1] = len; + for (i = 0; i < len; i++) { + buffer[i + 2] = HD44780_charmap[(unsigned char)string[i]]; + } - err = ula200_ftdi_write_command(drvthis, buffer, len+2, true); - if (err < 0) { - report(RPT_WARNING, "%s: ula200_ftdi_string: " - "ula200_ftdi_write_command() failed", drvthis->name); - } + err = ula200_ftdi_write_command(drvthis, buffer, len + 2, true); + if (err < 0) { + report(RPT_WARNING, "%s: ula200_ftdi_string: " + "ula200_ftdi_write_command() failed", drvthis->name); + } - return err; + return err; } -/////////////////////////////////////////////////////////////////////////////// -// Enables the raw register access mode. -// +/** + * Enables the raw register access mode. + * \param drvthis Pointer to driver + * \return Error code from ula200_ftdi_write_command. + */ static int ula200_ftdi_enable_raw_mode(Driver *drvthis) { - unsigned char command[3]; + unsigned char command[3]; - report(RPT_DEBUG, "%s: enable raw mode", drvthis->name); + report(RPT_DEBUG, "%s: enable raw mode", drvthis->name); - command[0] = 'R'; - command[1] = 'E'; - command[2] = '1'; - return ula200_ftdi_write_command(drvthis, command, 3, false); + command[0] = 'R'; + command[1] = 'E'; + command[2] = '1'; + return ula200_ftdi_write_command(drvthis, command, 3, false); } -/////////////////////////////////////////////////////////////////////////////// -// Loads custom characters in the display -// +/** + * Loads custom characters in the display. + */ static int ula200_load_custom_chars(Driver *drvthis) { - int i, col, row; - int err = 0; - char custom_chars[8][CELLHEIGHT*CELLHEIGHT] = { - { 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, - 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1, - 1, 0, 1, 0, 1, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 1, 0, 0, 0, 1, - 1, 1, 0, 1, 1, - 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1, - 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, - 0, 1, 1, 1, 0, - 0, 1, 1, 1, 0, - 1, 0, 1, 0, 1, - 1, 1, 0, 1, 1, - 1, 1, 1, 1, 1 }, - { 0, 0, 1, 0, 0, - 0, 1, 1, 1, 0, - 1, 0, 1, 0, 1, - 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, - 1, 0, 1, 0, 1, - 0, 1, 1, 1, 0, - 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, - 1, 0, 0, 0, 1, - 1, 0, 0, 0, 1, - 1, 0, 0, 0, 1, - 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, - 1, 1, 1, 0, 1, - 1, 0, 1, 1, 0, - 1, 0, 1, 0, 1, - 1, 0, 0, 0, 1, - 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, - 1, 0, 1, 0, 1, - 1, 1, 0, 1, 1, - 1, 0, 1, 0, 1, - 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0 }}; + int i, row; + int err = 0; + unsigned char mask = (1 << CELLWIDTH) - 1; + char custom_chars[8][CELLHEIGHT] = { + { + b__XXXXX, + b__XXXXX, + b__XXXXX, + b__XXXXX, + b__XXXXX, + b__XXXXX, + b__XXXXX, + b__XXXXX + }, + { + b__XXXXX, + b__X_X_X, + b_______, + b_______, + b_______, + b__X___X, + b__XX_XX, + b__XXXXX + }, + { + b__XXXXX, + b__X_X_X, + b___X_X_, + b___XXX_, + b___XXX_, + b__X_X_X, + b__XX_XX, + b__XXXXX + }, + { + b____X__, + b___XXX_, + b__X_X_X, + b____X__, + b____X__, + b____X__, + b____X__, + b_______ + }, + { + b____X__, + b____X__, + b____X__, + b____X__, + b__X_X_X, + b___XXX_, + b____X__, + b_______ + }, + { + b_______, + b_______, + b__XXXXX, + b__X___X, + b__X___X, + b__X___X, + b__XXXXX, + b_______ + }, + { + b____X__, + b____X__, + b__XXX_X, + b__X_XX_, + b__X_X_X, + b__X___X, + b__XXXXX, + b_______ + }, + { + b_______, + b_______, + b__XXXXX, + b__X_X_X, + b__XX_XX, + b__X_X_X, + b__XXXXX, + b_______ + } + }; - for (i = 0; i < 8 && err == 0; i++) - { - /* Tell the HD44780 we will redefine char number i */ - ula200_ftdi_rawdata(drvthis, RS_INSTR, SETCHAR | i * 8); - if (err < 0) { - report(RPT_WARNING, "%s: ula200_ftdi_rawdata failed", drvthis->name); - break; - } + for (i = 0; i < 8 && err == 0; i++) { + /* Tell the HD44780 we will redefine char number i */ + ula200_ftdi_rawdata(drvthis, RS_INSTR, SETCHAR | i * 8); + if (err < 0) { + report(RPT_WARNING, "%s: ula200_ftdi_rawdata failed", drvthis->name); + break; + } - /* Send the subsequent rows */ - for (row = 0; row < CELLHEIGHT; row++) { - int value = 0; + /* Send the subsequent rows */ + for (row = 0; row < CELLHEIGHT; row++) { + int value = custom_chars[i][row] & mask; + err = ula200_ftdi_rawdata(drvthis, RS_DATA, value); + if (err < 0) { + report(RPT_WARNING, "%s: ula200_ftdi_rawdata failed", drvthis->name); + break; + } + } + } - for (col = 0; col < CELLWIDTH; col++) { - value <<= 1; - value |= (custom_chars[i][(row * CELLWIDTH) + col] > 0) ? 1 : 0; - } - err = ula200_ftdi_rawdata(drvthis, RS_DATA, value); - if (err < 0) { - report(RPT_WARNING, "%s: ula200_ftdi_rawdata failed", drvthis->name); - break; - } - } - } - - return err; + return err; } +/* --------------------------- API functions ----------------------------- */ /** * Initialize the driver. @@ -609,12 +554,12 @@ ula200_init(Driver *drvthis) int err, i; const char *s; - // Alocate and store private data - p = (PrivateData *) malloc( sizeof( PrivateData) ); + /* Allocate and store private data */ + p = (PrivateData *) malloc(sizeof(PrivateData)); if (p == NULL) { return -1; } - if (drvthis->store_private_ptr(drvthis, p)) { + if (drvthis->store_private_ptr(drvthis, p)){ return -1; } @@ -622,7 +567,7 @@ ula200_init(Driver *drvthis) p->all_dirty = 1; EmptyKeyRing(&p->keyring); - // Get and parse size + /* Get and parse size */ s = drvthis->config_get_string(drvthis->name, "size", 0, "20x4"); if ((sscanf(s, "%dx%d", &(p->width), &(p->height)) != 2) || (p->width <= 0) || (p->width > LCD_MAX_WIDTH) @@ -631,36 +576,36 @@ ula200_init(Driver *drvthis) return -1; } - // read the keymap + /* read the keymap */ for (i = 0; i < MAX_KEY_MAP; i++) { char buf[40]; - // First fill with default value + /* First fill with default value */ p->key_map[i] = default_key_map[i]; - // Read config value - sprintf(buf, "KeyMap_%c", i+'A'); + /* Read config value */ + sprintf(buf, "KeyMap_%c", i + 'A'); s = drvthis->config_get_string(drvthis->name, buf, 0, NULL); - // Was a key specified in the config file ? + /* Was a key specified in the config file ? */ if (s != NULL) { p->key_map[i] = strdup(s); report(RPT_INFO, "%s: Key '%c' mapped to \"%s\"", - drvthis->name, i+'A', s ); + drvthis->name, i + 'A', s); } } /* End of config file parsing */ - // Allocate framebuffer + /* Allocate framebuffer */ p->framebuf = (unsigned char *) malloc(p->width * p->height); if (p->framebuf == NULL) { report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name); goto err_begin; } - // Allocate and clear the buffer for incremental updates + /* Allocate and clear the buffer for incremental updates */ p->lcd_contents = (unsigned char *) malloc(p->width * p->height); if (p->lcd_contents == NULL) { report(RPT_ERR, "%s: unable to allocate framebuffer backing store", drvthis->name); @@ -668,40 +613,40 @@ ula200_init(Driver *drvthis) } memset(p->lcd_contents, 0, p->width * p->height); - // open the FTDI library + /* open the FTDI library */ ftdi_init(&p->ftdic); (&p->ftdic)->usb_write_timeout = 20; (&p->ftdic)->usb_read_timeout = 20; - // open the device + /* open the device */ err = ftdi_usb_open(&p->ftdic, DISPLAY_VENDOR_ID, DISPLAY_PRODUCT_ID); if (err < 0) { report(RPT_ERR, "%s: cannot open USB device", drvthis->name); goto err_lcd; } - // set the baudrate + /* set the baudrate */ err = ftdi_set_baudrate(&p->ftdic, 19200); if (err < 0) { report(RPT_ERR, "%s: cannot set baudrate", drvthis->name); goto err_ftdi; } - // set communication parameters + /* set communication parameters */ err = ftdi_set_line_property(&p->ftdic, BITS_8, STOP_BIT_1, EVEN); if (err < 0) { report(RPT_ERR, "%s: cannot set line properties", drvthis->name); goto err_ftdi; } - // user is able to write commands + /* user is able to write commands */ err = ula200_ftdi_enable_raw_mode(drvthis); if (err < 0) { report(RPT_ERR, "%s: unable to enable the raw mode", drvthis->name); goto err_ftdi; } - // load the chars + /* load the chars */ err = ula200_load_custom_chars(drvthis); if (err < 0) { report(RPT_ERR, "%s: unable to write the custom characters", drvthis->name); @@ -715,12 +660,11 @@ ula200_init(Driver *drvthis) err_ftdi: ftdi_usb_close(&p->ftdic); ftdi_deinit(&p->ftdic); -err_framebuf: - free(p->framebuf); err_lcd: free(p->lcd_contents); +err_framebuf: + free(p->framebuf); err_begin: - return -1; } @@ -740,10 +684,10 @@ ula200_close(Driver *drvthis) ftdi_deinit(&p->ftdic); if (p->framebuf != NULL) - free(p->framebuf); + free(p->framebuf); if (p->lcd_contents != NULL) - free(p->lcd_contents); + free(p->lcd_contents); free(p); } @@ -757,7 +701,7 @@ ula200_close(Driver *drvthis) * \return Number of characters the display is wide. */ MODULE_EXPORT int -ula200_width (Driver *drvthis) +ula200_width(Driver *drvthis) { PrivateData *p = (PrivateData *) drvthis->private_data; return p->width; @@ -770,7 +714,7 @@ ula200_width (Driver *drvthis) * \return Number of characters the display is high. */ MODULE_EXPORT int -ula200_height (Driver *drvthis) +ula200_height(Driver *drvthis) { PrivateData *p = (PrivateData *) drvthis->private_data; return p->height; @@ -782,7 +726,7 @@ ula200_height (Driver *drvthis) * \param drvthis Pointer to driver structure. */ MODULE_EXPORT void -ula200_clear (Driver *drvthis) +ula200_clear(Driver *drvthis) { PrivateData *p = (PrivateData *) drvthis->private_data; memset(p->framebuf, ' ', p->width * p->height); @@ -798,14 +742,14 @@ ula200_clear (Driver *drvthis) * \param c Character that gets written. */ MODULE_EXPORT void -ula200_chr (Driver *drvthis, int x, int y, char c) +ula200_chr(Driver *drvthis, int x, int y, char c) { PrivateData *p = (PrivateData *) drvthis->private_data; y--; x--; if ((x >= 0) && (y >= 0) && (x < p->width) && (y < p->height)) - p->framebuf[ (y * p->width) + x] = c; + p->framebuf[(y * p->width) + x] = c; } @@ -818,16 +762,16 @@ ula200_chr (Driver *drvthis, int x, int y, char c) * \param string String that gets written. */ MODULE_EXPORT void -ula200_string (Driver *drvthis, int x, int y, const char string[]) +ula200_string(Driver *drvthis, int x, int y, const char string[]) { PrivateData *p = (PrivateData *) drvthis->private_data; int i; - x --; // Convert 1-based coords to 0-based - y --; + x--; /* Convert 1-based coords to 0-based */ + y--; for (i = 0; string[i] != '\0'; i++) { - // Check for buffer overflows... + /* Check for buffer overflows... */ if ((y * p->width) + x + i > (p->width * p->height)) break; p->framebuf[(y * p->width) + x + i] = string[i]; @@ -841,24 +785,24 @@ ula200_string (Driver *drvthis, int x, int y, const char string[]) * \param on New backlight status. */ MODULE_EXPORT void -ula200_backlight (Driver *drvthis, int on) +ula200_backlight(Driver *drvthis, int on) { PrivateData *p = (PrivateData *) drvthis->private_data; unsigned char command[2]; int err; if (p->backlight != on) { - p->backlight = on; + p->backlight = on; - command[0] = 'h'; - command[1] = (on) ? '1' : '0'; - err = ula200_ftdi_write_command(drvthis, command, 2, false); - if (err < 0) + command[0] = 'h'; + command[1] = (on) ? '1' : '0'; + err = ula200_ftdi_write_command(drvthis, command, 2, false); + if (err < 0) report(RPT_WARNING, "%s: error in ula200_ftdi_write_command", - drvthis->name); + drvthis->name); else report(RPT_INFO, "%s: turn backlight %s", - drvthis->name, (on) ? "on" : "off"); + drvthis->name, (on) ? "on" : "off"); } } @@ -884,18 +828,18 @@ ula200_flush(Driver *drvthis) p->all_dirty = 0; } - // Update LCD incrementally by comparing with last contents + /* Update LCD incrementally by comparing with last contents */ count = 0; for (y = 0; y < p->height; y++) { drawing = 0; firstdiff = -1; lastdiff = 0; - for (x = 0 ; x < wid; x++) { + for (x = 0; x < wid; x++) { ch = p->framebuf[(y * wid) + x]; - if (ch != p->lcd_contents[(y*wid)+x]) { - p->lcd_contents[(y*wid)+x] = ch; - if (firstdiff == -1) { - firstdiff = x; + if (ch != p->lcd_contents[(y * wid) + x]) { + p->lcd_contents[(y * wid) + x] = ch; + if (firstdiff == -1) { + firstdiff = x; } lastdiff = x; } @@ -903,8 +847,8 @@ ula200_flush(Driver *drvthis) if (firstdiff >= 0) { ula200_ftdi_position(drvthis, firstdiff, y); - ula200_ftdi_string(drvthis, p->framebuf + (y*wid) + firstdiff, - lastdiff - firstdiff + 1); + ula200_ftdi_string(drvthis, p->framebuf + (y * wid) + firstdiff, + lastdiff - firstdiff + 1); } } } @@ -920,42 +864,41 @@ ula200_flush(Driver *drvthis) * \retval <0 Server core shall define/write the icon. */ MODULE_EXPORT int -ula200_icon (Driver *drvthis, int x, int y, int icon) +ula200_icon(Driver *drvthis, int x, int y, int icon) { - /* Yes I know, this is a VERY BAD implementation */ switch (icon) { case ICON_BLOCK_FILLED: - ula200_chr(drvthis, x, y, 0xff); - break; - case ICON_HEART_FILLED: - ula200_chr(drvthis, x, y, 2); - break; - case ICON_HEART_OPEN: - ula200_chr(drvthis, x, y, 1); - break; - case ICON_ARROW_UP: - ula200_chr(drvthis, x, y, 3); - break; - case ICON_ARROW_DOWN: - ula200_chr(drvthis, x, y, 4); - break; - case ICON_ARROW_LEFT: - ula200_chr(drvthis, x, y, 0x7F); - break; - case ICON_ARROW_RIGHT: - ula200_chr(drvthis, x, y, 0x7E); - break; - case ICON_CHECKBOX_OFF: - ula200_chr(drvthis, x, y, 5); - break; - case ICON_CHECKBOX_ON: - ula200_chr(drvthis, x, y, 6); - break; - case ICON_CHECKBOX_GRAY: - ula200_chr(drvthis, x, y, 7); - break; - default: - return -1; /* Let the core do other icons */ + ula200_chr(drvthis, x, y, 0xff); + break; + case ICON_HEART_FILLED: + ula200_chr(drvthis, x, y, 2); + break; + case ICON_HEART_OPEN: + ula200_chr(drvthis, x, y, 1); + break; + case ICON_ARROW_UP: + ula200_chr(drvthis, x, y, 3); + break; + case ICON_ARROW_DOWN: + ula200_chr(drvthis, x, y, 4); + break; + case ICON_ARROW_LEFT: + ula200_chr(drvthis, x, y, 0x7F); + break; + case ICON_ARROW_RIGHT: + ula200_chr(drvthis, x, y, 0x7E); + break; + case ICON_CHECKBOX_OFF: + ula200_chr(drvthis, x, y, 5); + break; + case ICON_CHECKBOX_ON: + ula200_chr(drvthis, x, y, 6); + break; + case ICON_CHECKBOX_GRAY: + ula200_chr(drvthis, x, y, 7); + break; + default: + return -1; /* Let the core do other icons */ } return 0; } @@ -968,22 +911,24 @@ ula200_icon (Driver *drvthis, int x, int y, int icon) * \c NULL for nothing available / unmapped key. */ MODULE_EXPORT const char * -ula200_get_key (Driver *drvthis) +ula200_get_key(Driver *drvthis) { PrivateData *p = drvthis->private_data; unsigned char key; int i; - // The libftdi has no non-blocking read (`select' system call), so we force - // a read that could not block by updating one character on the display. - // As long as lcdproc is single-threaded, we can write to the display because - // we're not inside a read here. + /* + * The libftdi has no non-blocking read (`select' system call), so we + * force a read that could not block by updating one character on the + * display. As long as lcdproc is single-threaded, we can write to + * the display because we're not inside a read here. + */ ula200_ftdi_position(drvthis, 0, 0); ula200_ftdi_string(drvthis, p->lcd_contents, 1); key = GetKeyFromKeyRing(&p->keyring); - // search the bit that was set by the hardware + /* search the bit that was set by the hardware */ for (i = 0; i < MAX_KEY_MAP; i++) { if (key & (1 << i)) return p->key_map[i]; @@ -994,4 +939,3 @@ ula200_get_key (Driver *drvthis) } return NULL; } - diff --git a/server/drivers/ula200.h b/server/drivers/ula200.h index 13f36b8..4763970 100644 --- a/server/drivers/ula200.h +++ b/server/drivers/ula200.h @@ -1,33 +1,28 @@ -/* This is the LCDproc driver header for ULA-200 (http://www.elv.de) +/** \file server/drivers/ula200.h + * This is the LCDproc driver header for ULA-200 (http://www.elv.de). + */ - Author: bernhard.walle@gmx.de +/*- + * Copyright (C) 2006 Bernhard Walle + * + * 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 + * any later version. - Copyright (C) 2006, Bernhard Walle + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. - 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 - any later version. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ #ifndef ULA200_H #define ULA200_H -#include "lcd.h" - -#ifndef bool -# define bool short -# define true 1 -# define false 0 -#endif - MODULE_EXPORT int ula200_init(Driver *drvthis); MODULE_EXPORT void ula200_close (Driver *drvthis); MODULE_EXPORT int ula200_width (Driver *drvthis); @@ -37,9 +32,7 @@ MODULE_EXPORT void ula200_string (Driver *drvthis, int x, int y, const char stri MODULE_EXPORT void ula200_chr (Driver *drvthis, int x, int y, char c); MODULE_EXPORT void ula200_backlight (Driver *drvthis, int on); MODULE_EXPORT void ula200_flush (Driver *drvthis); -MODULE_EXPORT void ula200_vbar (Driver *drvthis, int x, int y, int len, int promille, int options); -MODULE_EXPORT void ula200_hbar (Driver *drvthis, int x, int y, int len, int promille, int options); -MODULE_EXPORT void ula200_num (Driver *drvthis, int x, int num); MODULE_EXPORT int ula200_icon(Driver *drvthis, int x, int y, int icon); MODULE_EXPORT const char * ula200_get_key (Driver *drvthis); + #endif /* ULA200_H */