non-blocking reset
This commit is contained in:
parent
2db5472a8d
commit
f1fa53fab5
221
lcd.c
221
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;
|
||||
}
|
||||
|
5
lcd.h
5
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_ */
|
||||
|
24
qnaplcd.c
24
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user