From faa4861eb39c23c347b0d61c01f989957a390628 Mon Sep 17 00:00:00 2001 From: robijn Date: Thu, 1 Nov 2001 00:37:12 +0000 Subject: [PATCH] HD44780 update: - supports new API - major clean up, more consistent code - uses configfile options - serialLpt works also with only 2 output lines - serialLpt can now use keypad --- LCDd.conf | 39 +- docs/hd44780_howto.txt | 237 +++++++++-- server/drivers/hd44780-4bit.c | 111 +++--- server/drivers/hd44780-ext8bit.c | 70 ++-- server/drivers/hd44780-low.h | 23 +- server/drivers/hd44780-serialLpt.c | 121 +++--- server/drivers/hd44780-winamp.c | 65 ++-- server/drivers/hd44780.c | 605 +++++++++++++++-------------- server/drivers/hd44780.h | 9 +- 9 files changed, 786 insertions(+), 494 deletions(-) diff --git a/LCDd.conf b/LCDd.conf index 3a0b7dc..6002036 100644 --- a/LCDd.conf +++ b/LCDd.conf @@ -37,8 +37,8 @@ [server] # Server section with all kinds of settings for the LCDd server -Driver=HD44780 -#Driver=curses +Driver=curses +#Driver=HD44780 #Driver=MtxOrb # # Tells the server to load the given drivers. Multiple lines can be given. @@ -46,7 +46,7 @@ Driver=HD44780 Bind=127.0.0.1 # Tells the driver to bind to the given interface -Port=3777 +Port=13666 # Listen on this specified port; defaults to 13666. #Debug=5 @@ -59,10 +59,10 @@ User=nobody # User to run as. LCDd will drop its root priviledges, # if any, and run as this user instead. -EnableServerScreen=yes +ServerScreen=no # Enables the server screen also when other screens are active. -Foreground=no +Foreground=yes # The server will stay in the foreground if set to true. @@ -94,13 +94,30 @@ Arguments="-d /dev/ttyS0 -t 20x2 -c 120" # Hitachi HD44780 driver # See docs/hd44780_howto.txt -Arguments="-p 0x378 -c 4bit -k -b" +Port=0x378 +# Port where the LPT is. Usual values are 0x278, 0x378 and 0x3BC -# Meaning: -# -p Use the given port -# -c Use the given connectiontype -# -k Keypad support -# -b Backlight support +ConnectionType=4bit +# Select what type of connection. See documentation for types. + +Keypad=no +# If you have a keypad connected. Keypad layout is currently not +# configureable from the config file. + +Backlight=no +# If you have a switchable backlight. + +Size=20x4 +# Specifies the size of the LCD. +# In case of multiple combined displays, this should be the total size. + +#vspan=1,2 +# For multiple displays: at what 'logical' lines do the individual displays +# start. + +#extended=yes +# If you want to use more than 3 HD44780 controllers on the LPT, you need to +# specify this. See documentation. [LB216] diff --git a/docs/hd44780_howto.txt b/docs/hd44780_howto.txt index 05bdfa1..f60bedb 100644 --- a/docs/hd44780_howto.txt +++ b/docs/hd44780_howto.txt @@ -79,7 +79,7 @@ to the input pins. If you connect a key like sketched below, then you can only connect one key per input pin. It is a simple solution if you need only few keys. - + 5V + O 5V | | - @@ -136,7 +136,7 @@ Y1 o---|<---@--@--@ | | | Y2 o---|<---@--@--@ | | | -Y3 o---|<---@--@--@ + 5V +Y3 o---|<---@--@--@ O 5V | | | | diodes | | | ___ | 1N4148 +----------|___|---+ @@ -168,6 +168,54 @@ You can buy arrays of keys that are connected like this in the electronics shop. They usually call it a matrix keypad. To hook it to lcdproc, you would only need to add the resistors and diodes. +If the driver generates keypresses without that you actually press a key, +it might be that the unconnected input lines are picking up +electromagnetic waves from the air. In that case connect the unconnected +input lines (pin 10, 11, 12, 13 and 15 of the LPT) to VCC. + + +1.1.3 Backlight +--------------- + +A small extension allows you to switch the backlight of the display on +and off. At the moment only the 4bit and winamp connection types support +this. The extension uses one output pin, you cannot use that pin for other +functions anymore. The wiring looks like this: + + O 5V + ___ | + +---|___|--------+ +LPT Sub-D connector | 4k7 | + | |e + | ___ b |/ + BL pin o---------------+---|___|------| + 330E |\ + bc327 |c + | LCD connector + | + +--------o 15 backlight + + +--------o 16 GND backlight + | + === GND + +Note: 4k7 means 4,7 kohm and 330E means 330 ohm. +The BC327 has the following connections: + + _____ + | | + |bc327| + |_____| + | | | + | | | + | | | + c b e + +Sometimes the backlight connections are not on the 'main' connector, but on +the side. If that is the case, there is usually NO RESISTOR present to limit +the current through the LEDs. Therefor you should add a resistor after +the transistor of 10 ohm. + 1.2 4-bit ---------- @@ -219,6 +267,8 @@ The optional keypad can be connected as follows: SELIN (13) X3 nFAULT (15) X4 +The optional backlight wiring should be connected to D5, pin 7. + 1.3 8-bit "Winamp" ------------------- @@ -267,6 +317,8 @@ The optional keypad can be connected as follows: SELIN (13) X3 nFAULT (15) X4 +The optional backlight wiring should be connected to nSEL, pin 17. + 1.4 Extended 8-bit "lcdtime" ----------------------------- @@ -280,6 +332,9 @@ http://metalab.unc.edu/pub/linux/system/status/lcdtime-0.2.tar.gz http://metalab.unc.edu/pub/linux/system/status/meter-0.2.tar.gz http://metalab.unc.edu/pub/linux/system/status/portato-1.2.tar.gz +Theoretically this wiring sends the data over twice as slow as the +winamp or ext8bit wirings, because it only sends 4 bits at a time. + The LCD connections are: printer port LCD @@ -321,16 +376,153 @@ The optional keypad can be connected as follows: SELIN (13) X3 nFAULT (15) X4 +The backlight wiring should be attached to nSEL, pin 17. Because the portato +program (mentioned above) also uses this pin to control the bargraph, you +cannot use the backlight control together with the bargraph. + 1.5 Serial LPT --------------- This interface uses a handful of wires to interface to the HD44780. Suitable for high noise, long connections. Designed by -Andrew McMeikan . Refer to -http://members.xoom.com/andrewmuck for details of the connections. +Andrew McMeikan . The original wiring and +driver can be found at: +http://members.xoom.com/andrewmuck -Note from Joris: I still need to add keypad stuff here +I (Joris) have extended this driver and the wiring a bit. It now supports +keys again (it had earlier supported keys, but some time did not). + +Further I have extended the driver and the wiring to be able to run +using 2 instead of 3 output pins. That's even one less pin ! :) + +Of course the use of fewer lines than the other wirings can not stay +without drawbacks. In this case the simplicity of the long feeding wires +is compensated by some intelligence in the decoding of the data. If you +have no experience with the soldering iron, I do not recommend to build +this wiring. + +OK, so here is the wiring. First of the 'simple' 3 wires version. IC1 is +the shift register, a 4094. Do not forget to connect the 5V to pin 16 and +GND to pin 8 of the IC. + + IC1 + ----------- + | 4094 | + 5V | shift reg | display + O | | /keys + | 1| |3 + +----|STR Q0|---------------------o 7 D0 + | | |4 /Y0 + Data | 2| Q1|---------------------o 8 D1 + D3 5 o---------------------------|D |5 /Y1 + | | Q2|---------------------o 9 D2 + | 3|CK |6 /Y2 + D4 6 o---------------------------| Q3|---------------------o 10 D3 + | | |10 /Y3 + | 15| Q4|---------------------o Y4 + +----|OE |11 + | Q5|---------------------o 4 RS + | |12 /Y5 + | Q6|---------------------o Y6 + | |13 + | Q7|---------------------o Y7 + | |9 + | QS|-- +--o 5 RW + | __|10 | + | QS|-- === + | | + ----------- + + + D2 4 o-------------------------------------------------------------o 6 EN + + D7 9 o-------------------------------------------------------------o 6 EN2 + (2nd LCD) + + + 5V O-----+--------+----------------------------------+-----o 2 VCC + | | | + | | | + |100n O 16 .-. + --- IC1 | |<---o 3 Vlcd + --- O 8 | |10k + | | '-' + GND | | | + 18..25 o-----------+--------+--------------------------+-------+-----o 1 GND + | + === GND + + + +The second possible wiring is with 2 output lines. This one is a bit more +complex. If you do not understand the schematic, do not build it. + + IC2 + ----------- + | 74HCT164 | + | shift reg | display + | | /keys + Data 1| |3 + D3 5 o-----------------------+---|D Q0|---------------------o 7 D0 + | | |4 /Y0 + | 2| Q1|---------------------o 8 D1 + +---|D |5 /Y1 + | Q2|---------------------o 9 D2 + | |6 /Y2 + | Q3|---------------------o 10 D3 + | |10 /Y3 + Clock 8| Q4|---------------------o Y4 + D4 6 o---------------------------|CK |11 + | Q5|---------------------o 4 RS + ___ 9|\ 8 9|_ |12 /Y5 + +--|___|--+----| >o----|R Q6|---------------------o Y6 + | 22k | |/ | |13 + | --- IC1 | Q7|---+ +--o 5 RW + | --- | | | 5V | + | |100p ----------- | O === + | | | | + | === | .-. + | | | |22k + +--------------------------------------+ | | + | '-' + | ___ 11|\ 10 | 5|\ 6 + +--|___|--+----| >o-------------------||----+-----| >o---o 6 EN + 22k | |/ 22p |/ + --- IC1 IC1 + --- + |22p + | IC1=74HCT14 (6x Schmitt trigger inverter) + === + + + 5V O--+-------+------+------+------------------------+-----o 2 VCC + | | | | 13|\ 12 | + | | | +---| >o- | + |100n O 14 O 14 |/ .-. + --- IC1 IC2 | |<---o 3 Vlcd + --- O 7 O 7 1|\ 2 3|\ 4 | |10k + | | | +--| >o- +--| >o- '-' + GND | | | | |/ | |/ | + 18..25 o--------+-------+------+-------+----------+-----+------+-----o 1 GND + | + === GND + +Also the serialLpt wiring supports a keypad. The 3 wires version supports +8 keys, or if you use multiple return lines up to 8 x 5 = 40 lines. The +2 wires version supports 7 keys, or with multiple return lines +7 x 5 = 35 keys. + +The return lines are the following: + + nACK (10) X0 + BUSY (11) X1 + PAPEREND (12) X2 + SELIN (13) X3 + nFAULT (15) X4 + +To understand some of this keypad documentation, do also read the keypad +section in this document. 2. Compiling @@ -344,33 +536,17 @@ can be done by specifying "--enable-drivers=all" or by 3. Running ---------- -Keep in mind the following points. +Modify the LCDd.conf file before you run LCDd. In this config file are +detailed instructions on how to configure the HD44780 driver. -- When specifying the lcd size, do so before the -d argument. -- Arguments that need to be passed to the driver should be in quotes after - the -d HD44780 arguments. -- Use the "-e" argument for extended interfaces (e.g. 3 or more displays as - indicated by "optional" connections above). -- Use "-k" to enable the keypad code. +Then as usual, start LCDd with the correct config file: + LCDd -c ./LCDd.conf +for example. - -EXAMPLES: - - For a 4bit connection, 16x2 display on port 0x278 - LCDd -t 16x2 -d HD44780 "-p 0x278" - - For a 4bit, 40x4 display (effectively two 40x2 displays) - LCDd -t 40x4 -d HD44780 "-v 2,2" - - For a Winamp connection, 20x2 and 20x1 displays - LCDd -t 20x3 -d HD44780 "-c winamp -v 2,1" - - For a 4bit, 16x2, 16x4 and 16x1 displays - LCDd -t 16x7 -d HD44780 "-v 2,4,1 -e" - - For help on the parameters for the 8-bit driver (make sure --help is the - last arguments in quotes): - LCDd -d HD44780 "-c 8bit --help" +If you want to override the driver selection in LCDd.conf then use: + LCDd -c ./LCDd.conf -d HD44780 +If you use this, the HD44780 driver will read the options from the config +file. 4. Miscellania @@ -381,3 +557,4 @@ This text originally taken from a message by Bill Farrow Updated February 2000, Benjamin Tse (blt@ComPorts.com) +Updated October 2001, Joris Robijn (joris at robijn.net) diff --git a/server/drivers/hd44780-4bit.c b/server/drivers/hd44780-4bit.c index fa016f7..2a3f578 100644 --- a/server/drivers/hd44780-4bit.c +++ b/server/drivers/hd44780-4bit.c @@ -20,7 +20,11 @@ * D6 (8) EN (6) * D7 (9) EN2 (LCD2 - 6) (optional) * + * Backlight + * D5 (7) backlight (optional, see documentation) + * * Extended interface (including LCD3 above) + * D5 (7) EN3 * STR (1) EN4 * LF (14) EN5 * INIT (16) EN6 @@ -66,34 +70,37 @@ #include // Generally, any function that accesses the LCD control lines needs to be -// implemented separately for each HW design. This is typically just -// HD44780_senddata and HD44780_readkeypad +// implemented separately for each HW design. This is typically (but not +// restricted to): +// HD44780_senddata +// HD44780_readkeypad void lcdstat_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch); +void lcdstat_HD44780_backlight (unsigned char state); unsigned char lcdstat_HD44780_readkeypad (unsigned int YData); -#define RS 0x10 -#define RW 0x20 -#define EN1 0x40 -#define EN2 0x80 -#define EN3 0x20 +#define RS 0x10 +#define RW 0x20 +#define EN1 0x40 +#define EN2 0x80 +#define EN3 0x20 +#define BL 0x20 +// note that the above bits are all meant for the data port of LPT static unsigned char EnMask[] = { EN1, EN2, EN3, STRB, LF, INIT, SEL }; -static int EnMaskSize = sizeof (EnMask) / sizeof (unsigned char); -static int extIF = 0; // non-zero if extended interface +#define ALLEXT (STRB|LF|INIT|SEL) +// The above bits are on the control port of LPT + static unsigned int lptPort; -static char stuckinputs = 0; // if an input line is stuck, it will be ignored +static char stuckinputs = 0; // if an input line is stuck, it will be ignored +static char backlight_bit = 0; // default to low to enable three displays // initialisation function int hd_init_4bit (HD44780_functions * hd44780_functions, lcd_logical_driver * driver, char *args, unsigned int port) { - // TODO: remove magic numbers below - char *argv[64]; - int argc; - int i; - int displayID = EN1 | EN2; + int enableLines = EN1 | EN2; // Reserve the port registers lptPort = port; @@ -102,44 +109,36 @@ hd_init_4bit (HD44780_functions * hd44780_functions, lcd_logical_driver * driver port_access(lptPort+2); hd44780_functions->senddata = lcdstat_HD44780_senddata; + hd44780_functions->backlight = lcdstat_HD44780_backlight; hd44780_functions->readkeypad = lcdstat_HD44780_readkeypad; - // parse command-line arguments - argc = get_args (argv, args, 64); - - for (i = 0; i < argc; ++i) { - if (strcmp (argv[i], "-e") == 0 || strcmp (argv[i], "--extended") == 0) { - extIF = 1; - } - } - // powerup the lcd now if (extIF) { - displayID |= EN3; + enableLines |= EN3; port_out (lptPort + 2, 0 ^ OUTMASK); } - port_out (lptPort, displayID | 0x03); + port_out (lptPort, enableLines | 0x03); if (extIF) - port_out (lptPort + 2, (EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK); + port_out (lptPort + 2, ALLEXT ^ OUTMASK); hd44780_functions->uPause (1); port_out (lptPort, 0x03); if (extIF) port_out (lptPort + 2, 0 ^ OUTMASK); hd44780_functions->uPause (4100); - port_out (lptPort, displayID | 0x03); + port_out (lptPort, enableLines | 0x03); if (extIF) - port_out (lptPort + 2, (EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK); + port_out (lptPort + 2, ALLEXT ^ OUTMASK); hd44780_functions->uPause (1); port_out (lptPort, 0x03); if (extIF) port_out (lptPort + 2, 0 ^ OUTMASK); hd44780_functions->uPause (100); - port_out (lptPort, displayID | 0x03); + port_out (lptPort, enableLines | 0x03); if (extIF) - port_out (lptPort + 2, (EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK); + port_out (lptPort + 2, ALLEXT ^ OUTMASK); hd44780_functions->uPause (1); port_out (lptPort, 0x03); if (extIF) @@ -147,9 +146,9 @@ hd_init_4bit (HD44780_functions * hd44780_functions, lcd_logical_driver * driver hd44780_functions->uPause (40); // now in 8-bit mode... set 4-bit mode - port_out (lptPort, displayID | 0x02); + port_out (lptPort, enableLines | 0x02); if (extIF) - port_out (lptPort + 2, (EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]) ^ OUTMASK); + port_out (lptPort + 2, ALLEXT ^ OUTMASK); hd44780_functions->uPause (1); port_out (lptPort, 0x02); if (extIF) @@ -168,16 +167,18 @@ hd_init_4bit (HD44780_functions * hd44780_functions, lcd_logical_driver * driver // lcdstat_HD44780_senddata void -lcdstat_HD44780_senddata (unsigned char displayID, unsigned char iflags, unsigned char ch) +lcdstat_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch) { - unsigned char enableLines = 0, flags = 0; + unsigned char enableLines = 0, portControl = 0; unsigned char h = (ch >> 4) & 0x0f; // high and low nibbles unsigned char l = ch & 0x0f; - if (iflags == RS_INSTR) - flags = 0; - else //if (iflags == RS_DATA) - flags = RS; + if (flags == RS_INSTR) + portControl = 0; + else //if (flags == RS_DATA) + portControl = RS; + + portControl |= backlight_bit; if (displayID <= 3) { if (displayID == 0) @@ -185,36 +186,43 @@ lcdstat_HD44780_senddata (unsigned char displayID, unsigned char iflags, unsigne else enableLines = EnMask[displayID - 1]; - port_out (lptPort, flags | h); + port_out (lptPort, portControl | h); hd44780_functions->uPause (2); - port_out (lptPort, enableLines | flags | h); + port_out (lptPort, enableLines | portControl | h); hd44780_functions->uPause (4); - port_out (lptPort, flags | h); + port_out (lptPort, portControl | h); - port_out (lptPort, enableLines | flags | l); + port_out (lptPort, enableLines | portControl | l); hd44780_functions->uPause (4); - port_out (lptPort, flags | l); + port_out (lptPort, portControl | l); } if (extIF && (displayID == 0 || displayID >= 4)) { if (displayID == 0) - enableLines = EnMask[3] | EnMask[4] | EnMask[5] | EnMask[6]; + enableLines = ALLEXT; else - enableLines = EnMask[(displayID - 1) % EnMaskSize]; + enableLines = EnMask[(displayID - 1)]; - port_out (lptPort, flags | h); + port_out (lptPort, portControl | h); hd44780_functions->uPause (2); port_out (lptPort + 2, enableLines ^ OUTMASK); hd44780_functions->uPause (4); port_out (lptPort + 2, 0 ^ OUTMASK); - port_out (lptPort, flags | l); + port_out (lptPort, portControl | l); port_out (lptPort + 2, enableLines ^ OUTMASK); hd44780_functions->uPause (4); port_out (lptPort + 2, 0 ^ OUTMASK); } } +void lcdstat_HD44780_backlight (unsigned char state) +{ + backlight_bit = (state?0:0x20); // D5 line + + port_out (lptPort, backlight_bit); +} + unsigned char lcdstat_HD44780_readkeypad (unsigned int YData) { unsigned char readval; @@ -226,7 +234,12 @@ unsigned char lcdstat_HD44780_readkeypad (unsigned int YData) port_out (lptPort + 2, ( ((~YData & 0x03C0) << 6 )) ^ OUTMASK); } - // And convert it back. + // Read inputs readval = ~ port_in (lptPort + 1) ^ INMASK; + + // Put port back into idle state for backlight + port_out (lptPort, backlight_bit ^ OUTMASK); + + // And convert value back. return ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) ) & ~stuckinputs; } diff --git a/server/drivers/hd44780-ext8bit.c b/server/drivers/hd44780-ext8bit.c index 40c8474..f2a8102 100644 --- a/server/drivers/hd44780-ext8bit.c +++ b/server/drivers/hd44780-ext8bit.c @@ -16,11 +16,13 @@ * D5 (7) D5 (12) * D6 (8) D6 (13) * D7 (9) D7 (14) - * nSEL (17) - * nSTRB (1) RS (4) * nLF (14) RW (5) (LCD2 - 6) (optional - pull all LCD RW low) * INIT (16) EN (6) * + * Backlight + * SEL (17) backlight (optional, see documentation) + * * Keypad connection (optional): * Some diodes and resistors are needed, see further documentation. * printer port keypad @@ -65,20 +67,17 @@ // HD44780_readkeypad void lcdtime_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch); +void lcdtime_HD44780_backlight (unsigned char state); unsigned char lcdtime_HD44780_readkeypad (unsigned int YData); -#define nRS nSTRB -#define nRW nLF -#define EN1 INIT -#define METER_OFF nSEL +#define RS STRB +#define RW LF +#define EN1 INIT +#define BL SEL -#define SETUPLCD (METER_OFF | nRS) -#define CTRL (nRW | METER_OFF | nRS) -#define CHAR (nRW | METER_OFF) - -static int extIF = 0; // non-zero if extended interface static unsigned int lptPort; -static char stuckinputs = 0; // if an input line is stuck, it will be ignored +static char stuckinputs = 0; // if an input line is stuck, it will be ignored +static char backlight_bit = 0; static int semid; @@ -95,6 +94,7 @@ hd_init_ext8bit (HD44780_functions * hd44780_functions, lcd_logical_driver * dri port_access(lptPort+2); hd44780_functions->senddata = lcdtime_HD44780_senddata; + hd44780_functions->backlight = lcdtime_HD44780_backlight; hd44780_functions->readkeypad = lcdtime_HD44780_readkeypad; // setup the lcd in 8 bit mode @@ -106,6 +106,11 @@ hd_init_ext8bit (HD44780_functions * hd44780_functions, lcd_logical_driver * dri hd44780_functions->uPause (40); common_init (); + + if (have_keypad) { + // Remember which input lines are stuck + stuckinputs = lcdtime_HD44780_readkeypad (0); + } return 0; } @@ -113,31 +118,42 @@ hd_init_ext8bit (HD44780_functions * hd44780_functions, lcd_logical_driver * dri void lcdtime_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch) { - unsigned char dispID = 0, portControl; + unsigned char enableLines = 0, portControl; - if (displayID == 1) - dispID |= EN1; - else //if (displayID == 0) - dispID |= EN1; + // Only one controller is supported + enableLines = EN1; - if (flags == RS_DATA) - portControl = CHAR; - else - portControl = CTRL; + if (flags == RS_INSTR) + portControl = 0; + else //if (iflags == RS_DATA) + portControl = RS; + + portControl |= backlight_bit; sem_wait (semid); - port_out (lptPort + 2, SETUPLCD); + port_out (lptPort + 2, portControl ^ OUTMASK); port_out (lptPort, ch); - port_out (lptPort + 2, dispID | portControl); + port_out (lptPort + 2, (enableLines|portControl) ^ OUTMASK); hd44780_functions->uPause (1); - port_out (lptPort + 2, portControl); + port_out (lptPort + 2, portControl ^ OUTMASK); sem_signal (semid); } +void lcdtime_HD44780_backlight (unsigned char state) +{ + backlight_bit = (state?0:SEL); + + // Semaphores not needed because backlight will not go together with + // the bacrgraph anyway... + port_out (lptPort + 2, backlight_bit ^ OUTMASK); +} + unsigned char lcdtime_HD44780_readkeypad (unsigned int YData) { unsigned char readval; + sem_wait (semid); + // 10 bits output // Convert the positive logic to the negative logic on the LPT port port_out (lptPort, ~YData & 0x00FF ); @@ -145,7 +161,13 @@ unsigned char lcdtime_HD44780_readkeypad (unsigned int YData) port_out (lptPort + 2, ( ((~YData & 0x0100) >> 8) | ((~YData & 0x0200) >> 6)) ^ OUTMASK); } - // And convert it back. + // Read inputs readval = ~ port_in (lptPort + 1) ^ INMASK; + + // Put port back into idle state for backlight + port_out (lptPort, backlight_bit ^ OUTMASK); + sem_signal (semid); + + // And convert value back. return ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) ) & ~stuckinputs; } diff --git a/server/drivers/hd44780-low.h b/server/drivers/hd44780-low.h index a69cf83..80b27d2 100644 --- a/server/drivers/hd44780-low.h +++ b/server/drivers/hd44780-low.h @@ -14,26 +14,29 @@ typedef struct hwDependentFns { // microsec pauses void (*uPause) (int microSecondsTenths); - // senddata to the LCD + // Senddata to the LCD // dispID - display to send data to (0 = all displays) // flags - data or instruction command (RS_DATA | RS_INSTR) // ch - character to display or instruction value void (*senddata) (unsigned char dispID, unsigned char flags, unsigned char ch); - // position the cursor - // dispID - display to send data to (0 = all displays) - // DDaddr - display data address (see sect 2.5.2 of the LCD module FAQ) - void (*position) (int dispID, int DDaddr); + // Switch the backlight on or off + // state - to be or not to be on + void (*backlight) (unsigned char state); - // toggle vertical autoscroll on all displays - // on - non-zero turns autoscroll on, zero value turns it off - void (*autoscroll) (int on); - - // read the keypad + // Read the keypad // Ydata - the up to 11 bits that should be put on the Y side of the matrix // return - the up to 5 bits that are read out on the X side of the matrix unsigned char (*readkeypad) (unsigned int Ydata); + // Scan the keypad and return a scancode. + // The code is the Yvalue in the high nibble and the Xvalue in the low nibble. + // A subdriver should do only one of two things: + // - set readkeypad; or + // - override scankeypad. + unsigned char (*scankeypad) (); + + } HD44780_functions; /* for want of a better name :-) */ extern HD44780_functions *hd44780_functions; diff --git a/server/drivers/hd44780-serialLpt.c b/server/drivers/hd44780-serialLpt.c index 01b729b..3b01215 100644 --- a/server/drivers/hd44780-serialLpt.c +++ b/server/drivers/hd44780-serialLpt.c @@ -36,6 +36,7 @@ * Q4 (7) Y3 * Q5 (14) Y4 * Q6 (13) Y5 + * Q7 (12) Y6 * The 'output' of the keys should be connected to the following LPT pins: * nACK (10) X0 * BUSY (11) X1 @@ -59,9 +60,9 @@ // Hardware specific functions void lcdserLpt_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch); -unsigned char lcdserLpt_HD44780_readkeypad (unsigned int YData); +void lcdserLpt_HD44780_backlight (unsigned char state); -static char lcdserLpt_HD44780_getkey (void); // old keypad code +unsigned char lcdserLpt_HD44780_scankeypad (); void rawshift (unsigned char r); void shiftreg (unsigned char displayID, unsigned char r); @@ -72,9 +73,6 @@ void shiftreg (unsigned char displayID, unsigned char r); #define EN2 32 static unsigned int lptPort; -static char stuckinputs = 0; // if an input line is stuck, it will be ignored - -static char lastkey = 0; // currently not in use, old keypad code // Initialisation int @@ -89,11 +87,9 @@ hd_init_serialLpt (HD44780_functions * hd44780_functions, lcd_logical_driver * d port_access(lptPort+2); hd44780_functions->senddata = lcdserLpt_HD44780_senddata; - hd44780_functions->readkeypad = lcdserLpt_HD44780_readkeypad; + hd44780_functions->backlight = lcdserLpt_HD44780_backlight; + hd44780_functions->scankeypad = lcdserLpt_HD44780_scankeypad; - if (have_keypad) { - driver->getkey = lcdserLpt_HD44780_getkey; - } // Clear the shiftregister rawshift (0); @@ -114,17 +110,6 @@ hd_init_serialLpt (HD44780_functions * hd44780_functions, lcd_logical_driver * d common_init (); - /* - // set display type functions - lcdserLpt_HD44780_senddata (0, RS_INSTR, FUNCSET | IF_4BIT | TWOLINE | SMALLCHAR); - // clear - lcdserLpt_HD44780_senddata (0, RS_INSTR, CLEAR); - hd44780_functions->uPause (1600); - // Now turn on the display - lcdserLpt_HD44780_senddata (displayID, RS_INSTR, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK); - hd44780_functions->uPause (1600); - */ - return 0; } @@ -149,47 +134,67 @@ lcdserLpt_HD44780_senddata (unsigned char displayID, unsigned char flags, unsign shiftreg (enableLines, portControl | h); shiftreg (enableLines, portControl | l); - - /* TODO: instead of delay read keys here */ } -char -lcdserLpt_HD44780_getkey () +void +lcdserLpt_HD44780_backlight (unsigned char state) { - // TODO: a keypad scan that does not use shift register - // define a key table - char keytr[] = "ABCDEFGH"; - int n; +} - // disabled now ! - return 0; +unsigned char lcdserLpt_HD44780_scankeypad () +{ + // Unfortunately just bit shifting does not work with the 2 IC version... - rawshift (0); //send all line on shift register low - hd44780_functions->uPause (1); - if ((port_in (lptPort + 1) & 32) == 0) //test if line back is low - if not return(0) - { //else - //start walking a single zero across the eight lines - for (n = 7; n >= 0; n--) { - rawshift (255 - (1 << n)); - hd44780_functions->uPause (1); + unsigned char keybits; + unsigned int shiftcount; + unsigned int shiftingbit; + unsigned char readval, inputs_zero, r; + int i; + unsigned int scancode = 0; - if ((port_in (lptPort + 1) & 32) == 0) // check if line back is low if yes debounce - { - if (lastkey == keytr[n]) - return (0); - // printf("key is %c %d\n",keytr[n],n); - lastkey = keytr[n]; - return (keytr[n]); //return correct key code. + + r = 0xFF; // This command will set the cursor position, so it's harmless + + readval = ~ port_in (lptPort + 1) ^ INMASK; + inputs_zero = ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) ); + + if( inputs_zero == 0 ) { + return 0; + } + + // Scan the keypad while sending the first half of the command (high nibble) + for (i = 7; i >= 0; i--) { /* MSB first */ + port_out (lptPort, ((r >> i) & 1) * LCDDATA); /*set up data */ + port_out (lptPort, (((r >> i) & 1) * LCDDATA) | LCDCLOCK); /*rising edge of clock */ + + hd44780_functions->uPause (2); + + // Do keyscan too ! + if( !scancode ) { + // Read input line(s) + readval = ~ port_in (lptPort + 1) ^ INMASK; + keybits = ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) ); + if( keybits != inputs_zero ) { + shiftingbit = 1; + for (shiftcount=0; shiftcountuPause (4); + + // And again for the second half of the command (low nibble) + rawshift (r); + + hd44780_functions->uPause (4); + + return scancode; } /* this function sends r out onto the shift register */ @@ -197,6 +202,8 @@ void rawshift (unsigned char r) { int i; + // r |= 0x80; // just to make sure ... + for (i = 7; i >= 0; i--) { /* MSB first */ port_out (lptPort, ((r >> i) & 1) * LCDDATA); /*set up data */ port_out (lptPort, (((r >> i) & 1) * LCDDATA) | LCDCLOCK); /*rising edge of clock */ @@ -207,13 +214,9 @@ rawshift (unsigned char r) void shiftreg (unsigned char enableLines, unsigned char r) { - //unsigned char mr; - //mr = (r & 0xF0) | ((r<<3) & 0x0F) | ((r<<1) & 0x04) | - // ((r>>1) & 0x02) | ((r>>3) & 0x01); - - rawshift (r | 0x80); // highest bit always set to 1 for Clear - port_out (lptPort, enableLines); //latch it, to correct display + rawshift (r | 0x80); // highest bit always set to 1 for Clear for wiring with 2 ICs + port_out (lptPort, enableLines); // latch it, to correct display hd44780_functions->uPause (1); - port_out (lptPort, 0); + port_out (lptPort, 0); // for wiring with 1 IC hd44780_functions->uPause (3); } diff --git a/server/drivers/hd44780-winamp.c b/server/drivers/hd44780-winamp.c index 543e9e2..61ec1f6 100644 --- a/server/drivers/hd44780-winamp.c +++ b/server/drivers/hd44780-winamp.c @@ -29,6 +29,9 @@ * INIT (16) RS (4) * nSEL (17) EN2 (6 - LCD 2) (optional) * + * Backlight + * SEL (17) backlight (optional, see documentation) + * * Keypad connection (optional): * Some diodes and resistors are needed, see further documentation. * printer port keypad @@ -64,32 +67,33 @@ #include #include -#include "port.h" +// Generally, any function that accesses the LCD control lines needs to be +// implemented separately for each HW design. This is typically (but not +// restricted to): +// HD44780_senddata +// HD44780_readkeypad void lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch); +void lcdwinamp_HD44780_backlight (unsigned char state); unsigned char lcdwinamp_HD44780_readkeypad (unsigned int YData); -#define EN1 STRB -#define EN2 SEL -#define EN3 LF -#define RS INIT +#define EN1 STRB +#define EN2 SEL +#define EN3 LF +#define RW LF +#define RS INIT +#define BL SEL static unsigned char EnMask[] = { EN1, EN2, EN3 }; -static int EnMaskSize = sizeof (EnMask) / sizeof (unsigned char); -static int extIF = 0; // non-zero if extended interface static unsigned int lptPort; -static char stuckinputs = 0; // if an input line is stuck, it will be ignored +static char stuckinputs = 0; // if an input line is stuck, it will be ignored +static char backlight_bit = 0; // default to low to enable two displays // initialise the driver int hd_init_winamp (HD44780_functions * hd44780_functions, lcd_logical_driver * driver, char *args, unsigned int port) { - // TODO: remove magic numbers below - char *argv[64]; - int argc; - int i; - // Reserve the port registers lptPort = port; port_access(lptPort); @@ -97,16 +101,9 @@ hd_init_winamp (HD44780_functions * hd44780_functions, lcd_logical_driver * driv port_access(lptPort+2); hd44780_functions->senddata = lcdwinamp_HD44780_senddata; + hd44780_functions->backlight = lcdwinamp_HD44780_backlight; hd44780_functions->readkeypad = lcdwinamp_HD44780_readkeypad; - // parse command-line arguments - argc = get_args (argv, args, 64); - - for (i = 0; i < argc; ++i) { - if (strcmp (argv[i], "-e") == 0 || strcmp (argv[i], "--extended") == 0) - extIF = 1; - } - // setup the lcd in 8 bit mode hd44780_functions->senddata (0, RS_INSTR, FUNCSET | IF_8BIT); hd44780_functions->uPause (4100); @@ -123,7 +120,7 @@ hd_init_winamp (HD44780_functions * hd44780_functions, lcd_logical_driver * driv void lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch) { - unsigned char dispID = 0, portControl; + unsigned char enableLines = 0, portControl; if (flags == RS_DATA) portControl = RS; @@ -131,29 +128,36 @@ lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsign portControl = 0; if (displayID == 0) - dispID = EnMask[0] | EnMask[1] | ((extIF) ? EnMask[2] : 0); + enableLines = EnMask[0] | EnMask[1] | ((extIF) ? EnMask[2] : 0); else - dispID = EnMask[displayID - 1]; + enableLines = EnMask[displayID - 1]; // 40 nS setup time for RS valid to EN high, so set RS - port_out (lptPort + 2, portControl ^ OUTMASK); + port_out (lptPort + 2, (portControl|backlight_bit) ^ OUTMASK); // Output the actual data port_out (lptPort, ch); // then set EN high - port_out (lptPort + 2, (dispID | portControl) ^ OUTMASK); + port_out (lptPort + 2, (enableLines|portControl|backlight_bit) ^ OUTMASK); // 80 nS setup from valid data to EN low will be met without any delay // unless you are running a REALLY FAST ISA bus (like 75 MHZ!) // 230 nS minimum E high time provided by ISA bus delays as well... // Set EN low and we're done... - port_out (lptPort + 2, portControl ^ OUTMASK); + port_out (lptPort + 2, (portControl|backlight_bit) ^ OUTMASK); // 10 nS data hold time provided by the length of ISA write for EN } +void lcdwinamp_HD44780_backlight (unsigned char state) +{ + backlight_bit = (state?0:nSEL); + + port_out (lptPort + 2, backlight_bit ^ OUTMASK); +} + unsigned char lcdwinamp_HD44780_readkeypad (unsigned int YData) { unsigned char readval; @@ -163,7 +167,12 @@ unsigned char lcdwinamp_HD44780_readkeypad (unsigned int YData) port_out (lptPort, ~YData & 0x00FF ); port_out (lptPort + 2, ( ((~YData & 0x0100) >> 7) | ((~YData & 0x0200) >> 7 )) ^ OUTMASK); - // And convert it back. + // Read inputs readval = ~ port_in (lptPort + 1) ^ INMASK; + + // Set output back to idle state for backlight + port_out (lptPort + 2, backlight_bit ^ INMASK ); + + // And convert value back. return ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) ) & ~stuckinputs; } diff --git a/server/drivers/hd44780.c b/server/drivers/hd44780.c index ae549e6..e6fba59 100644 --- a/server/drivers/hd44780.c +++ b/server/drivers/hd44780.c @@ -25,12 +25,14 @@ * Character mapping for correct display of some special ASCII chars added * Sep 2001, Mark Haemmerling . * + * Modified October 2001 to read the configfile. + * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * Copyright (c) 2000, 1999, 1995 Benjamin Tse * 2001 Joris Robijn - * 2001 Mark Haemmerling + * 2001 Mark Haemmerling * 2000 Charles Steinkuehler * 1999 Andrew McMeikan * 1998 Richard Rognlie @@ -48,8 +50,6 @@ #endif #include "port.h" -#define atest(i) - // Uncomment one of the lines below to select your desired delay generation // mechanism. If both defines are commented, the original I/O read timing // loop is used. Using DELAY_NANOSLEEP seems to provide the best performance. @@ -76,7 +76,7 @@ #endif #include "shared/str.h" - +#include "render.h" #include "lcd.h" #include "hd44780.h" // #include "drv_base.h" @@ -97,7 +97,7 @@ HD44780_functions *hd44780_functions; // default value static enum connectionType connection = HD_4bit; -static int connIdx = 0; +static int connectiontype_index = 0; // spanList[line number] = display line number is in static int *spanList = NULL; @@ -112,15 +112,13 @@ static int numDisplays = 0; // input span list but is kept to save some cpu cycles. static int *dispSizes = NULL; -// Keypad option +// Keypad and backlight option char have_keypad = 0; // off by default - // This var is not static, so it's accessable from all sub-drivers +char have_backlight = 0; // off by default +char extIF = 0; // off by default + // These vars is not static, so it's accessable from all sub-drivers // Indeed, this should become cleaner... later... -// Maximum sizes of the keypad -// DO NOT CHANGE THESE 2 VALUES, unless you change the functions too -#define KEYPAD_MAXX 5 -#define KEYPAD_MAXY 11 // Autorepeat values #define KEYPAD_AUTOREPEAT_DELAY 500 #define KEYPAD_AUTOREPEAT_FREQ 15 @@ -132,25 +130,28 @@ static char keyMapDirect[KEYPAD_MAXX] = { 'A', 'B', 'C', 'D', 'E' }; // keyMapMatrix contrains an array with arrays of the ascii-codes that should be generated // when a key in the matrix is pressed. static char keyMapMatrix[KEYPAD_MAXY][KEYPAD_MAXX] = { - { '1', '2', '3', 'A', 0 }, - { '4', '5', '6', 'B', 0 }, - { '7', '8', '9', 'C', 0 }, - { '*', '0', '#', 'D', 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, 0 }, - { 0, 0, 0, 0, 0 }}; + { '1', '2', '3', 'A', 'E' }, + { '4', '5', '6', 'B', 'F' }, + { '7', '8', '9', 'C', 'G' }, + { '*', '0', '#', 'D', 'H' }, + { 'I', 'J', 'K', 'L', 'M' }, + { 'N', 'O', 'P', 'Q', 'R' }, + { 'S', 'T', 'U', 'V', 'W' }, + { 'X', 'Y', 'Z', 'a', 'b' }, + { 'c', 'd', 'e', 'f', 'g' }, + { 'h', 'i', 'j', 'k', 'l' }, + { 'm', 'n', 'o', 'p', 'q' }}; static char pressed_key = 0; static int pressed_key_repetitions = 0; static struct timeval pressed_key_time; - // function declarations +void HD44780_close (); void HD44780_flush (); +void HD44780_clear (); +void HD44780_chr (int x, int y, char ch); +void HD44780_string (int x, int y, char *s); void HD44780_flush_box (int lft, int top, int rgt, int bot); void HD44780_backlight (int on); void HD44780_init_vbar (); @@ -159,22 +160,15 @@ void HD44780_vbar (int x, int len); void HD44780_hbar (int x, int y, int len); void HD44780_init_num (); void HD44780_num (int x, int num); +void HD44780_heartbeat (int type); void HD44780_set_char (int n, char *dat); void HD44780_icon (int which, char dest); void HD44780_draw_frame (char *dat); -void HD44780_close (); +char HD44780_getkey (); -static void HD44780_linewrap (int on); -static void HD44780_autoscroll (int on); -static void HD44780_position (int x, int y); -static void HD44780_chr (int x, int y, char ch); - -static void common_position (int display, int DDaddr); -static void common_autoscroll (int on); +void HD44780_position (int x, int y); static void uPause (int delayCalls); -static void HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch); -static char HD44780_getkey (); - +unsigned char HD44780_scankeypad(); static int parse_span_list (int *spanListArray[], int *spLsize, int *dispOffsets[], int *dOffsize, int *dispSizeArray[], char *spanlist); ///////////////////////////////////////////////////////////////// @@ -185,96 +179,52 @@ HD44780_init (lcd_logical_driver * driver, char *args) { // TODO: remove the two magic numbers below // TODO: single point of return - char *argv[64], *str; - int argc, i; + //char *argv[64]; + //int i; + char buf[40]; + char *s; HD44780 = driver; - // get_args inserts \0 into args - nasty ! - if (args) - if ((str = (char *) malloc (strlen (args) + 1))) - strcpy (str, args); - else { - fprintf (stderr, "Error mallocing\n"); - return -1; + // TODO: replace DriverName with driver->name when that field exists. + #define DriverName "HD44780" + + + //// READ THE CONFIG FILE + + port = driver->config_get_int( DriverName, "port", 0, 0x278 ); + + // Get and search for the connection type + s = driver->config_get_string( DriverName, "connectiontype", 0, "4bit" ); + for (connectiontype_index = 0; strcmp (s, connectionMapping[connectiontype_index].connectionTypeStr) != 0 && connectionMapping[connectiontype_index].type != HD_unknown; ++connectiontype_index); + + if (connectionMapping[connectiontype_index].type == HD_unknown) { + fprintf (stderr, "HD44780_init: Unknown connection type: %s\n", s); + return -1; // fatal error } else - str = NULL; + connection = connectionMapping[connectiontype_index].type; - argc = get_args (argv, args, 64); - - // arguments are passed in with -d HD44780 "-p 0x278" - // getopt will work well here - for (i = 0; i < argc; i++) { - if (0 == strcmp (argv[i], "-p") || 0 == strcmp (argv[i], "--port")) { - if (i + 1 >= argc) { - fprintf (stderr, "HD44780_init: %s requires an argument\n", argv[i]); - return -1; - } else { - int myport; - if (sscanf (argv[i + 1], "%i", &myport) != 1) { - fprintf (stderr, "HD44780_init: Couldn't read port address -" " using default value 0x%x\n", port); - return -1; - } else { - port = myport; - ++i; - } - } - } else if (0 == strcmp (argv[i], "-c") || 0 == strcmp (argv[i], "--connect")) { - int j = 0; - if (i + 1 >= argc) { - fprintf (stderr, "HD44780_init: %s requires an argument\n", argv[i]); - return -1; - } - // search the next argument for the connection type - for (j = 0; strcmp (argv[i + 1], connectionMapping[j].connectionTypeStr) != 0 && connectionMapping[j].type != HD_unknown; ++j); - - if (connectionMapping[j].type == HD_unknown) { - fprintf (stderr, "HD44780_init: Unknown connection type - using default %s driver\n", connectionMapping[0].connectionTypeStr); - connection = connectionMapping[0].type; - j = 0; - } else - connection = connectionMapping[j].type; - - connIdx = j; - ++i; - } else if (0 == strcmp (argv[i], "-v") || 0 == strcmp (argv[i], "--vspan")) { - if (i + 1 >= argc) { - fprintf (stderr, "HD44780_init: %s requires an argument\n", argv[i]); - return -1; - } - if (parse_span_list (&spanList, &numLines, &dispVOffset, &numDisplays, &dispSizes, argv[i + 1]) == -1) { - fprintf (stderr, "HD44780_init: invalid vspan argument\n"); - return -1; - } - ++i; - } else if (strcmp (argv[i], "-k") == 0 || strcmp (argv[i], "--keypad") == 0) { - have_keypad = 1; - printf( "HD44780 keypad extension enabled\n" ); - - } else if (0 == strcmp (argv[i], "-h") || 0 == strcmp (argv[i], "--help")) { - int i; - printf ("LCDproc HD44780 driver\n" "\t-p n\t--port n\tSelect the output device to use port n\n" "\t-c type\t--connect type\tSet the connection type (default 4 bit)\n" "\t\t\t\ttype = %s", connectionMapping[0].connectionTypeStr); - for (i = 1; connectionMapping[i].type != HD_unknown; ++i) - printf (" | %s", connectionMapping[i].connectionTypeStr); - printf ("\n\t-v spanlist\t--vspan spanlist\tvertical span n{,m}\n" "\t-h\t--help\t\tShow this help information\n" "\n\tNote that the '-t' option should precede the '-d' option\n"); - - if (connectionMapping[connIdx].type != HD_unknown) { - printf ("\n Parameters for %s driver\n", connectionMapping[connIdx].connectionTypeStr); - printf ("%s", connectionMapping[connIdx].helpMsg); - } + // Get and parse vspan only when specified + s = driver->config_get_string( DriverName, "vspan", 0, "" ); + if( s[0] != 0 ) { + if (parse_span_list (&spanList, &numLines, &dispVOffset, &numDisplays, &dispSizes, s) == -1) { + fprintf (stderr, "HD44780_init: invalid vspan value: %s\n", s ); return -1; } - /* ignore invalid arguments as they might be valid to the lower-level init - else - { - printf("Invalid parameter: %s\n", argv[i]); - } - */ + } + + extIF = driver->config_get_bool( DriverName, "extended", 0, 0 ); + have_keypad = driver->config_get_bool( DriverName, "keypad", 0, 0 ); + have_backlight = driver->config_get_bool( DriverName, "backlight", 0, 0 ); + + // Get and parse size + s = driver->config_get_string( DriverName, "size", 0, "20x4" ); + if( sscanf( s, "%dx%d", &(driver->wid), &(driver->hgt) ) != 2 ) { + fprintf( stderr, "HD44780_init: Cannot read size: %s\n", s ); } // default case for when spans aren't indicated // - add a sanity check against HD44780->hgt ?? - // - this only works if the -t option is specified before -d if (numLines == 0) { if ((spanList = (int *) malloc (sizeof (int) * HD44780->hgt))) { int i; @@ -293,6 +243,8 @@ HD44780_init (lcd_logical_driver * driver, char *args) } else fprintf (stderr, "Error mallocing for display sizes list\n"); } + + #if defined DELAY_NANOSLEEP // Change to Round-Robin scheduling for nanosleep { @@ -306,8 +258,6 @@ HD44780_init (lcd_logical_driver * driver, char *args) } #endif - atest( port ); - // Make sure the frame buffer is there... if (!HD44780->framebuf) HD44780->framebuf = (unsigned char *) malloc (HD44780->wid * HD44780->hgt); @@ -318,27 +268,31 @@ HD44780_init (lcd_logical_driver * driver, char *args) } // Set the functions the driver supports... // These are the default HD44780 functions - driver->clear = (void *) -1; - driver->string = (void *) -1; - driver->chr = HD44780_chr; - driver->vbar = HD44780_vbar; - driver->init_vbar = HD44780_init_vbar; - driver->hbar = HD44780_hbar; - driver->init_hbar = HD44780_init_hbar; - driver->num = HD44780_num; - driver->init_num = HD44780_init_num; - driver->init = HD44780_init; - driver->close = (void *) -1; + driver->close = HD44780_close; driver->flush = HD44780_flush; - driver->flush_box = HD44780_flush_box; - //driver->contrast = HD44780_contrast; // contrast by potmeter - driver->backlight = HD44780_backlight; + driver->clear = HD44780_clear; + driver->chr = HD44780_chr; + driver->string = HD44780_string; + driver->flush_box = HD44780_flush_box; // TO BE REMOVED + //driver->contrast = HD44780_contrast; // contrast is set by potmeter we assume + + //driver->output = HD44780_output; // not implemented + driver->init_vbar = HD44780_init_vbar; + driver->init_hbar = HD44780_init_hbar; + driver->vbar = HD44780_vbar; + driver->hbar = HD44780_hbar; + driver->init_num = HD44780_init_num; + driver->num = HD44780_num; + driver->heartbeat = HD44780_heartbeat; driver->set_char = HD44780_set_char; driver->icon = HD44780_icon; - driver->draw_frame = HD44780_draw_frame; + driver->draw_frame = HD44780_draw_frame; // TO BE REMOVED - if( have_keypad ) { + if ( have_backlight ) { + driver->backlight = HD44780_backlight; + } + if ( have_keypad ) { driver->getkey = HD44780_getkey; } @@ -346,21 +300,27 @@ HD44780_init (lcd_logical_driver * driver, char *args) return -1; } hd44780_functions->uPause = uPause; - hd44780_functions->position = common_position; - hd44780_functions->autoscroll = common_autoscroll; + hd44780_functions->scankeypad = HD44780_scankeypad; - connectionMapping[connIdx].init_fn (hd44780_functions, driver, str, port); + connectionMapping[connectiontype_index].init_fn (hd44780_functions, driver, args, port); - HD44780_autoscroll (0); + HD44780_clear (); + sprintf (buf, "HD44780 %dx%d", HD44780->wid, HD44780->hgt ); + HD44780_string (1, 1, buf); + sprintf (buf, "LPT 0x%x %s %s", port, (have_backlight?"bl":""), (have_keypad?"key":"") ); + HD44780_string (1, 2, buf); + HD44780_flush (); + sleep (1); return port; } +///////////////////////////////////////////////////////////////// // Common initialisation sequence - sets cursor off and not blinking, // clear display and homecursor // Does not set twoline mode nor small characters (5x8). The init function of // the connectiontype should do this. - +// void common_init () { @@ -372,7 +332,9 @@ common_init () hd44780_functions->uPause (1600); } +///////////////////////////////////////////////////////////////// // IO delay to avoid a task switch +// void uPause (int delayCalls) { @@ -408,26 +370,18 @@ uPause (int delayCalls) #endif } -// displayID - ID of display to use (0 = all displays) -static void -HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch) -{ - hd44780_functions->senddata (displayID, flags, ch); - hd44780_functions->uPause (40); // Minimum exec time for all commands -} - ///////////////////////////////////////////////////////////////// // Clean-up // -/* - void HD44780_close() - { - drv_base_close(); - } -*/ +void HD44780_close() +{ +} +///////////////////////////////////////////////////////////////// +// Set position (not part of API) +// // x and y here are for the virtual HD44780->hgt x HD44780->wid display -static void +void HD44780_position (int x, int y) { int dispID = spanList[y]; @@ -435,37 +389,74 @@ HD44780_position (int x, int y) int DDaddr; // 16x1 is a special case - if (dispSizes[dispID - 1] == 1 && HD44780->wid == 16) + if (dispSizes[dispID - 1] == 1 && HD44780->wid == 16) { if (x >= 8) { x -= 8; relY = 1; } + } DDaddr = x + (relY % 2) * 0x40; if ((relY % 4) >= 2) DDaddr += HD44780->wid; - hd44780_functions->position (dispID, DDaddr); -} - -void -common_position (int display, int DDaddr) -{ - hd44780_functions->senddata (display, RS_INSTR, POSITION | DDaddr); + hd44780_functions->senddata (dispID, RS_INSTR, POSITION | DDaddr); hd44780_functions->uPause (40); // Minimum exec time for all commands } -void HD44780_chr (int x, int y, char ch) -{ - HD44780->framebuf[ (y * HD44780->wid) + x] = ch; -} - +///////////////////////////////////////////////////////////////// +// Flush the framebuffer to the display +// void HD44780_flush () { HD44780_draw_frame (HD44780->framebuf); } +///////////////////////////////////////////////////////////////// +// Clear the framebuffer +// +void HD44780_clear () +{ + memset(HD44780->framebuf, ' ', HD44780->wid * HD44780->hgt); +} + +///////////////////////////////////////////////////////////////// +// Place a character in the framebuffer +// +void +HD44780_chr (int x, int y, char ch) +{ + y--; + x--; + + HD44780->framebuf[ (y * HD44780->wid) + x] = ch; +} + +///////////////////////////////////////////////////////////////// +// Place a string in the framebuffer +// +void +HD44780_string (int x, int y, char *s) +{ + int i; + + x --; // Convert 1-based coords to 0-based + y --; + + for (i = 0; s[i]; i++) { + // Check for buffer overflows... + if ((y * HD44780->wid) + x + i > (HD44780->wid * HD44780->hgt)) + break; + HD44780->framebuf[(y*HD44780->wid) + x + i] = s[i]; + } +} + +///////////////////////////////////////////////////////////////// +// Flush box +// +// TO BE REMOVED +// void HD44780_flush_box (int lft, int top, int rgt, int bot) { @@ -477,7 +468,9 @@ HD44780_flush_box (int lft, int top, int rgt, int bot) HD44780_position (lft, y); //printf("\n%d,%d :",lft,y); for (x = lft; x <= rgt; x++) { - HD44780_senddata (spanList[y], RS_DATA, HD44780->framebuf[(y * HD44780->wid) + x]); + + hd44780_functions->senddata (spanList[y], RS_DATA, HD44780->framebuf[(y * HD44780->wid) + x]); + hd44780_functions->uPause (40); // Minimum exec time for all commands } //write(fd, HD44780->framebuf[(y*HD44780->wid)+lft, rgt-lft+1]); } @@ -490,31 +483,7 @@ HD44780_flush_box (int lft, int top, int rgt, int bot) void HD44780_backlight (int on) { - //hd44780_functions->backlight (on); -} - -///////////////////////////////////////////////////////////////// -// Toggle the built-in linewrapping feature -// -static void -HD44780_linewrap (int on) -{ -} - -///////////////////////////////////////////////////////////////// -// Toggle the built-in automatic scrolling feature -// -static void -HD44780_autoscroll (int on) -{ - hd44780_functions->autoscroll (on); -} - -void -common_autoscroll (int on) -{ - hd44780_functions->senddata (0, RS_INSTR, ENTRYMODE | E_MOVERIGHT | ((on) ? EDGESCROLL : NOSCROLL)); - hd44780_functions->uPause (40); + hd44780_functions->backlight (on); } ///////////////////////////////////////////////////////////////// @@ -703,7 +672,7 @@ HD44780_hbar (int x, int y, int len) void HD44780_init_num () { - + } ///////////////////////////////////////////////////////////////// @@ -716,6 +685,38 @@ HD44780_num (int x, int num) HD44780->framebuf[x+offset] = num + '0'; } +///////////////////////////////////////////////////////////// +// Does the heartbeat... +// +void +HD44780_heartbeat (int type) +{ + static int timer = 0; + int whichIcon; + static int saved_type = HEARTBEAT_ON; + + if (type) + saved_type = type; + + if (type == HEARTBEAT_ON) { + // Set this to pulsate like a real heart beat... + whichIcon = (! ((timer + 4) & 5)); + + // This defines a custom character EVERY time... + // not efficient... is this necessary? + HD44780_icon (whichIcon, 0); + + // Put character on screen... + HD44780_chr (HD44780->wid, 1, 0); + + // change display... + HD44780_flush (); + } + + timer++; + timer &= 0x0f; +} + ///////////////////////////////////////////////////////////////// // Sets a custom character from 0-7... // @@ -734,7 +735,8 @@ HD44780_set_char (int n, char *dat) if (!dat) return; - HD44780_senddata (0, RS_INSTR, SETCHAR | n * 8); + hd44780_functions->senddata (0, RS_INSTR, SETCHAR | n * 8); + hd44780_functions->uPause (40); // Minimum exec time for all commands for (row = 0; row < HD44780->cellhgt; row++) { letter = 0; @@ -742,10 +744,14 @@ HD44780_set_char (int n, char *dat) letter <<= 1; letter |= (dat[(row * HD44780->cellwid) + col] > 0); } - HD44780_senddata (0, RS_DATA, letter); + hd44780_functions->senddata (0, RS_DATA, letter); + hd44780_functions->uPause (40); // Minimum exec time for all commands } } +///////////////////////////////////////////////////////////// +// Set default icon into a userdef char +// void HD44780_icon (int which, char dest) { @@ -793,6 +799,7 @@ HD44780_icon (int which, char dest) // // Input is a character array, sized HD44780->wid*hgt // +// TO BE REMOVED (move it into flush()) void HD44780_draw_frame (char *dat) { @@ -802,15 +809,136 @@ HD44780_draw_frame (char *dat) return; for (y = 0; y < HD44780->hgt; y++) { - HD44780_position (0, y); //printf("\n%d :",y); for (x = 0; x < HD44780->wid; x++) { - HD44780_senddata (spanList[y], RS_DATA, HD44780_charmap[(unsigned char)dat[(y * HD44780->wid) + x]]); + + if( x % 8 == 0 ) + HD44780_position (x, y); + hd44780_functions->senddata (spanList[y], RS_DATA, HD44780_charmap[(unsigned char)dat[(y * HD44780->wid) + x]]); + hd44780_functions->uPause (40); // Minimum exec time for all commands } } } +///////////////////////////////////////////////////////////// +// Get a key from the keypad (if there is one) +// +char HD44780_getkey() +{ + unsigned char scancode; + char ch; + struct timeval curr_time, time_diff; + + gettimeofday(&curr_time,NULL); + + scancode = hd44780_functions->scankeypad(); + if( scancode ) { + if( scancode & 0xF0 ) { + ch = keyMapMatrix[((scancode&0xF0)>>4)-1][(scancode&0x0F)-1]; + } + else { + ch = keyMapDirect[scancode - 1]; + } + } + else { + ch = 0; + } + + if (ch) { + if (ch == pressed_key) { + timersub (&curr_time, &pressed_key_time, &time_diff); + if (((time_diff.tv_usec / 1000 + time_diff.tv_sec * 1000) - KEYPAD_AUTOREPEAT_DELAY) < 1000 * pressed_key_repetitions / KEYPAD_AUTOREPEAT_FREQ ) { + // The key is already pressed quite some time + // but it's not yet time to return a repeated keypress + return 0; + } + // Otherwise a keypress will be returned + pressed_key_repetitions ++; + } + else { + // It's a new keypress + pressed_key_time = curr_time; + pressed_key_repetitions = 0; + printf( "Key: %c (%d,%d)\n", ch, scancode&0x0F, (scancode&0xF0)>>4 ); + } + } + + // Store the key for the next round + pressed_key = ch; + + return ch; +} + +///////////////////////////////////////////////////////////// +// Scan the keypad +// +unsigned char HD44780_scankeypad() +{ + unsigned int keybits; + unsigned int shiftcount; + unsigned int shiftingbit; + unsigned int Ypattern; + unsigned int Yval; + char exp; + + unsigned char scancode = 0; + + // First check if a directly connected key is pressed + // Put all zeros on Y of keypad + keybits = hd44780_functions->readkeypad (0); + + if (keybits) { + // A directly connected key was pressed + // Which key was it ? + shiftingbit = 1; + for (shiftcount=0; shiftcountreadkeypad (Ypattern)) { + // Yes, a key on the matrix is pressed + + // OK, now we know a key is pressed. + // Determine which one it is + + // First determine the row + // Do a 'binary search' to minimize I/O + Ypattern = 0; + Yval = 0; + for (exp=3; exp>=0; exp--) { + Ypattern = ((1 << (1 << exp)) - 1) << Yval; + keybits = hd44780_functions->readkeypad (Ypattern); + if (!keybits) { + Yval += (1 << exp); + } + } + + // Which key is pressed in that row ? + keybits = hd44780_functions->readkeypad (1<readkeypad (0); - - if (keybits) { - // A directly connected key was pressed - // Which key was it ? - shiftingbit = 1; - for (shiftcount=0; shiftcountreadkeypad (Ypattern)) { - // Yes, a key on the matrix is pressed - - // OK, now we know a key is pressed. - // Determine which one it is - // Do a 'binary search' to determine in what row a key is pressed - Ypattern = 0; - Yval = 0; - for (exp=3; exp>=0; exp--) { - Ypattern = ((1 << (1 << exp)) - 1) << Yval; - keybits = hd44780_functions->readkeypad (Ypattern); - if (!keybits) { - Yval += (1 << exp); - } - } - - // Which key is pressed in that row ? - keybits = hd44780_functions->readkeypad (1< 2 LCDs int HD44780_init (struct lcd_logical_driver *driver, char *args); /* The following methods can all be hidden. They are used through function ptrs