HD44780 keypad update. (second try)

This commit is contained in:
robijn
2001-10-05 21:01:24 +00:00
parent 4829ed367f
commit 16cce2fe2d
4 changed files with 355 additions and 141 deletions
+12 -5
View File
@@ -6,7 +6,8 @@
enum ifWidth { IF_4bit, IF_8bit }; enum ifWidth { IF_4bit, IF_8bit };
void common_init (enum ifWidth ifwidth); //void common_init (enum ifWidth ifwidth);
void common_init ();
// Structures holding pointers to HD44780 specific functions // Structures holding pointers to HD44780 specific functions
typedef struct hwDependentFns { typedef struct hwDependentFns {
@@ -16,7 +17,7 @@ typedef struct hwDependentFns {
// senddata to the LCD // senddata to the LCD
// dispID - display to send data to (0 = all displays) // dispID - display to send data to (0 = all displays)
// flags - data or instruction command (RS_DATA | RS_INSTR) // flags - data or instruction command (RS_DATA | RS_INSTR)
// ch - character to display or instruction value // ch - character to display or instruction value
void (*senddata) (unsigned char dispID, unsigned char flags, unsigned char ch); void (*senddata) (unsigned char dispID, unsigned char flags, unsigned char ch);
// position the cursor // position the cursor
@@ -25,8 +26,14 @@ typedef struct hwDependentFns {
void (*position) (int dispID, int DDaddr); void (*position) (int dispID, int DDaddr);
// toggle vertical autoscroll on all displays // toggle vertical autoscroll on all displays
// on - non-zero turns autoscroll on, zero value turns it off // on - non-zero turns autoscroll on, zero value turns it off
void (*autoscroll) (int on); void (*autoscroll) (int on);
// 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);
} HD44780_functions; /* for want of a better name :-) */ } HD44780_functions; /* for want of a better name :-) */
extern HD44780_functions *hd44780_functions; extern HD44780_functions *hd44780_functions;
@@ -81,7 +88,7 @@ extern HD44780_functions *hd44780_functions;
#define nSEL 0x08 #define nSEL 0x08
#define SEL 0x08 #define SEL 0x08
#define OUTMASK 0x0B #define OUTMASK 0x0B /* SEL, LF and STRB are hardware inverted */
// Input lines // Input lines
#define nFAULT 0x08 #define nFAULT 0x08
@@ -92,6 +99,6 @@ extern HD44780_functions *hd44780_functions;
#define ACK 0x40 #define ACK 0x40
#define BUSY 0x80 #define BUSY 0x80
#define INMASK 0x48 #define INMASK 0x84 /* BUSY input and the IRQ indicator are inverted */
#endif #endif
+100 -47
View File
@@ -4,82 +4,118 @@
* 4094 shift register and supports a keypad. * 4094 shift register and supports a keypad.
* *
* Copyright (c) 1999 Andrew McMeikan <andrewm@engineer.com> * Copyright (c) 1999 Andrew McMeikan <andrewm@engineer.com>
* modular driver 1999 Benjamin Tse <blt@Comports.com> * modular driver 1999 Benjamin Tse <blt@Comports.com>
*
* 2001 Joris Robijn <joris@robijn.net>
* - Keypad support
* - Changed for 2 line wire control
* *
* Full connection details at http://members.xoom.com/andrewmuck/LCD.htm * Full connection details at http://members.xoom.com/andrewmuck/LCD.htm
* *
* printer port 4094/LCD * printer port 4094/LCD
* D2 (4) EN (6 - LCD) * D2 (4) EN (6 - LCD)
* D3 (5) D (2 - 4094) * D3 (5) D (2 - 4094)
* D4 (6) CLK (3 - 4094) * D4 (6) CLK (3 - 4094)
* +Vcc OE, STR (15, 1 - 4094) * +Vcc OE, STR (15, 1 - 4094)
* D7 (9) EN2 (6 - LCD2) (optional) * D7 (9) EN2 (6 - LCD2) (optional)
* *
* 4094 LCD * 4094 LCD
* Q1 (4) D4 (11) * Q1 (4) D4 (11)
* Q2 (5) D5 (12) * Q2 (5) D5 (12)
* Q3 (6) D6 (13) * Q3 (6) D6 (13)
* Q4 (7) D7 (14) * Q4 (7) D7 (14)
* Q6 (13) RS (4) * Q6 (13) RS (4)
* Gnd nRW (5) * Gnd nRW (5)
*
* Keypad connection (optional):
* This is connected on the 4094 parallel to the LCD.
* Some diodes and resistors are needed, see further documentation.
* Q1 (4) Y0
* Q2 (5) Y1
* Q3 (6) Y2
* Q4 (7) Y3
* Q5 (14) Y4
* Q6 (13) Y5
* The 'output' of the keys should be connected to the following LPT pins:
* nACK (10) X0
* BUSY (11) X1
* PAPEREND (12) X2
* SELIN (13) X3
* nFAULT (15) X4
* If you want to use as few LPT lines as possible, only use X0.
* *
* This file is released under the GNU General Public License. Refer to the * This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package. * COPYING file distributed with this package.
*/ */
#include "hd44780-serialLpt.h"
#include "hd44780.h"
#include "port.h"
#include "shared/str.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include "hd44780-serialLpt.h"
#include "port.h"
// Hardware specific functions // Hardware specific functions
void lcdserLpt_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch); void lcdserLpt_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch);
unsigned char lcdserLpt_HD44780_readkeypad (unsigned int YData);
static char lcdserLpt_HD44780_getkey (void); static char lcdserLpt_HD44780_getkey (void); // old keypad code
void rawshift (unsigned char r); void rawshift (unsigned char r);
void shiftreg (unsigned char displayID, unsigned char r); void shiftreg (unsigned char displayID, unsigned char r);
#define RS 16 #define RS 32
#define LCDDATA 8 #define LCDDATA 8
#define LCDCLOCK 16 #define LCDCLOCK 16
#define EN1 4 #define EN1 4
#define EN2 32 #define EN2 32
static unsigned int lp; static unsigned int lptPort;
static char lastkey = 0; static char keypad;
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 // Initialisation
int int
hd_init_serialLpt (HD44780_functions * hd44780_functions, lcd_logical_driver * driver, char *args, unsigned int port) hd_init_serialLpt (HD44780_functions * hd44780_functions, lcd_logical_driver * driver, char *args, unsigned int port)
{ {
int displayID = EN1 | EN2; unsigned char enableLines = EN1 | EN2;
lp = port; // Reserve the port registers
if (port_access (lp) || port_access (lp +1)) { lptPort = port;
fprintf (stderr, "HD44780_init: failed (%s)\n", strerror (errno)); port_access(lptPort);
return( -1 ); port_access(lptPort+1);
}; port_access(lptPort+2);
hd44780_functions->senddata = lcdserLpt_HD44780_senddata; hd44780_functions->senddata = lcdserLpt_HD44780_senddata;
hd44780_functions->readkeypad = lcdserLpt_HD44780_readkeypad;
// TODO: enable keypad only if specified on command line if (keypad) {
driver->getkey = lcdserLpt_HD44780_getkey; driver->getkey = lcdserLpt_HD44780_getkey;
}
// Clear the shiftregister
rawshift (0);
// setup the lcd in 4 bit mode // setup the lcd in 4 bit mode
shiftreg (displayID, 3); shiftreg (enableLines, 3);
hd44780_functions->uPause (4100); hd44780_functions->uPause (4100);
shiftreg (displayID, 3); shiftreg (enableLines, 3);
hd44780_functions->uPause (100); hd44780_functions->uPause (100);
shiftreg (displayID, 3); shiftreg (enableLines, 3);
hd44780_functions->uPause (40); hd44780_functions->uPause (40);
shiftreg (displayID, 2); shiftreg (enableLines, 2);
hd44780_functions->uPause (40); hd44780_functions->uPause (40);
hd44780_functions->senddata (0, RS_INSTR, FUNCSET | IF_4BIT | TWOLINE | SMALLCHAR);
common_init ();
/*
// set display type functions // set display type functions
lcdserLpt_HD44780_senddata (0, RS_INSTR, FUNCSET | IF_4BIT | TWOLINE | SMALLCHAR); lcdserLpt_HD44780_senddata (0, RS_INSTR, FUNCSET | IF_4BIT | TWOLINE | SMALLCHAR);
// clear // clear
@@ -88,6 +124,7 @@ hd_init_serialLpt (HD44780_functions * hd44780_functions, lcd_logical_driver * d
// Now turn on the display // Now turn on the display
lcdserLpt_HD44780_senddata (displayID, RS_INSTR, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK); lcdserLpt_HD44780_senddata (displayID, RS_INSTR, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK);
hd44780_functions->uPause (1600); hd44780_functions->uPause (1600);
*/
return 0; return 0;
} }
@@ -95,22 +132,24 @@ hd_init_serialLpt (HD44780_functions * hd44780_functions, lcd_logical_driver * d
void void
lcdserLpt_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch) lcdserLpt_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch)
{ {
unsigned char dispID = 0, portControl = 0, h = ch >> 4, l = ch & 15; unsigned char enableLines;
unsigned char portControl = 0;
unsigned char h = ch >> 4, l = ch & 15;
if (displayID == 1) if (displayID == 1)
dispID |= EN1; enableLines = EN1;
else if (displayID == 2) else if (displayID == 2)
dispID |= EN2; enableLines = EN2;
else else
dispID |= EN1 | EN2; enableLines = EN1 | EN2;
if (flags == RS_DATA) if (flags == RS_DATA)
portControl = RS; portControl = RS;
else else
portControl = 0; portControl = 0;
shiftreg (displayID, flags | portControl | h); shiftreg (enableLines, portControl | h);
shiftreg (displayID, flags | portControl | l); shiftreg (enableLines, portControl | l);
/* TODO: instead of delay read keys here */ /* TODO: instead of delay read keys here */
} }
@@ -123,45 +162,59 @@ lcdserLpt_HD44780_getkey ()
char keytr[] = "ABCDEFGH"; char keytr[] = "ABCDEFGH";
int n; int n;
rawshift (0); //send all line on shift register low // disabled now !
return 0;
rawshift (0); //send all line on shift register low
hd44780_functions->uPause (1); hd44780_functions->uPause (1);
if ((port_in (lp + 1) & 32) == 0) //test if line back is low - if not return(0) if ((port_in (lptPort + 1) & 32) == 0) //test if line back is low - if not return(0)
{ //else { //else
//start walking a single zero across the eight lines //start walking a single zero across the eight lines
for (n = 7; n >= 0; n--) { for (n = 7; n >= 0; n--) {
rawshift (255 - (1 << n)); rawshift (255 - (1 << n));
hd44780_functions->uPause (1); hd44780_functions->uPause (1);
if ((port_in (lp + 1) & 32) == 0) // check if line back is low if yes debounce if ((port_in (lptPort + 1) & 32) == 0) // check if line back is low if yes debounce
{ {
if (lastkey == keytr[n]) if (lastkey == keytr[n])
return (0); return (0);
// printf("key is %c %d\n",keytr[n],n); // printf("key is %c %d\n",keytr[n],n);
lastkey = keytr[n]; lastkey = keytr[n];
return (keytr[n]); //return correct key code. return (keytr[n]); //return correct key code.
} }
} }
} //else fall out and return(0) [too transient a keypress] } //else fall out and return(0) [too transient a keypress]
lastkey = 0; lastkey = 0;
return (0); return (0);
} }
unsigned char lcdserLpt_HD44780_readkeypad (unsigned int YData)
{
return 0;
}
/* this function sends r out onto the shift register */ /* this function sends r out onto the shift register */
void void
rawshift (unsigned char r) rawshift (unsigned char r)
{ {
int i; int i;
for (i = 7; i >= 0; i--) { /* MSB first */ for (i = 7; i >= 0; i--) { /* MSB first */
port_out (lp, ((r >> i) & 1) * LCDDATA); /*set up data */ port_out (lptPort, ((r >> i) & 1) * LCDDATA); /*set up data */
port_out (lp, (((r >> i) & 1) * LCDDATA) | LCDCLOCK); /*rising edge of clock */ port_out (lptPort, (((r >> i) & 1) * LCDDATA) | LCDCLOCK); /*rising edge of clock */
} }
} }
// displayID = value on parallel port to toggle the correct display // enableLines = value on parallel port to toggle the correct display
void void
shiftreg (unsigned char displayID, unsigned char r) shiftreg (unsigned char enableLines, unsigned char r)
{ {
rawshift (r); //unsigned char mr;
port_out (lp, displayID); //latch it, to correct display //mr = (r & 0xF0) | ((r<<3) & 0x0F) | ((r<<1) & 0x04) |
port_out (lp, 0); // ((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
hd44780_functions->uPause (1);
port_out (lptPort, 0);
hd44780_functions->uPause (3);
} }
+71 -19
View File
@@ -11,9 +11,12 @@
* - provided required setup time for RS valid to E high * - provided required setup time for RS valid to E high
* - 1 uS call to uPause removed as it is unnecessary * - 1 uS call to uPause removed as it is unnecessary
* *
* 2001 Joris Robijn <joris@robijn.net>
* - Keypad support
*
* The connections are: * The connections are:
* printer port LCD * printer port LCD
* D0 (2) D0 (7) * D0 (2) D0 (7)
* D1 (3) D1 (8) * D1 (3) D1 (8)
* D2 (4) D2 (9) * D2 (4) D2 (9)
* D3 (5) D3 (10) * D3 (5) D3 (10)
@@ -26,6 +29,26 @@
* INIT (16) RS (4) * INIT (16) RS (4)
* nSEL (17) EN2 (6 - LCD 2) (optional) * nSEL (17) EN2 (6 - LCD 2) (optional)
* *
* Keypad connection (optional):
* Some diodes and resistors are needed, see further documentation.
* printer port keypad
* D0 (2) Y0
* D1 (3) Y1
* D2 (4) Y2
* D3 (5) Y3
* D4 (6) Y4
* D5 (7) Y5
* D6 (7) Y6
* D7 (7) Y7
* nLF (14) Y8
* INIT (16) Y9
* nSEL (17) Y10
* nACK (10) X0
* BUSY (11) X1
* PAPEREND (12) X2
* SELIN (13) X3
* nFAULT (15) X4
*
* Created modular driver Dec 1999, Benjamin Tse <blt@Comports.com> * Created modular driver Dec 1999, Benjamin Tse <blt@Comports.com>
* *
* This file is released under the GNU General Public License. Refer to the * This file is released under the GNU General Public License. Refer to the
@@ -33,25 +56,30 @@
*/ */
#include "hd44780-winamp.h" #include "hd44780-winamp.h"
#include "port.h" #include "hd44780.h"
#include "port.h"
#include "shared/str.h" #include "shared/str.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
void lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch); #include "port.h"
#define EN1 STRB void lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch);
#define EN2 SEL unsigned char lcdwinamp_HD44780_readkeypad (unsigned int YData);
#define EN3 LF
#define RS INIT #define EN1 STRB
#define EN2 SEL
#define EN3 LF
#define RS INIT
static unsigned char EnMask[] = { EN1, EN2, EN3 }; static unsigned char EnMask[] = { EN1, EN2, EN3 };
static int EnMaskSize = sizeof (EnMask) / sizeof (unsigned char); static int EnMaskSize = sizeof (EnMask) / sizeof (unsigned char);
static int extIF = 0; // non-zero if extended interface
static unsigned int lptPort; static unsigned int lptPort;
static int extIF = 0; // non-zero if extended interface static char stuckinputs = 0; // if an input line is stuck, it will be ignored
// initialise the driver // initialise the driver
int int
@@ -62,22 +90,32 @@ hd_init_winamp (HD44780_functions * hd44780_functions, lcd_logical_driver * driv
int argc; int argc;
int i; int i;
hd44780_functions->senddata = lcdwinamp_HD44780_senddata; // Reserve the port registers
lptPort = port; lptPort = port;
port_access(lptPort);
port_access(lptPort+1);
port_access(lptPort+2);
hd44780_functions->senddata = lcdwinamp_HD44780_senddata;
hd44780_functions->readkeypad = lcdwinamp_HD44780_readkeypad;
// parse command-line arguments // parse command-line arguments
argc = get_args (argv, args, 64); argc = get_args (argv, args, 64);
for (i = 0; i < argc; ++i) for (i = 0; i < argc; ++i) {
if (strcmp (argv[i], "-e") == 0 || strcmp (argv[i], "--extended") == 0) if (strcmp (argv[i], "-e") == 0 || strcmp (argv[i], "--extended") == 0)
extIF = 1; extIF = 1;
if (port_access (lptPort + 2) || port_access (lptPort)) {
fprintf (stderr, "HD44780_init: failed (%s)\n", strerror (errno));
return -1;
} }
common_init (IF_8bit); // setup the lcd in 8 bit mode
hd44780_functions->senddata (0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (4100);
hd44780_functions->senddata (0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (100);
hd44780_functions->senddata (0, RS_INSTR, FUNCSET | IF_8BIT | TWOLINE | SMALLCHAR);
hd44780_functions->uPause (40);
common_init ();
return 0; return 0;
} }
@@ -100,12 +138,12 @@ lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsign
// 40 nS setup time for RS valid to EN high, so set RS // 40 nS setup time for RS valid to EN high, so set RS
port_out (lptPort + 2, portControl ^ OUTMASK); port_out (lptPort + 2, portControl ^ OUTMASK);
// then set EN high
port_out (lptPort + 2, (dispID | portControl) ^ OUTMASK);
// Output the actual data // Output the actual data
port_out (lptPort, ch); port_out (lptPort, ch);
// then set EN high
port_out (lptPort + 2, (dispID | portControl) ^ OUTMASK);
// 80 nS setup from valid data to EN low will be met without any delay // 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!) // 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... // 230 nS minimum E high time provided by ISA bus delays as well...
@@ -115,3 +153,17 @@ lcdwinamp_HD44780_senddata (unsigned char displayID, unsigned char flags, unsign
// 10 nS data hold time provided by the length of ISA write for EN // 10 nS data hold time provided by the length of ISA write for EN
} }
unsigned char lcdwinamp_HD44780_readkeypad (unsigned int YData)
{
unsigned char readval;
// 10 bits output
// Convert the positive logic to the negative logic on the LPT port
port_out (lptPort, ~YData & 0x00FF );
port_out (lptPort + 2, ( ((~YData & 0x0100) >> 7) | ((~YData & 0x0200) >> 7 )) ^ OUTMASK);
// And convert it back.
readval = ~ port_in (lptPort + 1) ^ INMASK;
return ( (readval >> 4 & 0x03) | (readval >> 5 & 0x04) | (readval >> 3 & 0x08) | (readval << 1 & 0x10) ) & ~stuckinputs;
}
+165 -63
View File
@@ -14,20 +14,23 @@
* 4. Modify the makefile * 4. Modify the makefile
* *
* Modular driver created and generic support for multiple displays added * Modular driver created and generic support for multiple displays added
* Dec 1999, Benjamin Tse <blt@Comports.com>. * Dec 1999, Benjamin Tse <blt@Comports.com>
* *
* Modified July 2000 by Charles Steinkuehler to use one of 3 methods for delay * Modified July 2000 by Charles Steinkuehler to use one of 3 methods for delay
* timing. I/O reads, gettimeofday, and nanosleep. Of the three, nanosleep * timing. I/O reads, gettimeofday, and nanosleep. Of the three, nanosleep
* seems to work best, so that's what is set by default. * seems to work best, so that's what is set by default.
* *
* Modified May 2001 by Joris Robijn to add Keypad support.
*
* Character mapping for correct display of some special ASCII chars added * Character mapping for correct display of some special ASCII chars added
* Sep 2001, Mark Haemmerling <mail@markh.de>. * Sep 2001, Mark Haemmerling <mail@markh.de>.
* *
* This file is released under the GNU General Public License. Refer to the * This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package. * COPYING file distributed with this package.
* *
* Copyright (c) 2001 Mark Haemmerling <mail@markh.de> * Copyright (c) 2000, 1999, 1995 Benjamin Tse <blt@Comports.com>
* 2000, 1999, 1995 Benjamin Tse <blt@Comports.com> * 2001 Joris Robijn <joris@robijn.net>
* 2001 Mark Haemmerling <mail@markh.de>
* 2000 Charles Steinkuehler <cstein@newtek.com> * 2000 Charles Steinkuehler <cstein@newtek.com>
* 1999 Andrew McMeikan <andrewm@engineer.com> * 1999 Andrew McMeikan <andrewm@engineer.com>
* 1998 Richard Rognlie <rrognlie@gamerz.net> * 1998 Richard Rognlie <rrognlie@gamerz.net>
@@ -51,7 +54,6 @@
//#define DELAY_GETTIMEOFDAY //#define DELAY_GETTIMEOFDAY
#define DELAY_NANOSLEEP #define DELAY_NANOSLEEP
#if defined DELAY_GETTIMEOFDAY
# if TIME_WITH_SYS_TIME # if TIME_WITH_SYS_TIME
# include <sys/time.h> # include <sys/time.h>
# include <time.h> # include <time.h>
@@ -64,6 +66,7 @@
# endif # endif
// Only one alternate delay method at a time, please ;-) // Only one alternate delay method at a time, please ;-)
#if defined DELAY_GETTIMEOFDAY
# undef DELAY_NANOSLEEP # undef DELAY_NANOSLEEP
#elif defined DELAY_NANOSLEEP #elif defined DELAY_NANOSLEEP
# include <sched.h> # include <sched.h>
@@ -82,7 +85,7 @@
// default parallel port address // default parallel port address
#ifndef LPTPORT #ifndef LPTPORT
#define LPTPORT 0x378 #define LPTPORT 0x378
#endif #endif
unsigned int port = LPTPORT; unsigned int port = LPTPORT;
@@ -107,10 +110,46 @@ static int numDisplays = 0;
// input span list but is kept to save some cpu cycles. // input span list but is kept to save some cpu cycles.
static int *dispSizes = NULL; static int *dispSizes = NULL;
// Keypad option
char keypad = 0; // off by default
// This var 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
// keyMapDirect contains an array of the ascii-codes that should be generated
// when a directly connected key is pressed (not in matrix).
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 }};
static char pressed_key = 0;
static int pressed_key_repetitions = 0;
static struct timeval pressed_key_time;
// function declarations // function declarations
void HD44780_flush (); void HD44780_flush ();
void HD44780_flush_box (int lft, int top, int rgt, int bot); void HD44780_flush_box (int lft, int top, int rgt, int bot);
int HD44780_contrast (int contrast);
void HD44780_backlight (int on); void HD44780_backlight (int on);
void HD44780_init_vbar (); void HD44780_init_vbar ();
void HD44780_init_hbar (); void HD44780_init_hbar ();
@@ -132,6 +171,7 @@ static void common_position (int display, int DDaddr);
static void common_autoscroll (int on); static void common_autoscroll (int on);
static void uPause (int delayCalls); static void uPause (int delayCalls);
static void HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch); static void HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch);
static char HD44780_getkey ();
static int parse_span_list (int *spanListArray[], int *spLsize, int *dispOffsets[], int *dOffsize, int *dispSizeArray[], char *spanlist); static int parse_span_list (int *spanListArray[], int *spLsize, int *dispOffsets[], int *dOffsize, int *dispSizeArray[], char *spanlist);
@@ -205,6 +245,10 @@ HD44780_init (lcd_logical_driver * driver, char *args)
return -1; return -1;
} }
++i; ++i;
} else if (strcmp (argv[i], "-k") == 0 || strcmp (argv[i], "--keypad") == 0) {
keypad = 1;
printf( "HD44780 keypad extension enabled\n" );
} else if (0 == strcmp (argv[i], "-h") || 0 == strcmp (argv[i], "--help")) { } else if (0 == strcmp (argv[i], "-h") || 0 == strcmp (argv[i], "--help")) {
int i; 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); 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);
@@ -259,11 +303,6 @@ HD44780_init (lcd_logical_driver * driver, char *args)
} }
} }
#endif #endif
// Set up io port correctly, and open it...
if (port_access (port)) {
fprintf (stderr, "HD44780_init: failed (%s)\n", strerror (errno));
return -1;
}
// Make sure the frame buffer is there... // Make sure the frame buffer is there...
if (!HD44780->framebuf) if (!HD44780->framebuf)
HD44780->framebuf = (unsigned char *) malloc (HD44780->wid * HD44780->hgt); HD44780->framebuf = (unsigned char *) malloc (HD44780->wid * HD44780->hgt);
@@ -288,12 +327,15 @@ HD44780_init (lcd_logical_driver * driver, char *args)
driver->close = (void *) -1; driver->close = (void *) -1;
driver->flush = HD44780_flush; driver->flush = HD44780_flush;
driver->flush_box = HD44780_flush_box; driver->flush_box = HD44780_flush_box;
driver->contrast = HD44780_contrast; //driver->contrast = HD44780_contrast; // contrast by potmeter
driver->backlight = HD44780_backlight; driver->backlight = HD44780_backlight;
driver->set_char = HD44780_set_char; driver->set_char = HD44780_set_char;
driver->icon = HD44780_icon; driver->icon = HD44780_icon;
driver->draw_frame = HD44780_draw_frame; driver->draw_frame = HD44780_draw_frame;
driver->getkey = NULL;
if( keypad ) {
driver->getkey = HD44780_getkey;
}
if ((hd44780_functions = (HD44780_functions *) malloc (sizeof (HD44780_functions))) == NULL) { if ((hd44780_functions = (HD44780_functions *) malloc (sizeof (HD44780_functions))) == NULL) {
return -1; return -1;
@@ -309,28 +351,14 @@ HD44780_init (lcd_logical_driver * driver, char *args)
return port; return port;
} }
// common initialisation sequence - sets twoline, small characters (5x8), // Common initialisation sequence - sets cursor off and not blinking,
// cursor off and not blinking, clear display and homecursor // clear display and homecursor
// Does not set twoline mode nor small characters (5x8). The init function of
// the connectiontype should do this.
void void
common_init (enum ifWidth ifwidth) common_init ()
{ {
if (ifwidth == IF_8bit) {
// setup the lcd in 8 bit mode
hd44780_functions->senddata (0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (4100);
hd44780_functions->senddata (0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (100);
hd44780_functions->senddata (0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (40);
}
// else 4bit
// senddata can't generate the timings to initialise a four bit device
// properly but it might just work properly anyway ....
// set display type functions
hd44780_functions->senddata (0, RS_INSTR, FUNCSET | ((ifwidth == IF_4BIT) ? IF_4BIT : IF_8BIT) | TWOLINE | SMALLCHAR);
hd44780_functions->uPause (40);
hd44780_functions->senddata (0, RS_INSTR, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK); hd44780_functions->senddata (0, RS_INSTR, ONOFFCTRL | DISPON | CURSOROFF | CURSORNOBLINK);
hd44780_functions->uPause (40); hd44780_functions->uPause (40);
hd44780_functions->senddata (0, RS_INSTR, CLEAR); hd44780_functions->senddata (0, RS_INSTR, CLEAR);
@@ -368,11 +396,10 @@ uPause (int delayCalls)
delay.tv_sec = remaining.tv_sec; delay.tv_sec = remaining.tv_sec;
delay.tv_nsec = remaining.tv_nsec; delay.tv_nsec = remaining.tv_nsec;
} }
#else #else // using I/O timing
int i; int i;
for (i = 0; i < delayCalls; ++i) for (i = 0; i < delayCalls; ++i)
port_in (port); port_in (port);
//TODO: put in option for nanosleep rather than dummy I/O call
#endif #endif
} }
@@ -381,7 +408,7 @@ static void
HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch) HD44780_senddata (unsigned char displayID, unsigned char flags, unsigned char ch)
{ {
hd44780_functions->senddata (displayID, flags, ch); hd44780_functions->senddata (displayID, flags, ch);
hd44780_functions->uPause (40); hd44780_functions->uPause (40); // Minimum exec time for all commands
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
@@ -420,7 +447,7 @@ void
common_position (int display, int DDaddr) common_position (int display, int DDaddr)
{ {
hd44780_functions->senddata (display, RS_INSTR, POSITION | DDaddr); hd44780_functions->senddata (display, RS_INSTR, POSITION | DDaddr);
hd44780_functions->uPause (40); hd44780_functions->uPause (40); // Minimum exec time for all commands
} }
void HD44780_chr (int x, int y, char ch) void HD44780_chr (int x, int y, char ch)
@@ -453,21 +480,12 @@ HD44780_flush_box (int lft, int top, int rgt, int bot)
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Changes screen contrast (0-255; 140 seems good) // Sets the backlight on or off
//
int
HD44780_contrast (int contrast)
{
return 0;
}
/////////////////////////////////////////////////////////////////
// Sets the backlight on or off -- can be done quickly for
// an intermediate brightness...
// //
void void
HD44780_backlight (int on) HD44780_backlight (int on)
{ {
//hd44780_functions->backlight (on);
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
@@ -491,7 +509,7 @@ void
common_autoscroll (int on) common_autoscroll (int on)
{ {
hd44780_functions->senddata (0, RS_INSTR, ENTRYMODE | E_MOVERIGHT | ((on) ? EDGESCROLL : NOSCROLL)); hd44780_functions->senddata (0, RS_INSTR, ENTRYMODE | E_MOVERIGHT | ((on) ? EDGESCROLL : NOSCROLL));
hd44780_functions->uPause (1600); hd44780_functions->uPause (40);
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
@@ -680,9 +698,7 @@ HD44780_hbar (int x, int y, int len)
void void
HD44780_init_num () HD44780_init_num ()
{ {
char out[3];
snprintf (out, sizeof(out), "%cn", 254);
//write(fd, out, 2);
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
@@ -691,10 +707,8 @@ HD44780_init_num ()
void void
HD44780_num (int x, int num) HD44780_num (int x, int num)
{ {
char out[5]; int offset = HD44780->wid * ( HD44780->hgt / 2 );
printf("Size of out is %d\n", sizeof(out)); HD44780->framebuf[x+offset] = num + '0';
snprintf (out, sizeof(out), "%c#%c%c", 254, x, num);
//write(fd, out, 4);
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
@@ -732,7 +746,7 @@ HD44780_icon (int which, char dest)
{ {
char icons[3][5 * 8] = { char icons[3][5 * 8] = {
{ {
1, 1, 1, 1, 1, // Empty Heart 1, 1, 1, 1, 1, // Empty Heart
1, 0, 1, 0, 1, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -743,7 +757,7 @@ HD44780_icon (int which, char dest)
}, },
{ {
1, 1, 1, 1, 1, // Filled Heart 1, 1, 1, 1, 1, // Filled Heart
1, 0, 1, 0, 1, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
0, 1, 1, 1, 0, 0, 1, 1, 1, 0,
@@ -754,7 +768,7 @@ HD44780_icon (int which, char dest)
}, },
{ {
0, 0, 0, 0, 0, // Ellipsis 0, 0, 0, 0, 0, // Ellipsis
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,
@@ -794,12 +808,12 @@ HD44780_draw_frame (char *dat)
// Parse the span list // Parse the span list
// spanListArray - array to store vertical spans // spanListArray - array to store vertical spans
// spLsize - size of spanListArray // spLsize - size of spanListArray
// dispOffsets - array to store display offsets // dispOffsets - array to store display offsets
// dOffsize - size of dispOffsets // dOffsize - size of dispOffsets
// dispSizeArray - array of display vertical sizes (= spanlist) // dispSizeArray - array of display vertical sizes (= spanlist)
// spanlist - null terminated input span list in comma delimited // spanlist - null terminated input span list in comma delimited
// format. All span elements [1-9] e.g. "1,4,2" // format. All span elements [1-9] e.g. "1,4,2"
// returns number of span elements, -1 on parse error // returns number of span elements, -1 on parse error
int int
@@ -842,3 +856,91 @@ parse_span_list (int *spanListArray[], int *spLsize, int *dispOffsets[], int *dO
} }
return retVal; return retVal;
} }
char HD44780_getkey()
{
unsigned int keybits;
unsigned int shiftcount;
unsigned int shiftingbit;
unsigned int Ypattern;
unsigned int Yval;
char exp;
char ch = 0;
char ch_set = 0;
struct timeval curr_time, time_diff;
gettimeofday(&curr_time,NULL);
// 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; shiftcount<KEYPAD_MAXX && !ch; shiftcount++) {
if ( keybits & shiftingbit) {
// Found ! Return from function.
ch = keyMapDirect[shiftcount];
}
shiftingbit <<= 1;
}
}
else {
// Now check the matrix
// First check with all 1's
Ypattern = (1 << KEYPAD_MAXY) - 1;
if( hd44780_functions->readkeypad (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<<Yval);
shiftingbit=1;
for (shiftcount=0; shiftcount<KEYPAD_MAXX && !ch; shiftcount++) {
if ( keybits & shiftingbit) {
// Found !
ch = keyMapMatrix[Yval][shiftcount];
}
shiftingbit <<= 1;
}
}
}
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\n", ch );
}
}
// Store the key for the next round
pressed_key = ch;
return ch;
}