diff --git a/CREDITS b/CREDITS index c7efa74..c365ef1 100644 --- a/CREDITS +++ b/CREDITS @@ -224,6 +224,9 @@ Karsten Festag Gatewood Green - picolcd driver +Dave Pratt + - overhauled CwLnx driver + Further developers in the sourceforge lcdproc team: Mindaugas Idzelis aim4min diff --git a/ChangeLog b/ChangeLog index 7cd9d0b..10a0705 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,7 @@ v.0.5dev (ongoing development) - server core: cleanup - remove unnecessary cruft * server core: refactor renderin code + LCDd: config options TitleSpeed= and Heartbeat= + * overhauled CwLnx driver (Dave Pratt) v.0.5.2 * fix switching on/off the Load screen in lcdproc client using the menu diff --git a/server/drivers/CwLnx.c b/server/drivers/CwLnx.c index e1612c4..ff668c1 100644 --- a/server/drivers/CwLnx.c +++ b/server/drivers/CwLnx.c @@ -122,6 +122,7 @@ MODULE_EXPORT char *symbol_prefix = "CwLnx_"; static void CwLnx_linewrap(int fd, int on); static void CwLnx_autoscroll(int fd, int on); static void CwLnx_hidecursor(int fd); +static void CwLnx_set_char_unrestricted(Driver *drvthis, int n, unsigned char *dat); #define LCD_CMD 254 @@ -140,31 +141,37 @@ static void CwLnx_hidecursor(int fd); #define LCD_SETCHAR 78 #define LCD_ENABLE_SCROLL 81 #define LCD_DISABLE_SCROLL 82 +#define LCD_SOFT_RESET 86 #define LCD_OFF_CURSOR 72 #define LCD_PUT_PIXEL 112 #define LCD_CLEAR_PIXEL 113 #define DELAY 2000 /* 2 milli sec */ -#define UPDATE_DELAY 0 /* 1 imicro sec */ -#define SETUP_DELAY 1 /* 2 micro sec */ - +#define UPDATE_DELAY 20000 /* 20 milliseconds */ +#define SETUP_DELAY 20000 /* 20 milliseconds */ +#define MOVE_COST 5 /* # bytes for most move-to ops */ static int Write_LCD(int fd, char *c, int size) { - int rc; + int rc, wrote = 0; int retries = 30; do { rc = write(fd, c, size); - if (rc == size) + if (rc > 0) { + c += rc; + size -= rc; + wrote += rc; + } else if (rc == 0 || (rc < 0 && errno == EAGAIN)) { /* would have blocked */ + usleep(DELAY); + } else { break; - usleep(DELAY); + } + } while (size > 0 && --retries > 0); - } while (--retries > 0); - - return rc; + return wrote; } @@ -392,7 +399,20 @@ CwLnx_autoscroll(int fd, int on) static void CwLnx_hidecursor(int fd) { - Disable_Cursor(fd); + Disable_Cursor(fd); +} + + +/******************************************************************** + * Reset the display bios + */ +static void CwLnx_reboot(int fd) +{ + char cmd[] = { LCD_CMD, LCD_SOFT_RESET, LCD_CMD_END }; + + Write_LCD(fd, cmd, 3); + usleep(SETUP_DELAY); + return; } @@ -410,8 +430,6 @@ CwLnx_hidecursor(int fd) MODULE_EXPORT int CwLnx_init(Driver *drvthis) { - struct termios portset_save; - char device[200] = DEFAULT_DEVICE; int speed = DEFAULT_SPEED; char size[200] = DEFAULT_SIZE; @@ -576,23 +594,26 @@ CwLnx_init(Driver *drvthis) } report(RPT_INFO, "%s: opened display on %s", drvthis->name, device); + /* + Since we don't know what speed the display is using when + we first connect to it, configure the port for the speed + we don't want to use, send a command to switch the display + to the speed we want to use, and flush the command. + */ + Init_Port(p->fd); - tcgetattr(p->fd, &portset_save); - speed = B19200; - Setup_Port(p->fd, speed); + if (speed == B9600) { + Setup_Port(p->fd, B19200); Set_9600(p->fd); - close(p->fd); - - p->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); - if (p->fd == -1) { - report(RPT_ERR, "%s: open(%s) failed (%s)", drvthis->name, device, strerror(errno)); - return -1; + } else { + Setup_Port(p->fd, B9600); + Set_19200(p->fd); } - report(RPT_INFO, "%s: opened display on %s", drvthis->name, device); - + tcdrain(p->fd); + usleep(SETUP_DELAY); Init_Port(p->fd); - speed = B9600; Setup_Port(p->fd, speed); + CwLnx_hidecursor(p->fd); CwLnx_linewrap(p->fd, 1); CwLnx_autoscroll(p->fd, 0); @@ -712,7 +733,8 @@ CwLnx_flush(Driver *drvthis) PrivateData *p = drvthis->private_data; int i, j; - int move = 1; + int iUpdate = 0, jUpdate = 0; + unsigned char *firstUpdate = NULL, *lastUpdate = NULL; unsigned char *q = p->framebuf; unsigned char *r = p->backingstore; @@ -720,25 +742,43 @@ CwLnx_flush(Driver *drvthis) for (i = 0; i < p->height; i++) { for (j = 0; j < p->width; j++) { if ((*q == *r) && !((0 < *q) && (*q < 16))) { - move = 1; - } - else { - /* Draw characters that have changed, as well - * as custom characters. We know not if a custom - * character has changed. */ - if (move == 1) { - Set_Insert(p->fd, i, j); - move = 0; + if (firstUpdate && q - lastUpdate > MOVE_COST) { + Set_Insert(p->fd, iUpdate, jUpdate); + Write_LCD(p->fd, (char *) firstUpdate, + lastUpdate - firstUpdate + 1); + firstUpdate = lastUpdate = NULL; + } + } else { + lastUpdate = q; + if (!firstUpdate) { + firstUpdate = q; + iUpdate = i; + jUpdate = j; } - Write_LCD(p->fd, (char *) q, 1); } q++; r++; } } - memcpy(p->backingstore, p->framebuf, p->width * p->height); -} + if (firstUpdate) { + Set_Insert(p->fd, iUpdate, jUpdate); + Write_LCD(p->fd, (char *) firstUpdate, + lastUpdate - firstUpdate + 1); + } + memcpy(p->backingstore, p->framebuf, p->width * p->height); + + if (p->backlight != p->saved_backlight || + p->brightness != p->saved_brightness) { + if (!p->backlight) { + Backlight_Brightness(p->fd, 1); + } else { + Backlight_Brightness(p->fd, 1 + p->brightness * 6 / 900); /* 90% and up is full brightness */ + } + p->saved_backlight = p->backlight; + p->saved_brightness = p->brightness; + } +} /** * Print a character on the screen at position (x,y). @@ -904,7 +944,11 @@ CwLnx_hbar(Driver *drvthis, int x, int y, int len, int promille, int options) for (i = 1; i <= p->cellwidth; i++) { // fill pixel columns from left to right. memset(hBar, 0xFF & ~((1 << (p->cellwidth - i)) - 1), sizeof(hBar)); +#if defined(SEAMLESS_HBARS) + CwLnx_set_char_unrestricted(drvthis, i+1, hBar); +#else CwLnx_set_char(drvthis, i+1, hBar); +#endif } } @@ -1020,6 +1064,65 @@ CwLnx_set_char(Driver *drvthis, int n, unsigned char *dat) } +/* + * Identical to CwLnx_set_char, but it doesn't restrict the 12232 to + * using only 5 of its 6 columns. Full 6-column mode is required + * for seamless H-bars. + */ + +#if defined(SEAMLESS_HBARS) +static void +CwLnx_set_char_unrestricted(Driver *drvthis, int n, unsigned char *dat) +{ + PrivateData *p = drvthis->private_data; + + char c; + int rc; + + if ((n <= 0) || (n > CwLnx_get_free_chars(drvthis))) + return; + if (!dat) + return; + + c = LCD_CMD; + rc = Write_LCD(p->fd, &c, 1); + c = LCD_SETCHAR; + rc = Write_LCD(p->fd, &c, 1); + c = (char) n; + rc = Write_LCD(p->fd, &c, 1); + + if (p->model == 1602) { // the character model + unsigned char mask = (1 << p->cellwidth) - 1; + int row; + + for (row = 0; row < p->cellheight; row++) { + c = dat[row] & mask; + Write_LCD(p->fd, &c, 1); + } + } else if (p->model == 12232) { // the graphical model + int col; + + for (col = p->cellwidth - 1; col >= 0; col--) { + int letter = 0; + int row; + + for (row = p->cellheight - 1; row >= 0; row--) { + letter <<= 1; + letter |= ((dat[row] >> col) & 1); + } + + c = letter; + + Write_LCD(p->fd, &c, 1); + } + } + + c = LCD_CMD_END; + rc = Write_LCD(p->fd, &c, 1); +} +#endif + + /** * Place an icon on the screen. * \param drvthis Pointer to driver structure. diff --git a/server/drivers/CwLnx.h b/server/drivers/CwLnx.h index e6a17db..5cc149a 100644 --- a/server/drivers/CwLnx.h +++ b/server/drivers/CwLnx.h @@ -31,7 +31,7 @@ #define DEFAULT_DEVICE "/dev/lcd" #define DEFAULT_BACKLIGHT 1 -#define DEFAULT_BRIGHTNESS 200 +#define DEFAULT_BRIGHTNESS 700 #define DEFAULT_CELL_WIDTH_1602 5 #define DEFAULT_CELL_WIDTH_12232 6