From f1fa53fab5033cbe218b92f895d928efd889f116 Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Mon, 18 Apr 2011 21:59:49 +0200 Subject: [PATCH] non-blocking reset --- lcd.c | 221 +++++++++++++++++++++++++++++++++++++----------------- lcd.h | 5 +- qnaplcd.c | 24 ++---- 3 files changed, 164 insertions(+), 86 deletions(-) diff --git a/lcd.c b/lcd.c index b662d63..1f79423 100644 --- a/lcd.c +++ b/lcd.c @@ -14,6 +14,9 @@ #define _LCD_DEBUG 1 +#define LCD_RESET_TIMEOUT_US 250000 /* 250ms */ +#define LCD_RESET_RETRY_TIMEOUT 10 /* 10s */ + #define A125_CMD_GETBUTTON { 0x4D, 0x06 } // not tried #define A125_CMD_SETLINE { 0x4D, 0x0C, 0x00, 0x10 } // [2] is line, append 16 chars #define A125_CMD_CLEAR { 0x4D, 0x0D } // works, but slow @@ -27,17 +30,30 @@ #define A125_EVENT_ACTINFO { 0x53, 0xAA } #define A125_EVENT_INVALID { 0x53, 0xFB } // never seen +enum lcdstate { + LCD_STATE_NOT_INITIALIZED = 0x00, + LCD_STATE_INITIALIZING, + LCD_STATE_INITIALIZING_FAILED, + LCD_STATE_READY, +}; + struct lcddev { int fd; - char device[32]; struct termios oldtio; - int backlight_timeout; + int backlight_time; + enum lcdstate state; + int (*button_cb)(struct lcddev *dev, int button, void *privdata); void *privdata; + const char *line_data[2]; + int scrollpos; + struct event_fd *read_event; - struct event_timeout *backlight_event; + struct event_timeout *reset_timeout; + struct event_timeout *backlight_timeout; + struct event_timeout *scroll_timeout; }; void lcd_close(struct lcddev *dev) @@ -48,15 +64,12 @@ void lcd_close(struct lcddev *dev) static int lcd_open(struct lcddev *dev, const char *device) { - int fd = open(device, O_RDWR); - if (fd < 0) { + dev->fd = open(device, O_RDWR); + if (dev->fd < 0) { log_print(LOG_ERROR, "failed to open '%s'", device); return -1; } - strncpy(dev->device, device, sizeof(dev->device)); - dev->fd = fd; - tcgetattr(dev->fd, &dev->oldtio); struct termios newtio; @@ -107,35 +120,136 @@ static int lcd_write(struct lcddev *dev, char *buf, int len) 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"); #endif return retval; } -static int lcd_reset(struct lcddev *dev) +static int lcd_reset_retry_timeout_cb(void *privdata) +{ + struct lcddev *dev = (struct lcddev *)privdata; + + lcd_reset(dev); + return -1; /* singleshot */ +} + +static int lcd_reset_timeout_cb(void *privdata) +{ + struct lcddev *dev = (struct lcddev *)privdata; + + log_print(LOG_ERROR, "failed to initalize LCD"); + dev->state = LCD_STATE_INITIALIZING_FAILED; + + struct timeval tv = { .tv_sec = LCD_RESET_RETRY_TIMEOUT }; + dev->reset_timeout = event_add_timeout(&tv, lcd_reset_retry_timeout_cb, dev); + + return -1; /* singleshot */ +} + +void lcd_reset(struct lcddev *dev) { char cmd[] = A125_CMD_RESET; lcd_write(dev, cmd, sizeof(cmd)); - char event[2], expect[] = A125_EVENT_ACTINFO; - if (lcd_read(dev, event, sizeof(event)) != sizeof(event)) + 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); +} + +static int lcd_backlight(struct lcddev *dev, int mode) +{ + if (dev->state != LCD_STATE_READY) return -1; - return !memcmp(event, expect, sizeof(event)); -} - -static void lcd_backlight(struct lcddev *dev, int mode) -{ char cmd[] = A125_CMD_BACKLIGHT; - cmd[2] = (mode) ? 0x01 : 0x00; lcd_write(dev, cmd, sizeof(cmd)); + return 0; } -int lcd_setline(struct lcddev *dev, int line, const char *buf) +static int lcd_backlight_timeout_cb(void *privdata) { + struct lcddev *dev = (struct lcddev *)privdata; + dev->backlight_timeout = NULL; + + lcd_backlight(dev, 0); + return -1; /* singleshot */ +} + +int lcd_trigger_backlight(struct lcddev *dev, int timeout) +{ + if (dev->backlight_timeout != NULL) { + event_remove_timeout(dev->backlight_timeout); + dev->backlight_timeout = NULL; + } + + int retval = lcd_backlight(dev, 1); + + struct timeval tv = { .tv_sec = timeout }; + dev->backlight_timeout = event_add_timeout(&tv, lcd_backlight_timeout_cb, dev); + + return retval; +} + +static int lcd_read_cb(int fd, void *privdata) +{ + struct lcddev *dev = (struct lcddev *)privdata; + + char buf[4]; + 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; + + if (len != sizeof(expect)) + return 0; + + if (memcmp(buf, expect, sizeof(expect)) == 0) { + event_remove_timeout(dev->reset_timeout); + dev->reset_timeout = NULL; + + dev->state = LCD_STATE_READY; + + /* trigger application to set data */ + retval = dev->button_cb(dev, LCD_BUTTON0, dev->privdata); + } + + } else if (dev->state == LCD_STATE_READY) { + char expect1[] = A125_EVENT_BUTTON1; + char expect2[] = A125_EVENT_BUTTON2; + + if (len != sizeof(expect1) && len != sizeof(expect2)) + return 0; + + if (memcmp(buf, expect1, sizeof(buf)) == 0) { + retval = dev->button_cb(dev, LCD_BUTTON1, dev->privdata); + + } else if (memcmp(buf, expect2, sizeof(buf)) == 0) { + retval = dev->button_cb(dev, LCD_BUTTON2, dev->privdata); + } + } + + if (retval) + lcd_trigger_backlight(dev, dev->backlight_time); + + return 0; +} + +static int lcd_setline(struct lcddev *dev, int line, const char *buf) +{ + if (dev->state != LCD_STATE_READY) + return -1; + char cmd[20] = A125_CMD_SETLINE; - cmd[2] = (line) ? 0x01 : 0x00; + cmd[2] = line; memset(cmd +4, ' ', 16); int len = strlen(buf); @@ -145,59 +259,36 @@ int lcd_setline(struct lcddev *dev, int line, const char *buf) return 0; } -static int lcd_backlight_timeout_cb(void *privdata) +static int lcd_scroll_timeout_cb(void *privdata) { - struct lcddev *dev = (struct lcddev *)privdata; - dev->backlight_event = NULL; + // TODO: scrolling - lcd_backlight(dev, 0); - return -1; /* singleshot */ + return 0; /* periodic */ } -static void lcd_trigger_backlight(struct lcddev *dev) +int lcd_setlines(struct lcddev *dev, int scrollspeed, const char *line1, const char *line2) { - if (dev->backlight_event != NULL) { - event_remove_timeout(dev->backlight_event); - dev->backlight_event = NULL; + dev->line_data[0] = line1; + lcd_setline(dev, 0, line1); - } else { - lcd_backlight(dev, 1); + dev->line_data[1] = line2; + lcd_setline(dev, 1, line2); + + if (dev->scroll_timeout) { + event_remove_timeout(dev->scroll_timeout); + dev->scroll_timeout = NULL; } - struct timeval tv = { .tv_sec = dev->backlight_timeout }; - dev->backlight_event = event_add_timeout(&tv, lcd_backlight_timeout_cb, dev); -} - -static int lcd_read_cb(int fd, void *privdata) -{ - struct lcddev *dev = (struct lcddev *)privdata; - char buf[4]; - - if (lcd_read(dev, buf, sizeof(buf)) != sizeof(buf)) { - log_print(LOG_WARN, "lcd_read_cb(): invalid read"); - return 0; - } - - int retval = 0; - char expect1[] = A125_EVENT_BUTTON1; - char expect2[] = A125_EVENT_BUTTON2; - - if (memcmp(buf, expect1, sizeof(buf)) == 0) { - retval = dev->button_cb(dev, LCD_BUTTON1, dev->privdata); - - } else if (memcmp(buf, expect2, sizeof(buf)) == 0) { - retval = dev->button_cb(dev, LCD_BUTTON2, dev->privdata); - } - - if (retval) { - lcd_trigger_backlight(dev); + if (scrollspeed) { + struct timeval tv = { .tv_usec = scrollspeed }; + dev->scroll_timeout = event_add_timeout(&tv, lcd_scroll_timeout_cb, dev); } return 0; } struct lcddev * lcd_init(const char *devicename, - int backlight_timeout, + int backlight_time, int (*button_cb)(struct lcddev *dev, int button, void *privdata), void *privdata) { @@ -214,20 +305,12 @@ struct lcddev * lcd_init(const char *devicename, return NULL; } - if (lcd_reset(dev) < 0) { - log_print(LOG_ERROR, "lcd_init(): could not reset LCD"); - lcd_close(dev); - free(dev); - return NULL; - } - - dev->backlight_timeout = backlight_timeout; - lcd_trigger_backlight(dev); - + dev->backlight_time = backlight_time; dev->button_cb = button_cb; dev->privdata = privdata; - button_cb(dev, LCD_BUTTON0, dev->privdata); dev->read_event = event_add_readfd(NULL, dev->fd, lcd_read_cb, dev); + + lcd_reset(dev); return dev; } diff --git a/lcd.h b/lcd.h index ea4a635..d24f617 100644 --- a/lcd.h +++ b/lcd.h @@ -13,6 +13,9 @@ struct lcddev * lcd_init(const char *device, void *privdata); void lcd_close(struct lcddev *dev); -int lcd_setline(struct lcddev *dev, int line, const char *text); +void lcd_reset(struct lcddev *dev); + +int lcd_trigger_backlight(struct lcddev *dev, int timeout); +int lcd_setlines(struct lcddev *dev, int scrollspeed, const char *line1, const char *line2); #endif /* _LCD_H_ */ diff --git a/qnaplcd.c b/qnaplcd.c index 4e9d29e..b9039b4 100644 --- a/qnaplcd.c +++ b/qnaplcd.c @@ -62,36 +62,28 @@ static int button_callback(struct lcddev *dev, int button, void *privdata) switch (page) { case 0: - lcd_setline(dev, 0, "Debian 5.0 Lenny"); - lcd_setline(dev, 1, "2.6.34-kirkwood"); + lcd_setlines(dev, 0, "Debian 5.0 Lenny", "2.6.34-kirkwood"); break; case 1: - lcd_setline(dev, 0, "Hostname:"); - lcd_setline(dev, 1, "storenix.lan"); + lcd_setlines(dev, 0, "Hostname:", "storenix.lan"); break; case 2: - lcd_setline(dev, 0, "Address(br0):"); - lcd_setline(dev, 1, "10.10.250.135"); + lcd_setlines(dev, 0, "Address(br0):", "10.10.250.135"); break; case 3: - lcd_setline(dev, 0, "Netmask(br0):"); - lcd_setline(dev, 1, "255.255.0.0"); + lcd_setlines(dev, 0, "Netmask(br0):", "255.255.0.0"); break; case 4: - lcd_setline(dev, 0, "Gateway(br0):"); - lcd_setline(dev, 1, "10.10.250.250"); + lcd_setlines(dev, 0, "Gateway(br0):", "10.10.250.250"); break; case 5: - lcd_setline(dev, 0, "LoadAVG:"); - lcd_setline(dev, 1, "x.xx x.xx x.xx"); + lcd_setlines(dev, 0, "LoadAVG:", "x.xx x.xx x.xx"); break; case 6: - lcd_setline(dev, 0, "Uptime:"); - lcd_setline(dev, 1, " XXXd XX:XX:XX"); + lcd_setlines(dev, 0, "Uptime:", " XXXd XX:XX:XX"); break; case 7: - lcd_setline(dev, 0, "Time: XX:XX:XX"); - lcd_setline(dev, 1, "Date: XX-XX-XXXX"); + lcd_setlines(dev, 0, "Time: XX:XX:XX", "Date: XX-XX-XXXX"); break; }