work work

This commit is contained in:
Olaf Rempel 2012-12-08 00:39:04 +01:00
parent 86e94cce91
commit 031b7e540d
8 changed files with 672 additions and 293 deletions

240
lcd.c
View File

@ -30,11 +30,13 @@
#include "event.h" #include "event.h"
#include "lcd.h" #include "lcd.h"
#include "list.h"
#include "logging.h" #include "logging.h"
#define _LCD_DEBUG 1 #define _LCD_DEBUG 1
#define _LCD_DUMMY 1 #define _LCD_DUMMY 1
#define LCD_SCROLL_SPEED 750 /* 750ms */
#define LCD_RESET_TIMEOUT 250 /* 250ms */ #define LCD_RESET_TIMEOUT 250 /* 250ms */
#define LCD_RESET_RETRY_TIMEOUT 10000 /* 10s */ #define LCD_RESET_RETRY_TIMEOUT 10000 /* 10s */
@ -51,6 +53,14 @@
#define A125_EVENT_ACTINFO { 0x53, 0xAA } #define A125_EVENT_ACTINFO { 0x53, 0xAA }
#define A125_EVENT_INVALID { 0x53, 0xFB } // never seen #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 { enum lcdstate {
LCD_STATE_NOT_INITIALIZED = 0x00, LCD_STATE_NOT_INITIALIZED = 0x00,
LCD_STATE_INITIALIZING, LCD_STATE_INITIALIZING,
@ -67,14 +77,14 @@ struct lcddev {
enum lcdstate state; enum lcdstate state;
int backlight_state; int backlight_enabled;
int backlight_timeout_ms;
int (*event_callback)(struct lcddev *dev, int event, void *privdata); struct list_head page_list;
void *event_privdata; struct lcdpage *current_page;
const char *line_data[2]; const char *line_data[2];
int line_length[2]; int line_length[2];
int scroll_speed;
int scroll_pos; int scroll_pos;
struct event_fd *read_event; struct event_fd *read_event;
@ -84,8 +94,20 @@ struct lcddev {
struct event_timeout *update_timeout; struct event_timeout *update_timeout;
}; };
static void lcd_pagecallback(struct lcddev *dev, int event);
void lcd_close(struct lcddev *dev) 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) { if (dev->reset_timeout) {
event_remove_timeout(dev->reset_timeout); event_remove_timeout(dev->reset_timeout);
dev->reset_timeout = NULL; 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) 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) { if (dev->fd < 0) {
log_print(LOG_ERROR, "%s(): failed to open '%s'", __FUNCTION__, device); log_print(LOG_ERROR, "%s(): failed to open '%s'", __FUNCTION__, device);
return -1; 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); tcgetattr(dev->fd, &dev->oldtio);
struct termios newtio; struct termios newtio;
@ -208,14 +236,14 @@ static int lcd_fakedevice_open(struct lcddev *dev)
#endif /* (_LCD_DUMMY) */ #endif /* (_LCD_DUMMY) */
#if (_LCD_DEBUG > 1) #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 i;
int pos = 0; int pos = 0;
char buf[256]; char buf[256];
for (i = 0; i < len; i++) { 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); 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; return retval;
} }
static void lcd_reset(struct lcddev *dev);
static int lcd_reset_retry_timeout_cb(int timerid, void *privdata) static int lcd_reset_retry_timeout_cb(int timerid, void *privdata)
{ {
struct lcddev *dev = (struct lcddev *)privdata; struct lcddev *dev = (struct lcddev *)privdata;
@ -269,7 +299,7 @@ static int lcd_reset_timeout_cb(int timerid, void *privdata)
return -1; /* singleshot */ return -1; /* singleshot */
} }
void lcd_reset(struct lcddev *dev) static void lcd_reset(struct lcddev *dev)
{ {
#if (_LCD_DEBUG > 0) #if (_LCD_DEBUG > 0)
log_print(LOG_DEBUG, "%s()", __FUNCTION__); log_print(LOG_DEBUG, "%s()", __FUNCTION__);
@ -278,29 +308,32 @@ void lcd_reset(struct lcddev *dev)
char cmd[] = A125_CMD_RESET; char cmd[] = A125_CMD_RESET;
lcd_write(dev, cmd, sizeof(cmd)); lcd_write(dev, cmd, sizeof(cmd));
dev->backlight_state = -1; /* force next backlight command */
dev->backlight_enabled = -1;
dev->state = LCD_STATE_INITIALIZING; dev->state = LCD_STATE_INITIALIZING;
dev->reset_timeout = event_add_timeout_ms(LCD_RESET_TIMEOUT, lcd_reset_timeout_cb, 0, dev); 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) if (dev->state != LCD_STATE_READY)
return -1; return -1;
#if (_LCD_DEBUG > 0) #if (_LCD_DEBUG > 0)
log_print(LOG_DEBUG, "%s(%d)", __FUNCTION__, mode); log_print(LOG_DEBUG, "%s(%d)", __FUNCTION__, enable);
#endif /* (_LCD_DEBUG > 0) */ #endif /* (_LCD_DEBUG > 0) */
if (dev->backlight_state != mode) { if (dev->backlight_enabled != enable) {
char cmd[] = A125_CMD_BACKLIGHT; char cmd[] = A125_CMD_BACKLIGHT;
cmd[2] = (mode) ? 0x01 : 0x00;
cmd[2] = (enable) ? 0x01 : 0x00;
lcd_write(dev, cmd, sizeof(cmd)); lcd_write(dev, cmd, sizeof(cmd));
dev->backlight_enabled = enable;
} }
dev->backlight_state = mode;
return 0; return 0;
} }
@ -309,22 +342,27 @@ static int lcd_backlight_timeout_cb(int timerid, void *privdata)
struct lcddev *dev = (struct lcddev *)privdata; struct lcddev *dev = (struct lcddev *)privdata;
dev->backlight_timeout = NULL; dev->backlight_timeout = NULL;
lcd_pagecallback(dev, LCDPAGE_EVENT_BACKLIGHT);
if (dev->backlight_timeout == NULL) {
lcd_backlight(dev, 0); lcd_backlight(dev, 0);
dev->event_callback(dev, LCD_EVENT_BACKLIGHT, dev->event_privdata); }
return -1; /* singleshot */ 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) { if (dev->backlight_timeout != NULL) {
event_remove_timeout(dev->backlight_timeout); event_remove_timeout(dev->backlight_timeout);
dev->backlight_timeout = NULL; dev->backlight_timeout = NULL;
} }
int retval = lcd_backlight(dev, (timeout == 0) ? 0 : 1); int retval = lcd_backlight(dev, enable);
if (timeout != -1) { if (enable && (timeout_ms != -1)) {
dev->backlight_timeout = event_add_timeout_ms(timeout * 1000, lcd_backlight_timeout_cb, 0, dev); dev->backlight_timeout_ms = timeout_ms;
dev->backlight_timeout = event_add_timeout_ms(timeout_ms * 1000, lcd_backlight_timeout_cb, 0, dev);
} }
return retval; 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) static int lcd_update_timeout_cb(int timerid, void *privdata)
{ {
struct lcddev *dev = (struct lcddev *)privdata; struct lcddev *dev = (struct lcddev *)privdata;
dev->update_timeout = NULL; dev->update_timeout = NULL;
lcd_pagecallback(dev, LCDPAGE_EVENT_UPDATE);
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);
}
return -1; /* singleshot */ return -1; /* singleshot */
} }
@ -350,7 +383,6 @@ static int lcd_read_cb(int fd, void *privdata)
struct lcddev *dev = (struct lcddev *)privdata; struct lcddev *dev = (struct lcddev *)privdata;
char buf[4]; char buf[4];
int update = 0;
int size = (dev->state != LCD_STATE_INITIALIZING) ? sizeof(buf) : 2; int size = (dev->state != LCD_STATE_INITIALIZING) ? sizeof(buf) : 2;
int len = lcd_read(dev, buf, size); 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; dev->state = LCD_STATE_READY;
/* trigger application to set data */ /* 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) { } else if (dev->state == LCD_STATE_READY) {
@ -378,23 +410,13 @@ static int lcd_read_cb(int fd, void *privdata)
return 0; return 0;
if (memcmp(buf, expect1, sizeof(buf)) == 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) { } 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; return 0;
} }
@ -423,6 +445,12 @@ static int lcd_scroll_timeout_cb(int timerid, void *privdata)
struct lcddev *dev = (struct lcddev *)privdata; struct lcddev *dev = (struct lcddev *)privdata;
int i, reset_pos = 0; 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++) { for (i = 0; i < 2; i++) {
int line_pos = dev->scroll_pos; int line_pos = dev->scroll_pos;
if (line_pos < 0) if (line_pos < 0)
@ -446,19 +474,14 @@ static int lcd_scroll_timeout_cb(int timerid, void *privdata)
if (reset_pos == 2) if (reset_pos == 2)
dev->scroll_pos = -1; 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 */ /* periodic */
return 0; 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; int i;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (dev->line_data[i] != NULL) { if (dev->line_data[i] != NULL) {
free((void *)dev->line_data[i]); 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, 0, dev->line_length[0], dev->line_data[0]);
lcd_setline(dev, 1, dev->line_length[1], dev->line_data[1]); 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->line_length[0] > 16) || (dev->line_length[1] > 16)) {
if (dev->scroll_timeout && ((dev->scroll_speed != scroll_speed) || !scroll_enable)) { 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);
}
} else {
if (dev->scroll_timeout != NULL) {
event_remove_timeout(dev->scroll_timeout); event_remove_timeout(dev->scroll_timeout);
dev->scroll_timeout = NULL; dev->scroll_timeout = NULL;
} }
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);
} }
return 0; return 0;
} }
struct lcddev * lcd_open(const char *devicename, static void lcd_pagecallback(struct lcddev *dev, int event)
int (*event_callback)(struct lcddev *dev, int button, void *privdata), {
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) 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)); struct lcddev *dev = malloc(sizeof(struct lcddev));
if (dev == NULL) { if (dev == NULL) {
@ -515,6 +636,8 @@ struct lcddev * lcd_open(const char *devicename,
memset(dev, 0, sizeof(struct lcddev)); memset(dev, 0, sizeof(struct lcddev));
INIT_LIST_HEAD(&dev->page_list);
int retval; int retval;
#if (_LCD_DUMMY) #if (_LCD_DUMMY)
if (strncmp(devicename, "dummy", 5) == 0) { if (strncmp(devicename, "dummy", 5) == 0) {
@ -530,9 +653,6 @@ struct lcddev * lcd_open(const char *devicename,
return NULL; 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); dev->read_event = event_add_readfd(NULL, dev->fd, lcd_read_cb, dev);
lcd_reset(dev); lcd_reset(dev);

33
lcd.h
View File

@ -1,25 +1,28 @@
#ifndef _LCD_H_ #ifndef _LCD_H_
#define _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; /* private data */
struct lcddev * lcd_open(const char *device, struct lcddev * lcd_open(const char *devicename);
void lcd_close(struct lcddev *dev);
int lcd_trigger_backlight(struct lcddev *dev, int enable, int timeout);
int lcd_setlines(struct lcddev *dev, 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), int (*event_callback)(struct lcddev *dev, int event, void *privdata),
void *event_privdata); void *event_privdata);
void lcd_close(struct lcddev *dev); int lcdpage_init(struct lcddev *dev);
void lcd_reset(struct lcddev *dev); void lcdpage_free(void);
#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);
#endif /* _LCD_H_ */ #endif /* _LCD_H_ */

225
lcdpage.c Normal file
View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/utsname.h>
#include <sys/sysinfo.h>
#include <time.h>
#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, "<unknown>");
}
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, "<unknown>");
}
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;
}

