diff --git a/lcd.c b/lcd.c index d60903b..d02616b 100644 --- a/lcd.c +++ b/lcd.c @@ -30,11 +30,13 @@ #include "event.h" #include "lcd.h" +#include "list.h" #include "logging.h" #define _LCD_DEBUG 1 #define _LCD_DUMMY 1 +#define LCD_SCROLL_SPEED 750 /* 750ms */ #define LCD_RESET_TIMEOUT 250 /* 250ms */ #define LCD_RESET_RETRY_TIMEOUT 10000 /* 10s */ @@ -51,6 +53,14 @@ #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, @@ -67,14 +77,14 @@ struct lcddev { enum lcdstate state; - int backlight_state; + int backlight_enabled; + int backlight_timeout_ms; - int (*event_callback)(struct lcddev *dev, int event, void *privdata); - void *event_privdata; + struct list_head page_list; + struct lcdpage *current_page; const char *line_data[2]; int line_length[2]; - int scroll_speed; int scroll_pos; struct event_fd *read_event; @@ -84,8 +94,20 @@ struct lcddev { 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; @@ -130,12 +152,18 @@ void lcd_close(struct lcddev *dev) static int lcd_realdevice_open(struct lcddev *dev, const char *device) { - dev->fd = open(device, O_RDWR | O_NOCTTY | O_CLOEXEC); + 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; @@ -208,14 +236,14 @@ static int lcd_fakedevice_open(struct lcddev *dev) #endif /* (_LCD_DUMMY) */ #if (_LCD_DEBUG > 1) -static void lcd_dump(const char *prefix, int len, int size, const char *buf) +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)buf[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); @@ -248,6 +276,8 @@ static int lcd_write(struct lcddev *dev, char *buf, int len) 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; @@ -269,7 +299,7 @@ static int lcd_reset_timeout_cb(int timerid, void *privdata) return -1; /* singleshot */ } -void lcd_reset(struct lcddev *dev) +static void lcd_reset(struct lcddev *dev) { #if (_LCD_DEBUG > 0) log_print(LOG_DEBUG, "%s()", __FUNCTION__); @@ -278,29 +308,32 @@ void lcd_reset(struct lcddev *dev) char cmd[] = A125_CMD_RESET; lcd_write(dev, cmd, sizeof(cmd)); - dev->backlight_state = -1; + /* 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 mode) +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__, mode); + log_print(LOG_DEBUG, "%s(%d)", __FUNCTION__, enable); #endif /* (_LCD_DEBUG > 0) */ - if (dev->backlight_state != mode) { + if (dev->backlight_enabled != enable) { char cmd[] = A125_CMD_BACKLIGHT; - cmd[2] = (mode) ? 0x01 : 0x00; + + cmd[2] = (enable) ? 0x01 : 0x00; lcd_write(dev, cmd, sizeof(cmd)); + + dev->backlight_enabled = enable; } - dev->backlight_state = mode; return 0; } @@ -309,22 +342,27 @@ static int lcd_backlight_timeout_cb(int timerid, void *privdata) struct lcddev *dev = (struct lcddev *)privdata; dev->backlight_timeout = NULL; - lcd_backlight(dev, 0); - dev->event_callback(dev, LCD_EVENT_BACKLIGHT, dev->event_privdata); + lcd_pagecallback(dev, LCDPAGE_EVENT_BACKLIGHT); + + if (dev->backlight_timeout == NULL) { + lcd_backlight(dev, 0); + } + return -1; /* singleshot */ } -int lcd_trigger_backlight(struct lcddev *dev, int timeout) +int lcd_trigger_backlight(struct lcddev *dev, int enable, int timeout_ms) { if (dev->backlight_timeout != NULL) { event_remove_timeout(dev->backlight_timeout); dev->backlight_timeout = NULL; } - int retval = lcd_backlight(dev, (timeout == 0) ? 0 : 1); + int retval = lcd_backlight(dev, enable); - if (timeout != -1) { - dev->backlight_timeout = event_add_timeout_ms(timeout * 1000, lcd_backlight_timeout_cb, 0, dev); + if (enable && (timeout_ms != -1)) { + dev->backlight_timeout_ms = timeout_ms; + dev->backlight_timeout = event_add_timeout_ms(timeout_ms * 1000, lcd_backlight_timeout_cb, 0, dev); } return retval; @@ -333,14 +371,9 @@ int lcd_trigger_backlight(struct lcddev *dev, int timeout) static int lcd_update_timeout_cb(int timerid, void *privdata) { struct lcddev *dev = (struct lcddev *)privdata; + dev->update_timeout = NULL; - - int update = dev->event_callback(dev, LCD_EVENT_UPDATE, dev->event_privdata); - - /* update only if backlight is on (display visible) */ - if ((update != 0) && (dev->backlight_state != 0)) { - dev->update_timeout = event_add_timeout_ms(update, lcd_update_timeout_cb, 0, dev); - } + lcd_pagecallback(dev, LCDPAGE_EVENT_UPDATE); return -1; /* singleshot */ } @@ -350,7 +383,6 @@ static int lcd_read_cb(int fd, void *privdata) struct lcddev *dev = (struct lcddev *)privdata; char buf[4]; - int update = 0; int size = (dev->state != LCD_STATE_INITIALIZING) ? sizeof(buf) : 2; int len = lcd_read(dev, buf, size); @@ -367,7 +399,7 @@ static int lcd_read_cb(int fd, void *privdata) dev->state = LCD_STATE_READY; /* trigger application to set data */ - update = dev->event_callback(dev, LCD_EVENT_INIT, dev->event_privdata); + lcd_pagecallback(dev, LCDPAGE_EVENT_ENTER); } } else if (dev->state == LCD_STATE_READY) { @@ -378,23 +410,13 @@ static int lcd_read_cb(int fd, void *privdata) return 0; if (memcmp(buf, expect1, sizeof(buf)) == 0) { - update = dev->event_callback(dev, LCD_EVENT_BUTTON1, dev->event_privdata); + lcd_pagecallback(dev, LCDPAGE_EVENT_BUTTON1); } else if (memcmp(buf, expect2, sizeof(buf)) == 0) { - update = dev->event_callback(dev, LCD_EVENT_BUTTON2, dev->event_privdata); + lcd_pagecallback(dev, LCDPAGE_EVENT_BUTTON2); } } - if (dev->update_timeout != NULL) { - event_remove_timeout(dev->update_timeout); - dev->update_timeout = NULL; - } - - /* update only if backlight is on (display visible) */ - if ((update != 0) && (dev->backlight_state != 0)) { - dev->update_timeout = event_add_timeout_ms(update, lcd_update_timeout_cb, 0, dev); - } - return 0; } @@ -423,6 +445,12 @@ static int lcd_scroll_timeout_cb(int timerid, void *privdata) struct lcddev *dev = (struct lcddev *)privdata; int i, reset_pos = 0; + /* disable scrolling if backlight is off (display is not visible) */ + if (dev->backlight_enabled == 0) { + dev->scroll_timeout = NULL; + return -1; + } + for (i = 0; i < 2; i++) { int line_pos = dev->scroll_pos; if (line_pos < 0) @@ -446,19 +474,14 @@ static int lcd_scroll_timeout_cb(int timerid, void *privdata) 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 scroll_speed, const char *line1, const char *line2) +int lcd_setlines(struct lcddev *dev, const char *line1, const char *line2) { int i; + for (i = 0; i < 2; i++) { if (dev->line_data[i] != NULL) { free((void *)dev->line_data[i]); @@ -487,25 +510,123 @@ int lcd_setlines(struct lcddev *dev, int scroll_speed, const char *line1, const lcd_setline(dev, 0, dev->line_length[0], dev->line_data[0]); lcd_setline(dev, 1, dev->line_length[1], dev->line_data[1]); - 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 ((dev->line_length[0] > 16) || (dev->line_length[1] > 16)) { + if (dev->scroll_timeout == NULL) { + dev->scroll_pos = 0; + dev->scroll_timeout = event_add_timeout_ms(LCD_SCROLL_SPEED, lcd_scroll_timeout_cb, 0, dev); + } - dev->scroll_speed = scroll_speed; - dev->scroll_pos = 0; - - if ((dev->scroll_timeout == NULL) && scroll_enable && (scroll_speed > 0)) { - dev->scroll_timeout = event_add_timeout_ms(dev->scroll_speed, lcd_scroll_timeout_cb, 0, dev); + } else { + if (dev->scroll_timeout != NULL) { + event_remove_timeout(dev->scroll_timeout); + dev->scroll_timeout = NULL; + } } return 0; } -struct lcddev * lcd_open(const char *devicename, - int (*event_callback)(struct lcddev *dev, int button, void *privdata), - void *event_privdata) +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_trigger_backlight(dev, 1, dev->backlight_timeout_ms); + return; + } + + int next; + do { + log_print(LOG_DEBUG, "%s: cb(%p, 0x%x)", __FUNCTION__, dev->current_page, event); + int retval = dev->current_page->callback(dev, event, dev->current_page->privdata); + log_print(LOG_DEBUG, "%s: cb(%p, 0x%x) => 0x%x", __FUNCTION__, dev->current_page, event, retval); + + next = 0; + if ((event == LCDPAGE_EVENT_ENTER) && (retval == -1)) { + next = 1; + + } else if (retval == LCDPAGE_COMMAND_NEXT) { + next = 1; + } + + if (dev->update_timeout != NULL) { + event_remove_timeout(dev->update_timeout); + dev->update_timeout = NULL; + } + + 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); + } + + if (page == dev->current_page) { + next = 0; + break; + } + + if (next) { + dev->current_page->callback(dev, LCDPAGE_EVENT_EXIT, dev->current_page->privdata); + dev->current_page = page; + event = LCDPAGE_EVENT_ENTER; + } + + } else if ((retval != 0x00) && (dev->backlight_enabled != 0)) { + dev->update_timeout = event_add_timeout_ms(retval, lcd_update_timeout_cb, 0, dev); + } + } 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) { struct lcddev *dev = malloc(sizeof(struct lcddev)); if (dev == NULL) { @@ -515,6 +636,8 @@ struct lcddev * lcd_open(const char *devicename, memset(dev, 0, sizeof(struct lcddev)); + INIT_LIST_HEAD(&dev->page_list); + int retval; #if (_LCD_DUMMY) if (strncmp(devicename, "dummy", 5) == 0) { @@ -530,9 +653,6 @@ struct lcddev * lcd_open(const char *devicename, return NULL; } - dev->event_callback = event_callback; - dev->event_privdata = event_privdata; - dev->read_event = event_add_readfd(NULL, dev->fd, lcd_read_cb, dev); lcd_reset(dev); diff --git a/lcd.h b/lcd.h index 619d146..ca536b8 100644 --- a/lcd.h +++ b/lcd.h @@ -1,25 +1,28 @@ #ifndef _LCD_H_ #define _LCD_H_ -#define LCD_EVENT_INIT 0x00 /* lcd initialized */ -#define LCD_EVENT_UPDATE 0x01 /* update data */ -#define LCD_EVENT_BUTTON1 0x02 /* button1 pressed */ -#define LCD_EVENT_BUTTON2 0x03 /* button2 pressed */ -#define LCD_EVENT_BACKLIGHT 0x04 /* backlight timeout */ - struct lcddev; /* private data */ -struct lcddev * lcd_open(const char *device, - int (*event_callback)(struct lcddev *dev, int event, void *privdata), - void *event_privdata); - +struct lcddev * lcd_open(const char *devicename); 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 enable, int timeout); +int lcd_setlines(struct lcddev *dev, const char *line1, const char *line2); -int lcd_trigger_backlight(struct lcddev *dev, int timeout); -int lcd_setlines(struct lcddev *dev, int scrollspeed, const char *line1, const char *line2); +#define LCDPAGE_EVENT_BUTTON1 0xFFFFFF01 /* button "enter" pressed */ +#define LCDPAGE_EVENT_BUTTON2 0xFFFFFF02 /* button "select" pressed */ +#define LCDPAGE_EVENT_BACKLIGHT 0xFFFFFF03 /* backlight timeout */ +#define LCDPAGE_EVENT_ENTER 0xFFFFFF05 /* page entered */ +#define LCDPAGE_EVENT_EXIT 0xFFFFFF06 /* page left */ +#define LCDPAGE_EVENT_UPDATE 0xFFFFFF07 /* update content */ +#define LCDPAGE_COMMAND_NEXT 0xFFFFFF80 /* change to next page */ + +int lcd_addpage_cb(struct lcddev *dev, + int priority, + int (*event_callback)(struct lcddev *dev, int event, void *privdata), + void *event_privdata); + +int lcdpage_init(struct lcddev *dev); +void lcdpage_free(void); #endif /* _LCD_H_ */ diff --git a/lcdpage.c b/lcdpage.c new file mode 100644 index 0000000..92d6eb6 --- /dev/null +++ b/lcdpage.c @@ -0,0 +1,225 @@ +/*************************************************************************** + * Copyright (C) 12/2012 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 +#include +#include +#include + +#include +#include +#include + +#include "lcd.h" + +#define LCD_TIMEOUT 15 + +/* + * system: + * - os version done + * - kernel version done + * - hostname done + * - date/time done + * - uptime done + * - avgload done + * - cpu usage + * - memory/swap usage + * - temperature done (pic.c) + * - fan error done (pic.c) + * + * disk drives: + * - temperature -> disk + * - state (idle / running), time to idle -> disk + * - current i/o (aggregated?) + * + * partitions: + * - used / free / total + * + * ethernet interface: + * - link (10/100/1000) + * - current i/o + * + * ip interface: + * - ip address/netmask + * - default gateway + * - dns + * + */ + +static int lcdpage_system(struct lcddev *dev, int event, void *privdata) +{ + static int subpage; + int retval = 0; + char line1[64]; + char line2[64]; + + memset(line1, 0x00, sizeof(line1)); + memset(line2, 0x00, sizeof(line2)); + + if (event == LCDPAGE_EVENT_BUTTON1) { + lcd_trigger_backlight(dev, 1, LCD_TIMEOUT); + subpage++; + + } else if (event == LCDPAGE_EVENT_ENTER) { + lcd_trigger_backlight(dev, 1, LCD_TIMEOUT); + subpage = 0; + + } else if (event != LCDPAGE_EVENT_UPDATE) { + return 0; + } + + if (subpage == 0) { + FILE *fp = fopen("/etc/issue.net", "r"); + if (fp != NULL) { + fread(line1, 1, sizeof(line1), fp); + fclose(fp); + + char *trim = memchr(line1, 0x0A, sizeof(line1)); + if (trim != NULL) + *trim = '\0'; + + trim = memchr(line1, 0x0D, sizeof(line1)); + if (trim != NULL) + *trim = '\0'; + } else { + strcpy(line1, ""); + } + + struct utsname utsbuf; + uname(&utsbuf); + + snprintf(line2, sizeof(line2), "%s %s", utsbuf.sysname, utsbuf.release); + + lcd_setlines(dev, line1, line2); + + } else if (subpage == 1) { + /* copy hostname */ + if (gethostname(line2, sizeof(line2)) < 0) { + strcpy(line2, ""); + } + + int len = strlen(line2); + line2[len++] = '.'; + + /* append domainname */ + if (getdomainname(line2 + len, sizeof(line2) - len) < 0) { + strcpy(line2 + len, "unknown"); + } + + lcd_setlines(dev, "Hostname:", line2); + + } else if (subpage == 2) { + struct tm tmp; + time_t now; + + time(&now); + localtime_r(&now, &tmp); + + strftime(line1, sizeof(line1), "Time: %H:%M:%S", &tmp); + strftime(line2, sizeof(line2), "Date: %Y/%m/%d", &tmp); + + lcd_setlines(dev, line1, line2); + retval = 1000; /* update every second */ + + } else if (subpage == 3) { + struct sysinfo info; + + if (sysinfo(&info) < 0) { + return 0; + } + + int tmp, days, hours, minutes; + + days = info.uptime / 86400; + tmp = info.uptime % 86400; + + hours = tmp / 3600; + tmp = tmp % 3600; + + minutes = tmp / 60; + tmp = tmp % 60; + + snprintf(line2, sizeof(line2), " %03dd %02d:%02d:%02d", days, hours, minutes, tmp); + lcd_setlines(dev, "Uptime:", line2); + retval = 1000; + + } else if (subpage == 4) { + double loadavg[3]; + + if (getloadavg(loadavg, 3) < 0) { + return 0; + } + + snprintf(line2, sizeof(line2), " %1.2f %1.2f %1.2f", loadavg[0], loadavg[1], loadavg[2]); + lcd_setlines(dev, "LoadAVG:", line2); + retval = 1000; + + } else { + return LCDPAGE_COMMAND_NEXT; + } + + /* update every 1000ms */ + return retval; +} + +static int lcdpage_network(struct lcddev *dev, int event, void *privdata) +{ + static int subpage; + + if (event == LCDPAGE_EVENT_BUTTON1) { + lcd_trigger_backlight(dev, 1, LCD_TIMEOUT); + subpage++; + + } else if (event == LCDPAGE_EVENT_ENTER) { + lcd_trigger_backlight(dev, 1, LCD_TIMEOUT); + subpage = 0; + + } else if (event != LCDPAGE_EVENT_UPDATE) { + return 0; + } + + switch (subpage) { + case 0: + lcd_setlines(dev, "Address(br0):", "10.10.250.135"); + break; + case 1: + lcd_setlines(dev, "Netmask(br0):", "255.255.0.0"); + break; + case 2: + lcd_setlines(dev, "Gateway(br0):", "10.10.250.250"); + break; + default: + return LCDPAGE_COMMAND_NEXT; + } + + return 0; +} + +void lcdpage_free(void) +{ + /* nothing to do, lcdpages are cleaned up in lcd_close() */ +} + +int lcdpage_init(struct lcddev *dev) +{ + lcd_addpage_cb(dev, 200, lcdpage_system, NULL); + lcd_addpage_cb(dev, 100, lcdpage_network, NULL); + + return 0; +} diff --git a/pic.c b/pic.c index 9fb27aa..968eef2 100644 --- a/pic.c +++ b/pic.c @@ -29,81 +29,42 @@ #include #include "event.h" +#include "lcd.h" #include "logging.h" - -#define PIC_CMD_FANSPEED_0 0x30 -#define PIC_CMD_FANSPEED_1 0x31 -#define PIC_CMD_FANSPEED_2 0x32 -#define PIC_CMD_FANSPEED_3 0x33 -#define PIC_CMD_FANSPEED_4 0x34 -#define PIC_CMD_FANSPEED_5 0x35 - -#define PIC_CMD_POWER_OFF 0x41 - -#define PIC_CMD_AUTOPOWER_ON 0x48 -#define PIC_CMD_AUTOPOWER_OFF 0x49 - -#define PIC_CMD_POWERLED_OFF 0x4B -#define PIC_CMD_POWERLED_2HZ 0x4C -#define PIC_CMD_POWERLED_ON 0x4D -#define PIC_CMD_POWERLED_1HZ 0x4E - -#define PIC_CMD_BUZZ_SHORT 0x50 -#define PIC_CMD_BUZZ_LONG 0x51 - -#define PIC_CMD_STATUSLED_RED_2HZ 0x54 -#define PIC_CMD_STATUSLED_GREEN_2HZ 0x55 -#define PIC_CMD_STATUSLED_GREENON 0x56 -#define PIC_CMD_STATUSLED_REDON 0x57 -#define PIC_CMD_STATUSLED_REDGREEN_2HZ 0x58 -#define PIC_CMD_STATUSLED_OFF 0x59 -#define PIC_CMD_STATUSLED_GREEN_1HZ 0x5A -#define PIC_CMD_STATUSLED_RED_1HZ 0x5B -#define PIC_CMD_STATUSLED_REDGREEN_1HZ 0x5C - -#define PIC_CMD_USBLED_ON 0x60 -#define PIC_CMD_USBLED_8HZ 0x61 -#define PIC_CMD_USBLED_OFF 0x62 - -#define PIC_EVENT_POWER_BUTTON 0x40 - -#define PIC_EVENT_FAN1_ERR 0x73 -#define PIC_EVENT_FAN1_OK 0x74 -#define PIC_EVENT_FAN2_ERR 0x75 -#define PIC_EVENT_FAN2_OK 0x76 -#define PIC_EVENT_FAN3_ERR 0x77 -#define PIC_EVENT_FAN3_OK 0x78 -#define PIC_EVENT_FAN4_ERR 0x79 -#define PIC_EVENT_FAN4_OK 0x7A - -#define PIC_EVENT_TEMP_RANGE_MIN 0x80 /* 0°C */ -#define PIC_EVENT_TEMP_RANGE_MAX 0xC6 /* 70°C */ -#define PIC_EVENT_TEMP_WARN 0x38 /* 71-79°C */ -#define PIC_EVENT_TEMP_CRIT 0x39 /* >= 80°C */ - +#include "pic.h" struct picdev { int fd; struct termios oldtio; + + int fan_speed; + int fan_error; + int temperature; + + struct event_fd *read_event; }; -static struct picdev *g_dev; - -static int pic_close(struct picdev *dev) +static int pic_close_device(struct picdev *dev) { tcsetattr(dev->fd, TCSANOW, &dev->oldtio); close(dev->fd); return 0; } -static int pic_open(struct picdev *dev, const char *device) +static int pic_open_device(struct picdev *dev, const char *device) { - dev->fd = open(device, O_RDWR | O_NOCTTY | O_CLOEXEC); + 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; @@ -126,6 +87,44 @@ static int pic_open(struct picdev *dev, const char *device) return 0; } +int pic_set_fanspeed(struct picdev *dev, char value) +{ + if (value < PIC_CMD_FANSPEED_0 || value > PIC_CMD_FANSPEED_5) + return -1; + + dev->fan_speed = value - PIC_CMD_FANSPEED_0; + + write(dev->fd, &value, 1); + return 0; +} + +int pic_set_buzzer(struct picdev *dev, char value) +{ + if (value < PIC_CMD_BUZZ_SHORT || value > PIC_CMD_BUZZ_LONG) + return -1; + + write(dev->fd, &value, 1); + return 0; +} + +int pic_set_status_led(struct picdev *dev, char value) +{ + if (value < PIC_CMD_STATUSLED_RED_2HZ || value > PIC_CMD_STATUSLED_REDGREEN_1HZ) + return -1; + + write(dev->fd, &value, 1); + return 0; +} + +int pic_set_usb_led(struct picdev *dev, char value) +{ + if (value < PIC_CMD_USBLED_ON || value > PIC_CMD_USBLED_OFF) + return -1; + + write(dev->fd, &value, 1); + return 0; +} + static int pic_read_cb(int fd, void *privdata) { struct picdev *dev = (struct picdev *)privdata; @@ -137,30 +136,30 @@ static int pic_read_cb(int fd, void *privdata) switch (event) { - case PIC_EVENT_POWER_BUTTON: - log_print(LOG_DEBUG, "%s(): POWER BUTTON", __FUNCTION__); + case PIC_EVENT_FAN1_ERR: + pic_set_buzzer(dev, PIC_CMD_BUZZ_SHORT); + dev->fan_error = 1; break; - case PIC_EVENT_FAN1_ERR: case PIC_EVENT_FAN1_OK: - log_print(LOG_DEBUG, "%s(): FAN1 %s", __FUNCTION__, (event & 0x01) ? "fail" : "ok"); + dev->fan_error = 0; break; case PIC_EVENT_FAN2_ERR: case PIC_EVENT_FAN2_OK: - log_print(LOG_DEBUG, "%s(): FAN2 %s", __FUNCTION__, (event & 0x01) ? "fail" : "ok"); break; case PIC_EVENT_TEMP_RANGE_MIN ... PIC_EVENT_TEMP_RANGE_MAX: - log_print(LOG_DEBUG, "%s(): TEMP %d°C", __FUNCTION__, event - 128); + dev->temperature = event - 128; break; case PIC_EVENT_TEMP_WARN: - log_print(LOG_DEBUG, "%s(): TEMP WARNING", __FUNCTION__); + pic_set_buzzer(dev, PIC_CMD_BUZZ_SHORT); + dev->temperature = 75; break; case PIC_EVENT_TEMP_CRIT: - log_print(LOG_DEBUG, "%s(): TEMP CRITICAL", __FUNCTION__); + dev->temperature = 80; break; default: @@ -171,26 +170,79 @@ static int pic_read_cb(int fd, void *privdata) return 0; } -void pic_init(void) +static int lcdpage_case(struct lcddev *lcd, int event, void *privdata) +{ + struct picdev *dev = (struct picdev *)privdata; + + if (event == LCDPAGE_EVENT_BUTTON1) { + return LCDPAGE_COMMAND_NEXT; + + } else if (event == LCDPAGE_EVENT_BUTTON2) { + int fan_speed = PIC_CMD_FANSPEED_0 + dev->fan_speed +1; + + if (fan_speed > PIC_CMD_FANSPEED_5) + fan_speed = PIC_CMD_FANSPEED_0; + + pic_set_fanspeed(dev, fan_speed); + lcd_trigger_backlight(lcd, 1, 15); + + } else if (event == LCDPAGE_EVENT_ENTER) { + lcd_trigger_backlight(lcd, 1, 15); + + } else if (event != LCDPAGE_EVENT_UPDATE) { + return 0; + } + + char line1_ok[] = "FAN(OK): TEMP:"; + char line1_err[] = "FAN(ERR): TEMP:"; + char line2[20]; + + snprintf(line2, sizeof(line2), "[ ] %02d C ", dev->temperature); + + int i; + for (i = 1; i <= dev->fan_speed; i++) { + line2[i] = '#'; + } + + lcd_setlines(lcd, (dev->fan_error ? line1_err : line1_ok), line2); + return 1000; +} + +struct picdev * pic_open(const char *devicename, struct lcddev *lcd) { struct picdev *dev = malloc(sizeof(struct picdev)); if (dev == NULL) { log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__); - return; + return NULL; } memset(dev, 0, sizeof(struct picdev)); - if (pic_open(dev, "/dev/ttyS1")< 0) { + if (pic_open_device(dev, devicename) < 0) { free(dev); - return; + return NULL; } - event_add_readfd(NULL, dev->fd, pic_read_cb, dev); - g_dev = dev; // HACK + dev->read_event = event_add_readfd(NULL, dev->fd, pic_read_cb, dev); + + if (lcd != NULL) { + lcd_addpage_cb(lcd, 190, lcdpage_case, dev); + } + + pic_set_fanspeed(dev, PIC_CMD_FANSPEED_1); + pic_set_status_led(dev, PIC_CMD_STATUSLED_GREENON); + + return dev; } -void pic_exit(void) +void pic_close(struct picdev *dev) { - pic_close(g_dev); + if (dev->read_event != NULL) { + event_remove_fd(dev->read_event); + dev->read_event = NULL; + } + + pic_close_device(dev); + + free(dev); } diff --git a/pic.h b/pic.h new file mode 100644 index 0000000..55921d5 --- /dev/null +++ b/pic.h @@ -0,0 +1,64 @@ +#ifndef _PIC_H_ +#define _PIC_H_ + +struct picdev; /* private data */ + +struct picdev * pic_open(const char *devicename, struct lcddev *lcd); +void pic_close(struct picdev *dev); + +#define PIC_CMD_FANSPEED_0 0x30 +#define PIC_CMD_FANSPEED_1 0x31 +#define PIC_CMD_FANSPEED_2 0x32 +#define PIC_CMD_FANSPEED_3 0x33 +#define PIC_CMD_FANSPEED_4 0x34 +#define PIC_CMD_FANSPEED_5 0x35 + +#define PIC_CMD_POWER_OFF 0x41 + +#define PIC_CMD_AUTOPOWER_ON 0x48 +#define PIC_CMD_AUTOPOWER_OFF 0x49 + +#define PIC_EVENT_POWER_BUTTON 0x40 + +#define PIC_CMD_POWERLED_OFF 0x4B +#define PIC_CMD_POWERLED_2HZ 0x4C +#define PIC_CMD_POWERLED_ON 0x4D +#define PIC_CMD_POWERLED_1HZ 0x4E + +#define PIC_CMD_BUZZ_SHORT 0x50 +#define PIC_CMD_BUZZ_LONG 0x51 + +#define PIC_CMD_STATUSLED_RED_2HZ 0x54 +#define PIC_CMD_STATUSLED_GREEN_2HZ 0x55 +#define PIC_CMD_STATUSLED_GREENON 0x56 +#define PIC_CMD_STATUSLED_REDON 0x57 +#define PIC_CMD_STATUSLED_REDGREEN_2HZ 0x58 +#define PIC_CMD_STATUSLED_OFF 0x59 +#define PIC_CMD_STATUSLED_GREEN_1HZ 0x5A +#define PIC_CMD_STATUSLED_RED_1HZ 0x5B +#define PIC_CMD_STATUSLED_REDGREEN_1HZ 0x5C + +#define PIC_CMD_USBLED_ON 0x60 +#define PIC_CMD_USBLED_8HZ 0x61 +#define PIC_CMD_USBLED_OFF 0x62 + +#define PIC_EVENT_FAN1_ERR 0x73 +#define PIC_EVENT_FAN1_OK 0x74 +#define PIC_EVENT_FAN2_ERR 0x75 +#define PIC_EVENT_FAN2_OK 0x76 +#define PIC_EVENT_FAN3_ERR 0x77 +#define PIC_EVENT_FAN3_OK 0x78 +#define PIC_EVENT_FAN4_ERR 0x79 +#define PIC_EVENT_FAN4_OK 0x7A + +#define PIC_EVENT_TEMP_RANGE_MIN 0x80 /* 0°C */ +#define PIC_EVENT_TEMP_RANGE_MAX 0xC6 /* 70°C */ +#define PIC_EVENT_TEMP_WARN 0x38 /* 71-79°C */ +#define PIC_EVENT_TEMP_CRIT 0x39 /* >= 80°C */ + +int pic_set_fanspeed(struct picdev *dev, char value); +int pic_set_buzzer(struct picdev *dev, char value); +int pic_set_status_led(struct picdev *dev, char value); +int pic_set_usb_led(struct picdev *dev, char value); + +#endif /* _PIC_H_ */ diff --git a/pidfile.c b/pidfile.c index f5dd0be..36f035a 100644 --- a/pidfile.c +++ b/pidfile.c @@ -8,8 +8,6 @@ #include #include -#include "logging.h" - int pidfile_create(const char *filename) { int fd = open(filename, O_CREAT | O_EXCL | O_RDWR, 0644); diff --git a/qnapd.c b/qnapd.c index 1f90293..0afaede 100644 --- a/qnapd.c +++ b/qnapd.c @@ -22,147 +22,44 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#include #include "configfile.h" #include "disktimeout.h" #include "event.h" #include "lcd.h" #include "logging.h" +#include "pic.h" #include "pidfile.h" #include "signals.h" -void pic_init(void); -void pic_exit(void); - -#define LCD_DEVICE "/dev/ttyS0" -#define LCD_TIMEOUT 15 - -#define DEFAULT_CONFIG PROGNAME".conf" -#define DEFAULT_LOGFILE PROGNAME".log" -#define DEFAULT_PIDFILE PROGNAME".pid" +#define DEFAULT_CONFIG "qnapd.conf" +#define DEFAULT_LOGFILE "qnapd.log" +#define DEFAULT_PIDFILE "qnapd.pid" static struct option opts[] = { - {"config", 1, 0, 'c'}, - {"debug", 0, 0, 'd'}, - {"help", 0, 0, 'h'}, - {0, 0, 0, 0} + { "config", 1, 0, 'c' }, + { "debug", 0, 0, 'd' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } }; -#define PAGE_MAX 7 - -static int page; - -static int button_callback(struct lcddev *dev, int button, void *privdata) -{ - if (button == LCD_EVENT_BUTTON2) { - page = (page < PAGE_MAX) ? page +1 : 0; - - } else if (button == LCD_EVENT_BUTTON1) { - page = (page > 0) ? page -1 : PAGE_MAX; - - } else if (button == LCD_EVENT_BACKLIGHT) { - return 0; /* no update requested */ - } - - if (button != LCD_EVENT_UPDATE) { - lcd_trigger_backlight(dev, LCD_TIMEOUT); - } - - int update = 0; - - switch (page) { - case 7: - { - FILE *fp = fopen("/etc/issue.net", "r"); - char line1[64]; - char line2[64]; - - memset(line1, 0x00, sizeof(line1)); - memset(line2, 0x00, sizeof(line2)); - - if (fp != NULL) { - fread(line1, 1, sizeof(line1), fp); - fclose(fp); - } else { - strcpy(line1, ""); - } - - struct utsname utsbuf; - uname(&utsbuf); - - snprintf(line2, sizeof(line2), "%s %s", utsbuf.sysname, utsbuf.release); - - lcd_setlines(dev, 500, line1, line2); - } - break; - - case 1: - lcd_setlines(dev, 0, "Hostname:", "storenix.lan"); - break; - case 2: - lcd_setlines(dev, 0, "Address(br0):", "10.10.250.135"); - break; - case 3: - lcd_setlines(dev, 0, "Netmask(br0):", "255.255.0.0"); - break; - case 4: - lcd_setlines(dev, 0, "Gateway(br0):", "10.10.250.250"); - break; - case 5: - lcd_setlines(dev, 0, "LoadAVG:", "x.xx x.xx x.xx"); - break; - case 6: - lcd_setlines(dev, 0, "Uptime:", " XXXd XX:XX:XX"); - break; - case 0: - { - char line1[20]; - char line2[20]; - - struct tm tmp; - time_t now; - - time(&now); - localtime_r(&now, &tmp); - - strftime(line1, sizeof(line1), "Time: %H:%M:%S", &tmp); - strftime(line2, sizeof(line2), "Date: %d-%m-%Y", &tmp); - - lcd_setlines(dev, 0, line1, line2); - update = 1000; - } - break; - - - } - - return update; -} - static int restart_var; static void trigger_restart(void *privdata) { - int *restart = (int *)privdata; - *restart = 1; + restart_var = 1; } int check_restart(int *maxfd, void *readfds, void *writefds, struct timeval *timeout, void *privdata) { - int *restart = (int *)privdata; - if (*restart == 1) { - *restart = 0; - return 1; - } + if (restart_var == 1) { + restart_var = 0; + return 1; + } - return 0; + return 0; } int main(int argc, char *argv[]) @@ -183,7 +80,7 @@ int main(int argc, char *argv[]) break; case 'h': /* help */ - printf("Usage: "PROGNAME" [options]\n" + printf("Usage: qnapd [options]\n" "Options: \n" " --config -c configfile use this configfile\n" " --debug -d do not fork and log to stderr\n" @@ -209,7 +106,7 @@ int main(int argc, char *argv[]) /* check pidfile */ const char *pidfile = config_get_string("global", "pidfile", DEFAULT_PIDFILE); if (pidfile_check(pidfile, 1) != 0) { - log_print(LOG_ERROR, PROGNAME" already running"); + log_print(LOG_ERROR, "qnapd already running"); exit(1); } @@ -218,7 +115,7 @@ int main(int argc, char *argv[]) if (log_init(logfile) < 0) exit(1); - /* zum daemon mutieren */ + /* mutate to daemon */ if (daemon(-1, 0) < 0) { log_print(LOG_ERROR, "failed to daemonize"); exit(1); @@ -232,34 +129,52 @@ int main(int argc, char *argv[]) } signal_init(); - signal_add_callback(SIGHUP, trigger_restart, (void *)&restart_var); + signal_add_callback(SIGHUP, trigger_restart, NULL); - log_print(LOG_EVERYTIME, PROGNAME" started (pid:%d)", getpid()); + log_print(LOG_EVERYTIME, "qnapd started (pid:%d)", getpid()); while (1) { + struct lcddev *lcd = NULL; + struct picdev *pic = NULL; - const char *lcddevice = config_get_string("global", "lcddevice", NULL); - struct lcddev *dev = NULL; - if (lcddevice != NULL) { - dev = lcd_open(lcddevice, &button_callback, NULL); - if (dev == NULL) + do { + const char *devicename = config_get_string("global", "lcddevice", NULL); + if (devicename != NULL) { + lcd = lcd_open(devicename); + if (lcd == NULL) { + break; + } + + if (lcdpage_init(lcd) < 0) { + break; + } + } + + devicename = config_get_string("global", "picdevice", NULL); + if (devicename != NULL) { + pic = pic_open(devicename, lcd); + if (pic == NULL) { + break; + } + } + + if (disktimeout_init() < 0) break; - } - pic_init(); - - if (disktimeout_init() < 0) - break; - - /* exited on restart / SIGUSR1 */ - event_loop(check_restart, NULL, (void *)&restart_var); + /* exited on restart / SIGUSR1 */ + event_loop(check_restart, NULL, NULL); + } while (0); disktimeout_exit(); - pic_exit(); + if (pic != NULL) { + pic_close(pic); + } - if (dev != NULL) - lcd_close(dev); + if (lcd != NULL) { + lcdpage_free(); + lcd_close(lcd); + } config_free(); @@ -270,7 +185,7 @@ int main(int argc, char *argv[]) if (!debug && log_init(logfile) < 0) break; - log_print(LOG_EVERYTIME, PROGNAME" restarted (pid:%d) ", getpid()); + log_print(LOG_EVERYTIME, "qnapd restarted (pid:%d) ", getpid()); } return 0; diff --git a/qnapd.conf b/qnapd.conf index a8c8b35..1e9e059 100644 --- a/qnapd.conf +++ b/qnapd.conf @@ -1,6 +1,8 @@ [global] #lcddevice /dev/ttyS0 +#picdevice /dev/ttyS1 + #lcddevice dummy pidfile qnapd.pid