From 20d44982da55ee64afcd060111f66daffa82355e Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Fri, 22 Apr 2011 14:55:36 +0200 Subject: [PATCH] scrolling --- TODO | 1 - lcd.c | 173 +++++++++++++++++++++++++++++++++++++----------------- lcd.h | 15 +++-- qnaplcd.c | 15 +++-- 4 files changed, 139 insertions(+), 65 deletions(-) diff --git a/TODO b/TODO index 9681b48..5d6b904 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,5 @@ - dynamic pages - refresh of dynamic pages (clock, loadavg) -- scrolling - disk utilization (MB/GB) - mntpoints given in config diff --git a/lcd.c b/lcd.c index 1f79423..8c5721d 100644 --- a/lcd.c +++ b/lcd.c @@ -13,6 +13,7 @@ #include "logging.h" #define _LCD_DEBUG 1 +#define _LCD_FAKE 1 #define LCD_RESET_TIMEOUT_US 250000 /* 250ms */ #define LCD_RESET_RETRY_TIMEOUT 10 /* 10s */ @@ -41,14 +42,17 @@ struct lcddev { int fd; struct termios oldtio; - int backlight_time; enum lcdstate state; - int (*button_cb)(struct lcddev *dev, int button, void *privdata); - void *privdata; + int backlight_state; + + int (*event_callback)(struct lcddev *dev, int event, void *privdata); + void *event_privdata; const char *line_data[2]; - int scrollpos; + int line_length[2]; + int scroll_speed; + int scroll_pos; struct event_fd *read_event; struct event_timeout *reset_timeout; @@ -92,9 +96,22 @@ static int lcd_open(struct lcddev *dev, const char *device) return 0; } +#if (_LCD_DEBUG > 1) +static void lcd_dump(const char *prefix, int len, int size, const char *buf) +{ + int i; + + fprintf(stderr, "%s:[%d/%d]: ", prefix, len, size); + for (i = 0; i < len; i++) + fprintf(stderr, "0x%X ", (unsigned char)buf[i]); + + fprintf(stderr, "\n"); +} +#endif + static int lcd_read(struct lcddev *dev, const char *buf, int len) { - int retval = 0, i, cnt = 0; + int retval = 0, cnt = 0; while (cnt < len) { retval = read(dev->fd, (char *)buf + cnt, len - cnt); if (retval <= 0) @@ -102,37 +119,27 @@ static int lcd_read(struct lcddev *dev, const char *buf, int len) cnt += retval; } -#if _LCD_DEBUG - fprintf(stderr, "lcd_read[%d/%d]: ", cnt, len); - for (i = 0; i < cnt; i++) - fprintf(stderr, "0x%X ", (unsigned char)buf[i]); - fprintf(stderr, "\n"); +#if (_LCD_DEBUG > 1) + lcd_dump("lcd_read", cnt, len, buf); #endif return (cnt != 0) ? cnt : retval; } static int lcd_write(struct lcddev *dev, char *buf, int len) { - int retval, i; + int retval = write(dev->fd, buf, len); - retval = write(dev->fd, buf, len); -#if _LCD_DEBUG - fprintf(stderr, "lcd_write[%d/%d]: ", retval, len); - for (i = 0; i < retval; i++) - fprintf(stderr, "0x%X ", (unsigned char)buf[i]); - - if (len == 20) { - fprintf(stderr, "'%-16s'", buf + 4); - } - - fprintf(stderr, "\n"); +#if (_LCD_DEBUG > 1) + lcd_dump("lcd_write", retval, len, buf); #endif return retval; } +#if (_LCD_FAKE == 0) static int lcd_reset_retry_timeout_cb(void *privdata) { struct lcddev *dev = (struct lcddev *)privdata; + dev->reset_timeout = NULL; lcd_reset(dev); return -1; /* singleshot */ @@ -150,16 +157,30 @@ static int lcd_reset_timeout_cb(void *privdata) return -1; /* singleshot */ } +#endif void lcd_reset(struct lcddev *dev) { +#if (_LCD_DEBUG > 0) + fprintf(stderr, "lcd_reset()\n"); +#endif + char cmd[] = A125_CMD_RESET; lcd_write(dev, cmd, sizeof(cmd)); + dev->backlight_state = -1; + +#if (_LCD_FAKE == 0) dev->state = LCD_STATE_INITIALIZING; struct timeval tv = { .tv_usec = LCD_RESET_TIMEOUT_US }; dev->reset_timeout = event_add_timeout(&tv, lcd_reset_timeout_cb, dev); +#else + dev->state = LCD_STATE_READY; + + /* trigger application to set data */ + dev->event_callback(dev, LCD_EVENT_INIT, dev->event_privdata); +#endif } static int lcd_backlight(struct lcddev *dev, int mode) @@ -167,9 +188,17 @@ static int lcd_backlight(struct lcddev *dev, int mode) if (dev->state != LCD_STATE_READY) return -1; - char cmd[] = A125_CMD_BACKLIGHT; - cmd[2] = (mode) ? 0x01 : 0x00; - lcd_write(dev, cmd, sizeof(cmd)); +#if (_LCD_DEBUG > 0) + fprintf(stderr, "lcd_backlight(%d)\n", mode); +#endif + + if (dev->backlight_state != mode) { + char cmd[] = A125_CMD_BACKLIGHT; + cmd[2] = (mode) ? 0x01 : 0x00; + lcd_write(dev, cmd, sizeof(cmd)); + } + + dev->backlight_state = mode; return 0; } @@ -179,6 +208,7 @@ static int lcd_backlight_timeout_cb(void *privdata) dev->backlight_timeout = NULL; lcd_backlight(dev, 0); + dev->event_callback(dev, LCD_EVENT_BACKLIGHT, dev->event_privdata); return -1; /* singleshot */ } @@ -189,10 +219,12 @@ int lcd_trigger_backlight(struct lcddev *dev, int timeout) dev->backlight_timeout = NULL; } - int retval = lcd_backlight(dev, 1); + int retval = lcd_backlight(dev, (timeout == 0) ? 0 : 1); - struct timeval tv = { .tv_sec = timeout }; - dev->backlight_timeout = event_add_timeout(&tv, lcd_backlight_timeout_cb, dev); + if (timeout != -1) { + struct timeval tv = { .tv_sec = timeout }; + dev->backlight_timeout = event_add_timeout(&tv, lcd_backlight_timeout_cb, dev); + } return retval; } @@ -205,7 +237,6 @@ static int lcd_read_cb(int fd, void *privdata) int size = (dev->state != LCD_STATE_INITIALIZING) ? sizeof(buf) : 2; int len = lcd_read(dev, buf, size); - int retval = 0; if (dev->state == LCD_STATE_INITIALIZING) { char expect[] = A125_EVENT_ACTINFO; @@ -219,7 +250,7 @@ static int lcd_read_cb(int fd, void *privdata) dev->state = LCD_STATE_READY; /* trigger application to set data */ - retval = dev->button_cb(dev, LCD_BUTTON0, dev->privdata); + dev->event_callback(dev, LCD_EVENT_INIT, dev->event_privdata); } } else if (dev->state == LCD_STATE_READY) { @@ -230,57 +261,95 @@ static int lcd_read_cb(int fd, void *privdata) return 0; if (memcmp(buf, expect1, sizeof(buf)) == 0) { - retval = dev->button_cb(dev, LCD_BUTTON1, dev->privdata); + dev->event_callback(dev, LCD_EVENT_BUTTON1, dev->event_privdata); } else if (memcmp(buf, expect2, sizeof(buf)) == 0) { - retval = dev->button_cb(dev, LCD_BUTTON2, dev->privdata); + dev->event_callback(dev, LCD_EVENT_BUTTON2, dev->event_privdata); } } - if (retval) - lcd_trigger_backlight(dev, dev->backlight_time); - return 0; } -static int lcd_setline(struct lcddev *dev, int line, const char *buf) +static int lcd_setline(struct lcddev *dev, int line, int len, const char *buf) { if (dev->state != LCD_STATE_READY) return -1; - char cmd[20] = A125_CMD_SETLINE; + char cmd[20 +1] = A125_CMD_SETLINE; cmd[2] = line; memset(cmd +4, ' ', 16); - int len = strlen(buf); memcpy(cmd +4, buf, (len > 16) ? 16 : len); + cmd[20] = '\0'; - lcd_write(dev, cmd, sizeof(cmd)); +#if (_LCD_DEBUG > 0) + fprintf(stderr, "lcd_setline(%d, '%-16s')\n", line, cmd +4); +#endif + + lcd_write(dev, cmd, 20); return 0; } static int lcd_scroll_timeout_cb(void *privdata) { - // TODO: scrolling + struct lcddev *dev = (struct lcddev *)privdata; + int i, reset_pos = 0; - return 0; /* periodic */ + for (i = 0; i < 2; i++) { + int line_pos = dev->scroll_pos; + if (line_pos < 0) + line_pos = 0; + + /* mark line as complete if one space is visible after message */ + if ((dev->line_length[i] - line_pos) <= 15) { + reset_pos++; + } + + /* do not scroll further if message is not visible */ + if ((dev->line_length[i] - line_pos) < 0) { + line_pos = dev->line_length[i]; + } + + lcd_setline(dev, i, dev->line_length[i] - line_pos, dev->line_data[i] + line_pos); + } + + dev->scroll_pos++; + + if (reset_pos == 2) + dev->scroll_pos = -1; + + /* disable scrolling if backlight is off (display is not visible) */ + if (dev->backlight_state == 0) { + dev->scroll_timeout = NULL; + return -1; + } + + /* periodic */ + return 0; } -int lcd_setlines(struct lcddev *dev, int scrollspeed, const char *line1, const char *line2) +int lcd_setlines(struct lcddev *dev, int scroll_speed, const char *line1, const char *line2) { dev->line_data[0] = line1; - lcd_setline(dev, 0, line1); + dev->line_length[0] = (line1 != NULL) ? strlen(line1) : 0; + lcd_setline(dev, 0, dev->line_length[0], dev->line_data[0]); dev->line_data[1] = line2; - lcd_setline(dev, 1, line2); + dev->line_length[1] = (line2 != NULL) ? strlen(line2) : 0; + lcd_setline(dev, 1, dev->line_length[1], dev->line_data[1]); - if (dev->scroll_timeout) { + int scroll_enable = (dev->line_length[0] > 16 && dev->line_length[1] > 16); + if (dev->scroll_timeout && ((dev->scroll_speed != scroll_speed) || !scroll_enable)) { event_remove_timeout(dev->scroll_timeout); dev->scroll_timeout = NULL; } - if (scrollspeed) { - struct timeval tv = { .tv_usec = scrollspeed }; + dev->scroll_speed = scroll_speed; + dev->scroll_pos = 0; + + if ((dev->scroll_timeout == NULL) && scroll_enable && (scroll_speed > 0)) { + struct timeval tv = { .tv_usec = 1000 * dev->scroll_speed }; dev->scroll_timeout = event_add_timeout(&tv, lcd_scroll_timeout_cb, dev); } @@ -288,9 +357,8 @@ int lcd_setlines(struct lcddev *dev, int scrollspeed, const char *line1, const c } struct lcddev * lcd_init(const char *devicename, - int backlight_time, - int (*button_cb)(struct lcddev *dev, int button, void *privdata), - void *privdata) + int (*event_callback)(struct lcddev *dev, int button, void *privdata), + void *event_privdata) { struct lcddev *dev = malloc(sizeof(struct lcddev)); if (dev == NULL) { @@ -305,9 +373,8 @@ struct lcddev * lcd_init(const char *devicename, return NULL; } - dev->backlight_time = backlight_time; - dev->button_cb = button_cb; - dev->privdata = privdata; + dev->event_callback = event_callback; + dev->event_privdata = event_privdata; dev->read_event = event_add_readfd(NULL, dev->fd, lcd_read_cb, dev); diff --git a/lcd.h b/lcd.h index d24f617..ebc0c51 100644 --- a/lcd.h +++ b/lcd.h @@ -1,20 +1,23 @@ #ifndef _LCD_H_ #define _LCD_H_ -#define LCD_BUTTON0 0x00 -#define LCD_BUTTON1 0x01 -#define LCD_BUTTON2 0x02 +#define LCD_EVENT_INIT 0x00 +#define LCD_EVENT_BUTTON1 0x01 +#define LCD_EVENT_BUTTON2 0x02 +#define LCD_EVENT_BACKLIGHT 0x04 struct lcddev; /* private data */ struct lcddev * lcd_init(const char *device, - int backlight_timeout, - int (*button_callback)(struct lcddev *dev, int button, void *privdata), - void *privdata); + int (*event_callback)(struct lcddev *dev, int event, void *privdata), + void *event_privdata); void lcd_close(struct lcddev *dev); void lcd_reset(struct lcddev *dev); +#define LCD_BACKLIGHT_OFF (0) +#define LCD_BACKLIGHT_ON (-1) + int lcd_trigger_backlight(struct lcddev *dev, int timeout); int lcd_setlines(struct lcddev *dev, int scrollspeed, const char *line1, const char *line2); diff --git a/qnaplcd.c b/qnaplcd.c index b9039b4..90d05d1 100644 --- a/qnaplcd.c +++ b/qnaplcd.c @@ -54,15 +54,19 @@ static int page; static int button_callback(struct lcddev *dev, int button, void *privdata) { - if (button == LCD_BUTTON2) + if (button == LCD_EVENT_BUTTON2) { page = (page < PAGE_MAX) ? page +1 : 0; - else if (button == LCD_BUTTON1) + } else if (button == LCD_EVENT_BUTTON1) { page = (page > 0) ? page -1 : PAGE_MAX; + } else if (button == LCD_EVENT_BACKLIGHT) { + return 0; + } + switch (page) { case 0: - lcd_setlines(dev, 0, "Debian 5.0 Lenny", "2.6.34-kirkwood"); + lcd_setlines(dev, 500, "Debian GNU/Linux 5.0", "Linux 2.6.32.27-486 i586"); break; case 1: lcd_setlines(dev, 0, "Hostname:", "storenix.lan"); @@ -87,7 +91,8 @@ static int button_callback(struct lcddev *dev, int button, void *privdata) break; } - return 0; + lcd_trigger_backlight(dev, LCD_TIMEOUT); + return 1; } static int restart_var; @@ -181,7 +186,7 @@ int main(int argc, char *argv[]) log_print(LOG_EVERYTIME, "qnaplcd started (pid:%d)", getpid()); while (1) { - struct lcddev *dev = lcd_init(LCD_DEVICE, LCD_TIMEOUT, &button_callback, NULL); + struct lcddev *dev = lcd_init(LCD_DEVICE, &button_callback, NULL); if (dev == NULL) break;