196
pic.c
View File

@ -29,81 +29,42 @@
#include <termios.h> #include <termios.h>
#include "event.h" #include "event.h"
#include "lcd.h"
#include "logging.h" #include "logging.h"
#include "pic.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 */
struct picdev { struct picdev {
int fd; int fd;
struct termios oldtio; 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_device(struct picdev *dev)
static int pic_close(struct picdev *dev)
{ {
tcsetattr(dev->fd, TCSANOW, &dev->oldtio); tcsetattr(dev->fd, TCSANOW, &dev->oldtio);
close(dev->fd); close(dev->fd);
return 0; 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) { if (dev->fd < 0) {
log_print(LOG_ERROR, "%s(): failed to open '%s'", __FUNCTION__, device); log_print(LOG_ERROR, "%s(): failed to open '%s'", __FUNCTION__, device);
return -1; 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); tcgetattr(dev->fd, &dev->oldtio);
struct termios newtio; struct termios newtio;
@ -126,6 +87,44 @@ static int pic_open(struct picdev *dev, const char *device)
return 0; 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) static int pic_read_cb(int fd, void *privdata)
{ {
struct picdev *dev = (struct picdev *)privdata; struct picdev *dev = (struct picdev *)privdata;
@ -137,30 +136,30 @@ static int pic_read_cb(int fd, void *privdata)
switch (event) switch (event)
{ {
case PIC_EVENT_POWER_BUTTON: case PIC_EVENT_FAN1_ERR:
log_print(LOG_DEBUG, "%s(): POWER BUTTON", __FUNCTION__); pic_set_buzzer(dev, PIC_CMD_BUZZ_SHORT);
dev->fan_error = 1;
break; break;
case PIC_EVENT_FAN1_ERR:
case PIC_EVENT_FAN1_OK: case PIC_EVENT_FAN1_OK:
log_print(LOG_DEBUG, "%s(): FAN1 %s", __FUNCTION__, (event & 0x01) ? "fail" : "ok"); dev->fan_error = 0;
break; break;
case PIC_EVENT_FAN2_ERR: case PIC_EVENT_FAN2_ERR:
case PIC_EVENT_FAN2_OK: case PIC_EVENT_FAN2_OK:
log_print(LOG_DEBUG, "%s(): FAN2 %s", __FUNCTION__, (event & 0x01) ? "fail" : "ok");
break; break;
case PIC_EVENT_TEMP_RANGE_MIN ... PIC_EVENT_TEMP_RANGE_MAX: 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; break;
case PIC_EVENT_TEMP_WARN: 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; break;
case PIC_EVENT_TEMP_CRIT: case PIC_EVENT_TEMP_CRIT:
log_print(LOG_DEBUG, "%s(): TEMP CRITICAL", __FUNCTION__); dev->temperature = 80;
break; break;
default: default:
@ -171,26 +170,79 @@ static int pic_read_cb(int fd, void *privdata)
return 0; 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)); struct picdev *dev = malloc(sizeof(struct picdev));
if (dev == NULL) { if (dev == NULL) {
log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__); log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
return; return NULL;
} }
memset(dev, 0, sizeof(struct picdev)); memset(dev, 0, sizeof(struct picdev));
if (pic_open(dev, "/dev/ttyS1")< 0) { if (pic_open_device(dev, devicename) < 0) {
free(dev); free(dev);
return; return NULL;
} }
event_add_readfd(NULL, dev->fd, pic_read_cb, dev); dev->read_event = event_add_readfd(NULL, dev->fd, pic_read_cb, dev);
g_dev = dev; // HACK
if (lcd != NULL) {
lcd_addpage_cb(lcd, 190, lcdpage_case, dev);
} }
void pic_exit(void) pic_set_fanspeed(dev, PIC_CMD_FANSPEED_1);
pic_set_status_led(dev, PIC_CMD_STATUSLED_GREENON);
return dev;
}
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);
} }

