From add433dc14a9686d39981b8a2e9722a2bcbae7d0 Mon Sep 17 00:00:00 2001 From: reinelt Date: Wed, 4 Feb 2004 19:10:51 +0000 Subject: [lcd4linux @ 2004-02-04 19:10:51 by reinelt] Crystalfontz driver nearly finished git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@354 3ae390bd-cb1e-0410-b409-cd5a39f66f1f --- drv_Crystalfontz.c | 454 ++++++++++++++++++++++++++++++++++++++++---------- drv_HD44780.c | 20 +-- drv_generic_serial.c | 33 ++-- lcd4linux.conf.sample | 4 +- plugin_proc_stat.c | 6 +- 5 files changed, 400 insertions(+), 117 deletions(-) diff --git a/drv_Crystalfontz.c b/drv_Crystalfontz.c index e8fefa2..0d68f84 100644 --- a/drv_Crystalfontz.c +++ b/drv_Crystalfontz.c @@ -1,4 +1,4 @@ -/* $Id: drv_Crystalfontz.c,v 1.8 2004/02/01 08:05:12 reinelt Exp $ +/* $Id: drv_Crystalfontz.c,v 1.9 2004/02/04 19:10:51 reinelt Exp $ * * new style driver for Crystalfontz display modules * @@ -23,6 +23,9 @@ * * * $Log: drv_Crystalfontz.c,v $ + * Revision 1.9 2004/02/04 19:10:51 reinelt + * Crystalfontz driver nearly finished + * * Revision 1.8 2004/02/01 08:05:12 reinelt * Crystalfontz 633 extensions (CRC checking and stuff) * Models table for HD44780 @@ -70,6 +73,7 @@ #include "debug.h" #include "cfg.h" +#include "timer.h" #include "plugin.h" #include "widget.h" #include "widget_text.h" @@ -84,6 +88,22 @@ static char Name[]="Crystalfontz"; static int Model; static int Protocol; +static int Row, Col; + +// ring buffer for bytes received from the display +static unsigned char RingBuffer[256]; +static int RingRPos = 0; +static int RingWPos = 0; + +// packet from the display +struct { + unsigned char type; + unsigned char size; + unsigned char data[16+1]; // trailing '\0' +} Packet; + +// Line Buffer for 633 displays +static char Line[2*16]; // Fixme: // static int GPO[8]; @@ -101,16 +121,15 @@ typedef struct { // Fixme #1: number of gpo's should be verified // Fixme #2: protocol should be verified -// Fixme #3: do CF displays have type numbers? static MODEL Models[] = { - { 0x26, "626", 2, 16, 0, 1 }, - { 0x31, "631", 2, 16, 0, 2 }, - { 0x32, "632", 2, 16, 0, 1 }, - { 0x33, "633", 2, 16, 0, 2 }, - { 0x34, "634", 4, 20, 0, 1 }, - { 0x36, "636", 2, 16, 0, 1 }, - { 0xff, "Unknown", -1, -1, 0, 0 } + { 626, "626", 2, 16, 0, 1 }, + { 631, "631", 2, 20, 0, 3 }, + { 632, "632", 2, 16, 0, 1 }, + { 633, "633", 2, 16, 0, 2 }, + { 634, "634", 4, 20, 0, 1 }, + { 636, "636", 2, 16, 0, 1 }, + { -1, "Unknown", -1, -1, 0, 0 } }; @@ -132,113 +151,343 @@ static unsigned short CRC (unsigned char *p, size_t len, unsigned short seed) return ~seed; } +static unsigned char LSB (unsigned short word) +{ + return word & 0xff; +} -static void drv_CF_write_crc (char *string, int len) +static unsigned char MSB (unsigned short word) { - unsigned char buffer[16+2]; + return word >> 8; +} + + +static unsigned char byte (int pos) +{ + pos+=RingRPos; + if (pos>=sizeof(RingBuffer)) + pos-=sizeof(RingBuffer); + return RingBuffer[pos]; +} + + +static void drv_CF_process_packet (void) +{ + // debugging only + if (0) debug ("Packet: type=%d (%d) len=%d data=<%s>", + Packet.type, Packet.type & 0x3f, Packet.size, Packet.data); +} + + +static int drv_CF_poll (void) +{ + char buffer[32]; unsigned short crc; + int n, num, size; + + // read into RingBuffer + while (1) { + num=drv_generic_serial_poll(buffer, 32); + if (num<=0) break; + // put result into RingBuffer + for (n=0; n=sizeof(RingBuffer)) RingWPos=0; + } + } + + // process RingBuffer + while (1) { + // packet size + num=RingWPos-RingRPos; + if (num < 0) num+=10; + // minimum packet size=4 + if (num < 4) return 0; + // valid response types: 01xxxxx 10.. 11.. + // therefore: 00xxxxxx is invalid + if (byte(0)>>6 == 0) goto GARBAGE; + // valid command length is 0 to 16 + if (byte(1) > 16) goto GARBAGE; + // all bytes available? + size=byte(1); + if (num < size+4) return 0; + // check CRC + for (n=0; n= sizeof(RingBuffer)) RingRPos -= sizeof(RingBuffer); + // a packet arrived + return 1; + GARBAGE: + debug ("dropping garbage byte %d", byte(0)); + RingRPos++; + if (RingRPos>=sizeof(RingBuffer)) RingRPos=0; + continue; + } + + // not reached + return 0; +} + +static void drv_CF_timer (void *notused) +{ + while (drv_CF_poll()) { + drv_CF_process_packet(); + } +} + + +static void drv_CF_send (int cmd, int len, char *data) +{ + unsigned char buffer[16+2]; + unsigned short crc; if (len>sizeof(buffer)-2) { error ("%s: internal error: packet length %d exceeds buffer size %d", Name, len, sizeof(buffer)-2); len=sizeof(buffer)-1; } - strcpy (buffer, string); - crc = CRC(buffer, len, 0xffff); - buffer[len] = crc & 0xff; - buffer[len+1] = (crc >> 8); + buffer[0]=cmd; + buffer[1]=len; + memcpy (buffer+2, data, len); + crc = CRC(buffer, len+2, 0xffff); + buffer[len+2] = LSB(crc); + buffer[len+3] = MSB(crc); + + if (0) debug ("Tx Packet %d len=%d", buffer[0], buffer[1]); + + drv_generic_serial_write (buffer, len+4); + +} - drv_generic_serial_write (buffer, len+2); +static void drv_CF_write1 (char *string, int len) +{ + drv_generic_serial_write (string, len); } -static void drv_CF_write (char *string, int len) +static void drv_CF_write2 (char *string, int len) { - switch (Protocol) { - case 1: - drv_generic_serial_write (string, len); - break; - case 2: - drv_CF_write_crc (string, len); - break; + // limit length + if (Col+len>16) len=16-Col; + + // sanity check + if (Row>=2 || Col+len>16) { + error ("%s: internal error: write outside linebuffer bounds!", Name); + return; } + + memcpy (Line+16*Row+Col, string, len); + drv_CF_send (7+Row, 16, Line+16*Row); } -static void drv_CF_goto (int row, int col) +static void drv_CF_write3 (char *string, int len) { - char cmd[3]="\021xy"; // set cursor position + debug ("write3(<%.*s>,%d)", len, string, len); +} + +static void drv_CF_goto1 (int row, int col) +{ + char cmd[3]="\021xy"; // set cursor position + if (row==0 && col==0) { - drv_generic_serial_write("\001", 1); // cursor home + drv_CF_write1("\001", 1); // cursor home } else { cmd[1]=(char)col; cmd[2]=(char)row; - drv_generic_serial_write(cmd, 3); + drv_CF_write1(cmd, 3); } } +static void drv_CF_goto23 (int row, int col) +{ + // as the 633 does not have random access to the display content, + // and the 631 needs coordinates with random access, + // we just store the needed cursor position + Row=row; + Col=col; +} -static void drv_CF_defchar (int ascii, char *buffer) + +static void drv_CF_defchar1 (int ascii, char *buffer) { char cmd[2]="\031n"; // set custom char bitmap - + // user-defineable chars start at 128, but are defined at 0 cmd[1]=(char)(ascii-CHAR0); - drv_generic_serial_write (cmd, 2); - drv_generic_serial_write (buffer, 8); + drv_CF_write1 (cmd, 2); + drv_CF_write1 (buffer, 8); +} + + +static void drv_CF_defchar23 (int ascii, char *matrix) +{ + char buffer[9]; + + // user-defineable chars start at 128, but are defined at 0 + buffer[0] = (char)(ascii-CHAR0); + memcpy(buffer+1, matrix, 8); + drv_CF_send (9, 9, buffer); } +static int drv_CF_contrast (int contrast) +{ + char buffer[2]; + + if (contrast<0 ) contrast=0; + if (contrast>100) contrast=100; + + switch (Protocol) { + + case 1: + buffer[0] = 15; // Set LCD Contrast + buffer[1] = contrast; + drv_CF_write1 (buffer, 2); + break; + + case 2: + case 3: + // contrast goes from 0 to 50 only + if (contrast>50) contrast=50; + buffer[0] = contrast; + drv_CF_send (13, 1, buffer); + break; + } + + return contrast; +} + + +static int drv_CF_backlight (int backlight) +{ + char buffer[3]; + + if (backlight<0 ) backlight=0; + if (backlight>100) backlight=100; + + switch (Protocol) { + + case 1: + buffer[0] = 14; // Set LCD backlight + buffer[1] = backlight; + drv_CF_write1 (buffer, 2); + break; + + case 2: + case 3: + buffer[0] = backlight; + drv_CF_send (14, 1, buffer); + break; + } + + return backlight; +} + + +static int drv_CF_autodetect (void) +{ + int i, m; + + // only autodetect newer displays + if (Protocol<2) return -1; + + // read display type + drv_CF_send (1, 0, NULL); + + i=0; + while (1) { + // wait 10 msec + usleep(10*1000); + // packet available? + if (drv_CF_poll()) { + // display type + if (Packet.type==0x41) { + char t[7]; float h, v; + info ("%s: display identifies itself as '%s'", Name, Packet.data); + if (sscanf(Packet.data, "%6s:h%f,v%f", t, &h, &v)!=3) { + error ("%s: error parsing display identification string", Name); + return -1; + } + info ("%s: display type '%s', hardware version %3.1f, firmware version %3.1f", Name, t, h, v); + if (strncmp(t, "CFA", 3)==0) { + for (m=0; Models[m].type!=-1; m++) { + // omit the 'CFA' + if (strcasecmp(Models[m].name, t+3)==0) + return m; + } + } + error ("%s: display type '%s' may be not supported!", Name, t); + return -1; + } + drv_CF_process_packet(); + } + // wait no longer than 300 msec + if (++i > 30) { + error ("%s: display detection timed out", Name); + return -1; + } + } + + // not reached + return -1; +} + + static int drv_CF_start (char *section) { int i; char *model; - char buffer[17]; + char buffer; model=cfg_get(section, "Model", NULL); if (model!=NULL && *model!='\0') { - for (i=0; Models[i].type!=0xff; i++) { + for (i=0; Models[i].type!=-1; i++) { if (strcasecmp(Models[i].name, model)==0) break; } - if (Models[i].type==0xff) { + if (Models[i].type==-1) { error ("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source()); return -1; } - Model=i; - info ("%s: using model '%s'", Name, Models[Model].name); + Model = i; Protocol = Models[Model].protocol; + info ("%s: using model '%s'", Name, Models[Model].name); } else { - info ("%s: no '%s.Model' entry from %s, auto-dedecting", Name, section, cfg_source()); - Model=-1; - Protocol=2; //auto-dedect only newer displays + Model = -1; + Protocol = 2; //auto-detect only newer displays + info ("%s: no '%s.Model' entry from %s, auto-detecting", Name, section, cfg_source()); } // open serial port if (drv_generic_serial_open(section, Name)<0) return -1; - // MR: why such a large delay? + // Fixme: why such a large delay? usleep(350*1000); - // read display type - memset(buffer, 0, sizeof(buffer)); - drv_CF_write ("\1", 2); - usleep(250*1000); -#if 1 - while (1) { - int len; - // memset(buffer, 0, sizeof(buffer)); - len=drv_generic_serial_read (buffer, 16); - debug ("Michi1: len=<%d> buffer=<%d> <%d> <%d> <%d> <%s>", len, buffer[0], buffer[1], buffer[2], buffer[3], buffer); - usleep(250*1000); + // display autodetection + i=drv_CF_autodetect(); + if (Model==-1) Model=i; + if (Model==-1) { + error ("%s: auto-detection failed, please specify a '%s.Model' entry in %s", Name, section, cfg_source()); + return -1; } -#else - if (drv_generic_serial_read (buffer, 16)==16) { - info ("%s: display reports serial number 0x%x", Name, *(short*)buffer); + if (i!=-1 && Model!=i) { + error ("%s: %s.Model '%s' from %s does not match detected model '%s'", + Name, section, model, cfg_source(), Models[i].name); + return -1; } -#endif // initialize global variables DROWS = Models[Model].rows; @@ -246,10 +495,37 @@ static int drv_CF_start (char *section) GPOS = Models[Model].gpos; Protocol = Models[Model].protocol; - drv_generic_serial_write ("\014", 1); // Form Feed (Clear Display) - drv_generic_serial_write ("\004", 1); // hide cursor - drv_generic_serial_write ("\024", 1); // scroll off - drv_generic_serial_write ("\030", 1); // wrap off + // regularly process display answers + // Fixme: make 20msec configurable + timer_add (drv_CF_timer, NULL, 100, 0); + + switch (Protocol) { + case 1: + drv_CF_write1 ("\014", 1); // Form Feed (Clear Display) + drv_CF_write1 ("\004", 1); // hide cursor + drv_CF_write1 ("\024", 1); // scroll off + drv_CF_write1 ("\030", 1); // wrap off + break; + case 2: + case 3: + drv_CF_send ( 6, 0, NULL); // Clear Display + buffer=0; + drv_CF_send (12, 1, &buffer); // Set LCD Cursor Style + break; + } + + // clear 633 linebuffer + memset (Line, ' ', sizeof(Line)); + + // set contrast + if (cfg_number(section, "Contrast", 0, 0, 100, &i)==0) { + drv_CF_contrast(i); + } + + // set backlight + if (cfg_number(section, "Backlight", 0, 0, 100, &i)==0) { + drv_CF_backlight(i); + } return 0; } @@ -262,38 +538,25 @@ static int drv_CF_start (char *section) static void plugin_contrast (RESULT *result, RESULT *arg1) { - char buffer[3]; double contrast; - contrast=R2N(arg1); - if (contrast<0 ) contrast=0; - if (contrast>100) contrast=100; - - snprintf (buffer, 3, "\017%c", (int)contrast); - drv_generic_serial_write (buffer, 2); - + contrast=drv_CF_contrast(R2N(arg1)); SetResult(&result, R_NUMBER, &contrast); } static void plugin_backlight (RESULT *result, RESULT *arg1) { - char buffer[3]; double backlight; - - backlight=R2N(arg1); - if (backlight<0 ) backlight=0; - if (backlight>100) backlight=100; - - snprintf (buffer, 4, "\016%c", (int)backlight); - drv_generic_serial_write (buffer, 3); - + + backlight=drv_CF_backlight(R2N(arg1)); SetResult(&result, R_NUMBER, &backlight); } // Fixme: other plugins for Fans, Temmperature sensors, ... + // **************************************** // *** widget callbacks *** // **************************************** @@ -313,7 +576,7 @@ int drv_CF_list (void) { int i; - for (i=0; Models[i].type!=0xff; i++) { + for (i=0; Models[i].type!=-1; i++) { printf ("%s ", Models[i].name); } return 0; @@ -326,22 +589,37 @@ int drv_CF_init (char *section) WIDGET_CLASS wc; int ret; + // start display + if ((ret=drv_CF_start (section))!=0) + return ret; + // display preferences XRES = 6; // pixel width of one char YRES = 8; // pixel height of one char CHARS = 8; // number of user-defineable characters - CHAR0 = 128; // ASCII of first user-defineable char GOTO_COST = 3; // number of bytes a goto command requires // real worker functions - drv_generic_text_real_write = drv_generic_serial_write; - drv_generic_text_real_goto = drv_CF_goto; - drv_generic_text_real_defchar = drv_CF_defchar; - - - // start display - if ((ret=drv_CF_start (section))!=0) - return ret; + switch (Protocol) { + case 1: + CHAR0 = 128; // ASCII of first user-defineable char + drv_generic_text_real_goto = drv_CF_goto1; + drv_generic_text_real_write = drv_CF_write1; + drv_generic_text_real_defchar = drv_CF_defchar1; + break; + case 2: + CHAR0 = 0; // ASCII of first user-defineable char + drv_generic_text_real_goto = drv_CF_goto23; + drv_generic_text_real_write = drv_CF_write2; + drv_generic_text_real_defchar = drv_CF_defchar23; + break; + case 3: + CHAR0 = 0; // ASCII of first user-defineable char + drv_generic_text_real_goto = drv_CF_goto23; + drv_generic_text_real_write = drv_CF_write2; + drv_generic_text_real_defchar = drv_CF_defchar23; + break; + } // initialize generic text driver if ((ret=drv_generic_text_init(section, Name))!=0) @@ -357,6 +635,8 @@ int drv_CF_init (char *section) // add fixed chars to the bar driver drv_generic_text_bar_add_segment (0, 0, 255, 32); // ASCII 32 = blank + if (Protocol==2) + drv_generic_text_bar_add_segment (255,255,255,255); // ASCII 255 = block // register text widget wc=Widget_Text; diff --git a/drv_HD44780.c b/drv_HD44780.c index 30a848e..2ec1fd0 100644 --- a/drv_HD44780.c +++ b/drv_HD44780.c @@ -1,4 +1,4 @@ -/* $Id: drv_HD44780.c,v 1.10 2004/02/02 05:22:16 reinelt Exp $ +/* $Id: drv_HD44780.c,v 1.11 2004/02/04 19:10:51 reinelt Exp $ * * new style driver for HD44780-based displays * @@ -29,6 +29,9 @@ * * * $Log: drv_HD44780.c,v $ + * Revision 1.11 2004/02/04 19:10:51 reinelt + * Crystalfontz driver nearly finished + * * Revision 1.10 2004/02/02 05:22:16 reinelt * Brightness fpr Noritake Displays avaliable as a plugin * @@ -763,18 +766,3 @@ DRIVER drv_HD44780 = { }; -#if 0 -+ -+// Change Noritake CU series VFD brightness level -+ char tmpbuffer[2]; -+ int cu_vfd_brightness; -+ if (cfg_number("CU_VFD_Brightness", 0, 0, 3, &cu_vfd_brightness)<0) return -1; -+ if (cu_vfd_brightness) { - + snprintf (tmpbuffer, 2, "\%o", cu_vfd_brightness); - + HD_command (0x03, 0x38, T_EXEC); // enable function - + HD_write (0x03, tmpbuffer, 1, T_WRCG); // set brightness - + info ("HD44780: Noritake CU VFD detected. Brightness = %d (0-3)", cu_vfd_brightness); - + info (" Settings: 0=100\%, 1=75\%, 2=50\%, 3=25\%"); - + } - -#endif diff --git a/drv_generic_serial.c b/drv_generic_serial.c index de6a39a..56bbdb8 100644 --- a/drv_generic_serial.c +++ b/drv_generic_serial.c @@ -1,4 +1,4 @@ -/* $Id: drv_generic_serial.c,v 1.4 2004/02/01 08:05:12 reinelt Exp $ +/* $Id: drv_generic_serial.c,v 1.5 2004/02/04 19:10:51 reinelt Exp $ * * generic driver helper for serial and usbserial displays * @@ -23,6 +23,9 @@ * * * $Log: drv_generic_serial.c,v $ + * Revision 1.5 2004/02/04 19:10:51 reinelt + * Crystalfontz driver nearly finished + * * Revision 1.4 2004/02/01 08:05:12 reinelt * Crystalfontz 633 extensions (CRC checking and stuff) * Models table for HD44780 @@ -54,8 +57,13 @@ * int drv_generic_serial_open (char *driver, char *port, speed_t speed); * opens the serial port * + * int drv_generic_serial_poll (char *string, int len) + * reads from the serial or USB port + * without retry + * * int drv_generic_serial_read (char *string, int len); * reads from the serial or USB port + * with retry * * void drv_generic_serial_write (char *string, int len); * writes to the serial or USB port @@ -285,8 +293,13 @@ int drv_generic_serial_open (char *section, char *driver) int drv_generic_serial_poll (char *string, int len) { + int ret; if (Device==-1) return -1; - return read (Device, string, len); + ret=read (Device, string, len); + if (ret<0 && errno!=EAGAIN) { + error("%s: read(%s) failed: %s", Driver, Port, strerror(errno)); + } + return ret; } @@ -297,14 +310,12 @@ int drv_generic_serial_read (char *string, int len) for (run=0; run<10; run++) { ret=drv_generic_serial_poll(string, len); if (ret>=0 || errno!=EAGAIN) break; - debug ("read(): EAGAIN"); + info ("%s: read(%s): EAGAIN", Driver, Port); usleep(1000); } - if (ret<0) { - error("%s: read(%s, %d) failed: %s", Driver, Port, len, strerror(errno)); - } else if (ret!=len) { - error ("%s: partial read: len=%d ret=%d", Driver, len, ret); + if (ret>0 && ret!=len) { + error ("%s: partial read(%s): len=%d ret=%d", Driver, Port, len, ret); } return ret; @@ -319,14 +330,14 @@ void drv_generic_serial_write (char *string, int len) for (run=0; run<10; run++) { ret=write (Device, string, len); if (ret>=0 || errno!=EAGAIN) break; - debug ("write(): EAGAIN"); + info ("%s: write(%s): EAGAIN", Driver, Port); usleep(1000); } if (ret<0) { - error ("MatrixOrbital: write(%s) failed: %s", Port, strerror(errno)); + error ("%s: write(%s) failed: %s", Driver, Port, strerror(errno)); } else if (ret!=len) { - error ("MatrixOrbital: partial write: len=%d ret=%d", len, ret); + error ("%s: partial write(%s): len=%d ret=%d", Driver, Port, len, ret); } return; @@ -335,7 +346,7 @@ void drv_generic_serial_write (char *string, int len) int drv_generic_serial_close (void) { - debug ("%s: closing port %s", Driver, Port); + info ("%s: closing port %s", Driver, Port); close (Device); drv_generic_serial_unlock_port(Port); return 0; diff --git a/lcd4linux.conf.sample b/lcd4linux.conf.sample index 197bf94..f7f14ab 100644 --- a/lcd4linux.conf.sample +++ b/lcd4linux.conf.sample @@ -26,11 +26,13 @@ Display CF632 { } Display CF633 { - Icons 1 + Icons 4 Driver 'Crystalfontz' Model '633' Port '/dev/tts/0' Speed 19200 + Contrast 16 + Backlight 50 } Display HD44780-20x4 { diff --git a/plugin_proc_stat.c b/plugin_proc_stat.c index 48a19a0..f7276c4 100644 --- a/plugin_proc_stat.c +++ b/plugin_proc_stat.c @@ -1,4 +1,4 @@ -/* $Id: plugin_proc_stat.c,v 1.14 2004/02/01 19:37:40 reinelt Exp $ +/* $Id: plugin_proc_stat.c,v 1.15 2004/02/04 19:10:51 reinelt Exp $ * * plugin for /proc/stat parsing * @@ -23,6 +23,9 @@ * * * $Log: plugin_proc_stat.c,v $ + * Revision 1.15 2004/02/04 19:10:51 reinelt + * Crystalfontz driver nearly finished + * * Revision 1.14 2004/02/01 19:37:40 reinelt * got rid of every strtok() incarnation. * @@ -100,7 +103,6 @@ static HASH Stat = { 0, }; static void hash_set1 (char *key1, char *val) { - debug ("Michi: hash_set (<%s>=<%s>)", key1, val); hash_set_delta (&Stat, key1, val); } -- cgit v1.2.3