700 lines
17 KiB
C
700 lines
17 KiB
C
/***************************************************************************
|
|
* Copyright (C) 05/2011 by Olaf Rempel *
|
|
* razzor@kopf-tisch.de *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
***************************************************************************/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <termios.h>
|
|
|
|
#include "event.h"
|
|
#include "lcd.h"
|
|
#include "list.h"
|
|
#include "logging.h"
|
|
|
|
#define _LCD_DEBUG 0
|
|
#define _LCD_DUMMY 1
|
|
|
|
#define LCD_SCROLL_SPEED 750 /* 750ms */
|
|
#define LCD_RESET_TIMEOUT 250 /* 250ms */
|
|
#define LCD_RESET_RETRY_TIMEOUT 10000 /* 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
|
|
#define A125_CMD_BACKLIGHT { 0x4D, 0x5E, 0x00 } // [2] is on/off
|
|
#define A125_CMD_RESET { 0x4D, 0xFF }
|
|
|
|
#define A125_EVENT_ID { 0x53, 0x01 } // never seen
|
|
#define A125_EVENT_BUTTON1 { 0x53, 0x05, 0x00, 0x01 }
|
|
#define A125_EVENT_BUTTON2 { 0x53, 0x05, 0x00, 0x02 }
|
|
#define A125_EVENT_VERSION { 0x53, 0x08 } // never seen
|
|
#define A125_EVENT_ACTINFO { 0x53, 0xAA }
|
|
#define A125_EVENT_INVALID { 0x53, 0xFB } // never seen
|
|
|
|
struct lcdpage {
|
|
struct list_head list;
|
|
int priority;
|
|
|
|
int (*callback)(struct lcddev *dev, int event, void *privdata);
|
|
void *privdata;
|
|
};
|
|
|
|
enum lcdstate {
|
|
LCD_STATE_NOT_INITIALIZED = 0x00,
|
|
LCD_STATE_INITIALIZING,
|
|
LCD_STATE_INITIALIZING_FAILED,
|
|
LCD_STATE_READY,
|
|
};
|
|
|
|
struct lcddev {
|
|
int fd;
|
|
#if (_LCD_DUMMY)
|
|
struct event_fd *fakedevice_event;
|
|
#endif /* (_LCD_DUMMY) */
|
|
struct termios oldtio;
|
|
|
|
enum lcdstate state;
|
|
|
|
int backlight_enabled;
|
|
int backlight_timeout_ms;
|
|
|
|
struct list_head page_list;
|
|
struct lcdpage *current_page;
|
|
|
|
const char *line_data[2];
|
|
int line_length[2];
|
|
int scroll_pos;
|
|
|
|
int update_ms;
|
|
|
|
struct event_fd *read_event;
|
|
struct event_timeout *reset_timeout;
|
|
struct event_timeout *backlight_timeout;
|
|
struct event_timeout *scroll_timeout;
|
|
struct event_timeout *update_timeout;
|
|
};
|
|
|
|
static void lcd_pagecallback(struct lcddev *dev, int event);
|
|
|
|
void lcd_close(struct lcddev *dev)
|
|
{
|
|
if (dev->current_page) {
|
|
dev->current_page->callback(dev, LCDPAGE_EVENT_EXIT, dev->current_page->privdata);
|
|
dev->current_page = NULL;
|
|
}
|
|
|
|
struct lcdpage *search, *tmp;
|
|
list_for_each_entry_safe(search, tmp, &dev->page_list, list) {
|
|
free(search);
|
|
}
|
|
|
|
if (dev->reset_timeout) {
|
|
event_remove_timeout(dev->reset_timeout);
|
|
dev->reset_timeout = NULL;
|
|
}
|
|
|
|
if (dev->backlight_timeout) {
|
|
event_remove_timeout(dev->backlight_timeout);
|
|
dev->backlight_timeout = NULL;
|
|
}
|
|
|
|
if (dev->update_timeout) {
|
|
event_remove_timeout(dev->update_timeout);
|
|
dev->update_timeout = NULL;
|
|
}
|
|
|
|
if (dev->scroll_timeout) {
|
|
event_remove_timeout(dev->scroll_timeout);
|
|
dev->scroll_timeout = NULL;
|
|
}
|
|
|
|
if (dev->read_event) {
|
|
event_remove_fd(dev->read_event);
|
|
dev->read_event = NULL;
|
|
}
|
|
|
|
#if (_LCD_DUMMY)
|
|
if (dev->fakedevice_event != NULL) {
|
|
int fd = event_get_fd(dev->fakedevice_event);
|
|
event_remove_fd(dev->fakedevice_event);
|
|
dev->fakedevice_event = NULL;
|
|
close(fd);
|
|
|
|
} else
|
|
#endif /* (_LCD_DUMMY) */
|
|
{
|
|
tcsetattr(dev->fd, TCSANOW, &dev->oldtio);
|
|
}
|
|
|
|
close(dev->fd);
|
|
free(dev);
|
|
}
|
|
|
|
static int lcd_realdevice_open(struct lcddev *dev, const char *device)
|
|
{
|
|
dev->fd = open(device, O_RDWR | O_NOCTTY);
|
|
if (dev->fd < 0) {
|
|
log_print(LOG_ERROR, "%s(): failed to open '%s'", __FUNCTION__, device);
|
|
return -1;
|
|
}
|
|
|
|
if (fcntl(dev->fd, F_SETFD, FD_CLOEXEC) < 0) {
|
|
log_print(LOG_ERROR, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
|
|
tcgetattr(dev->fd, &dev->oldtio);
|
|
|
|
struct termios newtio;
|
|
memset(&newtio, 0, sizeof(newtio));
|
|
newtio.c_iflag |= IGNBRK;
|
|
newtio.c_lflag &= ~(ISIG | ICANON | ECHO);
|
|
newtio.c_cflag = B1200 | CS8 | CLOCAL | CREAD;
|
|
newtio.c_cc[VMIN] = 1;
|
|
newtio.c_cc[VTIME] = 0;
|
|
cfsetospeed(&newtio, B1200);
|
|
cfsetispeed(&newtio, B1200);
|
|
|
|
int err = tcsetattr(dev->fd, TCSAFLUSH, &newtio);
|
|
if (err < 0) {
|
|
log_print(LOG_ERROR, "%s(): failed to set termios", __FUNCTION__);
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if (_LCD_DUMMY)
|
|
static int lcd_fakedevice_reply(int fd, void *privdata)
|
|
{
|
|
struct lcddev *dev = (struct lcddev *)privdata;
|
|
char buf[32];
|
|
|
|
if (read(fd, buf, sizeof(buf)) <= 0) {
|
|
dev->fakedevice_event = NULL;
|
|
return -1;
|
|
}
|
|
|
|
char reset_expect[] = A125_CMD_RESET;
|
|
if (memcmp(buf, reset_expect, sizeof(reset_expect)) == 0) {
|
|
char actinfo_cmd[] = A125_EVENT_ACTINFO;
|
|
write(fd, actinfo_cmd, sizeof(actinfo_cmd));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lcd_fakedevice_open(struct lcddev *dev)
|
|
{
|
|
int fd[2];
|
|
|
|
if (socketpair(AF_LOCAL, SOCK_STREAM, 0 , fd) < 0) {
|
|
log_print(LOG_ERROR, "%s(): socketpair() failed", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0) {
|
|
log_print(LOG_ERROR, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
|
|
close(fd[0]);
|
|
close(fd[1]);
|
|
return -1;
|
|
}
|
|
|
|
if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0) {
|
|
log_print(LOG_ERROR, "%s(): fcntl(FD_CLOEXEC)", __FUNCTION__);
|
|
close(fd[0]);
|
|
close(fd[1]);
|
|
return -1;
|
|
}
|
|
|
|
dev->fd = fd[0];
|
|
dev->fakedevice_event = event_add_readfd(NULL, fd[1], lcd_fakedevice_reply, dev);
|
|
return 0;
|
|
}
|
|
#endif /* (_LCD_DUMMY) */
|
|
|
|
#if (_LCD_DEBUG > 1)
|
|
static void lcd_dump(const char *prefix, int len, int size, const char *data)
|
|
{
|
|
int i;
|
|
int pos = 0;
|
|
char buf[256];
|
|
|
|
for (i = 0; i < len; i++) {
|
|
pos += snprintf(buf, sizeof(buf) - pos, "0x%X ", (unsigned char)data[i]);
|
|
}
|
|
|
|
log_print(LOG_DEBUG, "%s:[%d/%d]: %s", prefix, len, size, buf);
|
|
}
|
|
#endif /* (_LCD_DEBUG > 1) */
|
|
|
|
static int lcd_read(struct lcddev *dev, const char *buf, int len)
|
|
{
|
|
int retval = 0, cnt = 0;
|
|
while (cnt < len) {
|
|
retval = read(dev->fd, (char *)buf + cnt, len - cnt);
|
|
if (retval <= 0)
|
|
break;
|
|
|
|
cnt += retval;
|
|
}
|
|
#if (_LCD_DEBUG > 1)
|
|
lcd_dump(__FUNCTION__, cnt, len, buf);
|
|
#endif /* (_LCD_DEBUG > 1) */
|
|
return (cnt != 0) ? cnt : retval;
|
|
}
|
|
|
|
static int lcd_write(struct lcddev *dev, char *buf, int len)
|
|
{
|
|
int retval = write(dev->fd, buf, len);
|
|
|
|
#if (_LCD_DEBUG > 1)
|
|
lcd_dump(__FUNCTION__, retval, len, buf);
|
|
#endif /* (_LCD_DEBUG > 1) */
|
|
return retval;
|
|
}
|
|
|
|
static void lcd_reset(struct lcddev *dev);
|
|
|
|
static int lcd_reset_retry_timeout_cb(int timerid, void *privdata)
|
|
{
|
|
struct lcddev *dev = (struct lcddev *)privdata;
|
|
dev->reset_timeout = NULL;
|
|
|
|
lcd_reset(dev);
|
|
return -1; /* singleshot */
|
|
}
|
|
|
|
static int lcd_reset_timeout_cb(int timerid, void *privdata)
|
|
{
|
|
struct lcddev *dev = (struct lcddev *)privdata;
|
|
|
|
log_print(LOG_ERROR, "failed to initalize LCD");
|
|
dev->state = LCD_STATE_INITIALIZING_FAILED;
|
|
|
|
dev->reset_timeout = event_add_timeout_ms(LCD_RESET_RETRY_TIMEOUT, lcd_reset_retry_timeout_cb, 0, dev);
|
|
|
|
return -1; /* singleshot */
|
|
}
|
|
|
|
static void lcd_reset(struct lcddev *dev)
|
|
{
|
|
#if (_LCD_DEBUG > 0)
|
|
log_print(LOG_DEBUG, "%s()", __FUNCTION__);
|
|
#endif /* (_LCD_DEBUG > 0) */
|
|
|
|
char cmd[] = A125_CMD_RESET;
|
|
lcd_write(dev, cmd, sizeof(cmd));
|
|
|
|
/* force next backlight command */
|
|
dev->backlight_enabled = -1;
|
|
|
|
dev->state = LCD_STATE_INITIALIZING;
|
|
|
|
dev->reset_timeout = event_add_timeout_ms(LCD_RESET_TIMEOUT, lcd_reset_timeout_cb, 0, dev);
|
|
}
|
|
|
|
static int lcd_backlight(struct lcddev *dev, int enable)
|
|
{
|
|
if (dev->state != LCD_STATE_READY)
|
|
return -1;
|
|
|
|
#if (_LCD_DEBUG > 0)
|
|
log_print(LOG_DEBUG, "%s(%d)", __FUNCTION__, enable);
|
|
#endif /* (_LCD_DEBUG > 0) */
|
|
|
|
if (dev->backlight_enabled != enable) {
|
|
char cmd[] = A125_CMD_BACKLIGHT;
|
|
|
|
cmd[2] = (enable) ? 0x01 : 0x00;
|
|
lcd_write(dev, cmd, sizeof(cmd));
|
|
|
|
dev->backlight_enabled = enable;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lcd_backlight_timeout_cb(int timerid, void *privdata)
|
|
{
|
|
struct lcddev *dev = (struct lcddev *)privdata;
|
|
dev->backlight_timeout = NULL;
|
|
|
|
lcd_set_backlight(dev, 0);
|
|
|
|
return -1; /* singleshot */
|
|
}
|
|
|
|
int lcd_set_backlight(struct lcddev *dev, int enable)
|
|
{
|
|
if (dev->backlight_timeout != NULL) {
|
|
event_remove_timeout(dev->backlight_timeout);
|
|
dev->backlight_timeout = NULL;
|
|
}
|
|
|
|
if (!enable) {
|
|
lcd_pagecallback(dev, LCDPAGE_EVENT_BACKLIGHT);
|
|
|
|
/* callback re-enabled backlight */
|
|
if (dev->backlight_timeout != NULL) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int retval = lcd_backlight(dev, enable);
|
|
|
|
if (enable) {
|
|
/* start backlight timeout */
|
|
dev->backlight_timeout = event_add_timeout_ms(dev->backlight_timeout_ms, lcd_backlight_timeout_cb, 0, dev);
|
|
|
|
} else {
|
|
/* disable updates (display is not visible) */
|
|
if (dev->update_timeout != NULL) {
|
|
event_remove_timeout(dev->update_timeout);
|
|
dev->update_timeout = NULL;
|
|
}
|
|
|
|
/* disable scrolling (display is not visible) */
|
|
if (dev->scroll_timeout != NULL) {
|
|
event_remove_timeout(dev->scroll_timeout);
|
|
dev->scroll_timeout = NULL;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int lcd_update_timeout_cb(int timerid, void *privdata)
|
|
{
|
|
struct lcddev *dev = (struct lcddev *)privdata;
|
|
|
|
dev->update_timeout = NULL;
|
|
lcd_pagecallback(dev, LCDPAGE_EVENT_UPDATE);
|
|
|
|
return -1; /* singleshot */
|
|
}
|
|
|
|
static void lcd_update_start(struct lcddev *dev, int update_ms)
|
|
{
|
|
dev->update_ms = update_ms;
|
|
|
|
if (dev->update_timeout != NULL) {
|
|
event_remove_timeout(dev->update_timeout);
|
|
dev->update_timeout = NULL;
|
|
}
|
|
|
|
if (update_ms > 0) {
|
|
dev->update_timeout = event_add_timeout_ms(update_ms, lcd_update_timeout_cb, 0, dev);
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
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 */
|
|
lcd_pagecallback(dev, LCDPAGE_EVENT_ENTER);
|
|
}
|
|
|
|
} 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) {
|
|
lcd_pagecallback(dev, LCDPAGE_EVENT_BUTTON1);
|
|
|
|
} else if (memcmp(buf, expect2, sizeof(buf)) == 0) {
|
|
lcd_pagecallback(dev, LCDPAGE_EVENT_BUTTON2);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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 +1] = A125_CMD_SETLINE;
|
|
cmd[2] = line;
|
|
|
|
memset(cmd +4, ' ', 16);
|
|
memcpy(cmd +4, buf, (len > 16) ? 16 : len);
|
|
cmd[20] = '\0';
|
|
|
|
#if (_LCD_DEBUG > 0)
|
|
log_print(LOG_DEBUG, "%s(%d, '%-16s')", __FUNCTION__, line, cmd +4);
|
|
#endif /* (_LCD_DEBUG > 0) */
|
|
|
|
lcd_write(dev, cmd, 20);
|
|
return 0;
|
|
}
|
|
|
|
static int lcd_scroll_timeout_cb(int timerid, void *privdata)
|
|
{
|
|
struct lcddev *dev = (struct lcddev *)privdata;
|
|
int i, reset_pos = 0;
|
|
|
|
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;
|
|
|
|
/* periodic */
|
|
return 0;
|
|
}
|
|
|
|
static void lcd_scroll_start(struct lcddev *dev)
|
|
{
|
|
if (dev->scroll_timeout != NULL) {
|
|
event_remove_timeout(dev->scroll_timeout);
|
|
dev->scroll_timeout = NULL;
|
|
}
|
|
|
|
if ((dev->line_length[0] > 16) || (dev->line_length[1] > 16)) {
|
|
dev->scroll_timeout = event_add_timeout_ms(LCD_SCROLL_SPEED, lcd_scroll_timeout_cb, 0, dev);
|
|
}
|
|
}
|
|
|
|
int lcd_setlines(struct lcddev *dev, const char *line1, const char *line2)
|
|
{
|
|
int i;
|
|
int line_length[2] = { 0, 0 };
|
|
const char *line[2] = { line1, line2 };
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
if (line[i] != NULL) {
|
|
line_length[i] = strlen(line[i]);
|
|
|
|
if ((line_length[i] == dev->line_length[i]) && (dev->line_data[i] != NULL)) {
|
|
if (memcmp(line[i], dev->line_data[i], line_length[i]) == 0) {
|
|
/* same data, no update needed */
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dev->line_data[i] != NULL) {
|
|
free((void *)dev->line_data[i]);
|
|
dev->line_data[i] = NULL;
|
|
}
|
|
|
|
if (line[i] != NULL) {
|
|
dev->line_data[i] = strdup(line[i]);
|
|
}
|
|
dev->line_length[i] = line_length[i];
|
|
|
|
if (dev->backlight_enabled) {
|
|
lcd_setline(dev, i, dev->line_length[i], dev->line_data[i]);
|
|
|
|
dev->scroll_pos = 0;
|
|
lcd_scroll_start(dev);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void lcd_pagecallback(struct lcddev *dev, int event)
|
|
{
|
|
if (dev->state != LCD_STATE_READY) {
|
|
return;
|
|
}
|
|
|
|
if (dev->current_page == NULL) {
|
|
if (list_empty(&dev->page_list)) {
|
|
return;
|
|
}
|
|
|
|
dev->current_page = list_entry(dev->page_list.next, struct lcdpage, list);
|
|
}
|
|
|
|
if ((dev->backlight_enabled == 0x00) && ((event == LCDPAGE_EVENT_BUTTON1) || (event == LCDPAGE_EVENT_BUTTON2))) {
|
|
lcd_set_backlight(dev, 1);
|
|
|
|
event = LCDPAGE_EVENT_UPDATE;
|
|
|
|
/* restart scrolling if needed */
|
|
lcd_scroll_start(dev);
|
|
}
|
|
|
|
int next;
|
|
do {
|
|
#if (_LCD_DEBUG > 0)
|
|
log_print(LOG_DEBUG, "%s: cb(%p, 0x%x)", __FUNCTION__, dev->current_page, event);
|
|
#endif
|
|
int retval = dev->current_page->callback(dev, event, dev->current_page->privdata);
|
|
#if (_LCD_DEBUG > 0)
|
|
log_print(LOG_DEBUG, "%s: cb(%p, 0x%x) => 0x%x", __FUNCTION__, dev->current_page, event, retval);
|
|
#endif
|
|
|
|
next = (retval == LCDPAGE_COMMAND_NEXT);
|
|
if (next) {
|
|
struct lcdpage *page = dev->current_page;
|
|
|
|
if (page->list.next != &dev->page_list) {
|
|
page = list_entry(page->list.next, struct lcdpage, list);
|
|
} else {
|
|
page = list_entry(page->list.next->next, struct lcdpage, list);
|
|
}
|
|
|
|
/* no other page ready */
|
|
if (page == dev->current_page) {
|
|
break;
|
|
}
|
|
|
|
/* remove update interval for next page */
|
|
if (dev->update_timeout != NULL) {
|
|
event_remove_timeout(dev->update_timeout);
|
|
dev->update_timeout = NULL;
|
|
}
|
|
|
|
/* remove scroll interval for next page */
|
|
if (dev->scroll_timeout != NULL) {
|
|
event_remove_timeout(dev->scroll_timeout);
|
|
dev->scroll_timeout = NULL;
|
|
}
|
|
|
|
dev->current_page->callback(dev, LCDPAGE_EVENT_EXIT, dev->current_page->privdata);
|
|
dev->current_page = page;
|
|
event = LCDPAGE_EVENT_ENTER;
|
|
|
|
/* retval is update interval */
|
|
} else if ((event != LCDPAGE_EVENT_BACKLIGHT) && (event != LCDPAGE_EVENT_EXIT)) {
|
|
lcd_update_start(dev, retval);
|
|
}
|
|
} while (next);
|
|
}
|
|
|
|
int lcd_addpage_cb(struct lcddev *dev,
|
|
int priority,
|
|
int (*event_callback)(struct lcddev *dev, int event, void *privdata),
|
|
void *event_privdata)
|
|
{
|
|
struct lcdpage *page = malloc(sizeof(struct lcdpage));
|
|
if (page == NULL) {
|
|
log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
page->priority = priority;
|
|
page->callback = event_callback;
|
|
page->privdata = event_privdata;
|
|
|
|
int inserted = 0;
|
|
struct lcdpage *search;
|
|
list_for_each_entry(search, &dev->page_list, list) {
|
|
if (page->priority > search->priority) {
|
|
list_add_tail(&page->list, &search->list);
|
|
inserted = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!inserted) {
|
|
list_add_tail(&page->list, &dev->page_list);
|
|
}
|
|
|
|
if (dev->current_page == NULL) {
|
|
lcd_pagecallback(dev, LCDPAGE_EVENT_ENTER);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct lcddev * lcd_open(const char *devicename, int backlight_timeout)
|
|
{
|
|
struct lcddev *dev = malloc(sizeof(struct lcddev));
|
|
if (dev == NULL) {
|
|
log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
memset(dev, 0, sizeof(struct lcddev));
|
|
|
|
INIT_LIST_HEAD(&dev->page_list);
|
|
|
|
int retval;
|
|
#if (_LCD_DUMMY)
|
|
if (strncmp(devicename, "dummy", 5) == 0) {
|
|
retval = lcd_fakedevice_open(dev);
|
|
} else
|
|
#endif /* (_LCD_DUMMY) */
|
|
{
|
|
retval = lcd_realdevice_open(dev, devicename);
|
|
}
|
|
|
|
if (retval < 0) {
|
|
free(dev);
|
|
return NULL;
|
|
}
|
|
|
|
dev->read_event = event_add_readfd(NULL, dev->fd, lcd_read_cb, dev);
|
|
dev->backlight_timeout_ms = backlight_timeout * 1000;
|
|
|
|
lcd_reset(dev);
|
|
return dev;
|
|
}
|