64
pic.h Normal file
View File

@ -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_ */

View File

@ -8,8 +8,6 @@
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include "logging.h"
int pidfile_create(const char *filename) int pidfile_create(const char *filename)
{ {
int fd = open(filename, O_CREAT | O_EXCL | O_RDWR, 0644); int fd = open(filename, O_CREAT | O_EXCL | O_RDWR, 0644);

169
qnapd.c
View File

@ -22,31 +22,21 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <getopt.h> #include <getopt.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/utsname.h> #include <signal.h>
#include <time.h>
#include "configfile.h" #include "configfile.h"
#include "disktimeout.h" #include "disktimeout.h"
#include "event.h" #include "event.h"
#include "lcd.h" #include "lcd.h"
#include "logging.h" #include "logging.h"
#include "pic.h"
#include "pidfile.h" #include "pidfile.h"
#include "signals.h" #include "signals.h"
void pic_init(void); #define DEFAULT_CONFIG "qnapd.conf"
void pic_exit(void); #define DEFAULT_LOGFILE "qnapd.log"
#define DEFAULT_PIDFILE "qnapd.pid"
#define LCD_DEVICE "/dev/ttyS0"
#define LCD_TIMEOUT 15
#define DEFAULT_CONFIG PROGNAME".conf"
#define DEFAULT_LOGFILE PROGNAME".log"
#define DEFAULT_PIDFILE PROGNAME".pid"
static struct option opts[] = { static struct option opts[] = {
{ "config", 1, 0, 'c' }, { "config", 1, 0, 'c' },
@ -55,110 +45,17 @@ static struct option opts[] = {
{ 0, 0, 0, 0 } { 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, "<unknown system>");
}
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 int restart_var;
static void trigger_restart(void *privdata) static void trigger_restart(void *privdata)
{ {
int *restart = (int *)privdata; restart_var = 1;
*restart = 1;
} }
int check_restart(int *maxfd, void *readfds, void *writefds, struct timeval *timeout, void *privdata) int check_restart(int *maxfd, void *readfds, void *writefds, struct timeval *timeout, void *privdata)
{ {
int *restart = (int *)privdata; if (restart_var == 1) {
if (*restart == 1) { restart_var = 0;
*restart = 0;
return 1; return 1;
} }
@ -183,7 +80,7 @@ int main(int argc, char *argv[])
break; break;
case 'h': /* help */ case 'h': /* help */
printf("Usage: "PROGNAME" [options]\n" printf("Usage: qnapd [options]\n"
"Options: \n" "Options: \n"
" --config -c configfile use this configfile\n" " --config -c configfile use this configfile\n"
" --debug -d do not fork and log to stderr\n" " --debug -d do not fork and log to stderr\n"
@ -209,7 +106,7 @@ int main(int argc, char *argv[])
/* check pidfile */ /* check pidfile */
const char *pidfile = config_get_string("global", "pidfile", DEFAULT_PIDFILE); const char *pidfile = config_get_string("global", "pidfile", DEFAULT_PIDFILE);
if (pidfile_check(pidfile, 1) != 0) { if (pidfile_check(pidfile, 1) != 0) {
log_print(LOG_ERROR, PROGNAME" already running"); log_print(LOG_ERROR, "qnapd already running");
exit(1); exit(1);
} }
@ -218,7 +115,7 @@ int main(int argc, char *argv[])
if (log_init(logfile) < 0) if (log_init(logfile) < 0)
exit(1); exit(1);
/* zum daemon mutieren */ /* mutate to daemon */
if (daemon(-1, 0) < 0) { if (daemon(-1, 0) < 0) {
log_print(LOG_ERROR, "failed to daemonize"); log_print(LOG_ERROR, "failed to daemonize");
exit(1); exit(1);
@ -232,34 +129,52 @@ int main(int argc, char *argv[])
} }
signal_init(); 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) { while (1) {
struct lcddev *lcd = NULL;
struct picdev *pic = NULL;
const char *lcddevice = config_get_string("global", "lcddevice", NULL); do {
struct lcddev *dev = NULL; const char *devicename = config_get_string("global", "lcddevice", NULL);
if (lcddevice != NULL) { if (devicename != NULL) {
dev = lcd_open(lcddevice, &button_callback, NULL); lcd = lcd_open(devicename);
if (dev == NULL) if (lcd == NULL) {
break; break;
} }
pic_init(); 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) if (disktimeout_init() < 0)
break; break;
/* exited on restart / SIGUSR1 */ /* exited on restart / SIGUSR1 */
event_loop(check_restart, NULL, (void *)&restart_var); event_loop(check_restart, NULL, NULL);
} while (0);
disktimeout_exit(); disktimeout_exit();
pic_exit(); if (pic != NULL) {
pic_close(pic);
}
if (dev != NULL) if (lcd != NULL) {
lcd_close(dev); lcdpage_free();
lcd_close(lcd);
}
config_free(); config_free();
@ -270,7 +185,7 @@ int main(int argc, char *argv[])
if (!debug && log_init(logfile) < 0) if (!debug && log_init(logfile) < 0)
break; break;
log_print(LOG_EVERYTIME, PROGNAME" restarted (pid:%d) ", getpid()); log_print(LOG_EVERYTIME, "qnapd restarted (pid:%d) ", getpid());
} }
return 0; return 0;

View File

@ -1,6 +1,8 @@
[global] [global]
#lcddevice /dev/ttyS0 #lcddevice /dev/ttyS0
#picdevice /dev/ttyS1
#lcddevice dummy #lcddevice dummy
pidfile qnapd.pid pidfile qnapd.pid