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 "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_pagecallback(dev, LCDPAGE_EVENT_BACKLIGHT);
if (dev->backlight_timeout == NULL) {
lcd_backlight(dev, 0);
dev->event_callback(dev, LCD_EVENT_BACKLIGHT, dev->event_privdata);
}
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)) {
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);
}
} else {
if (dev->scroll_timeout != NULL) {
event_remove_timeout(dev->scroll_timeout);
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;
}
struct lcddev * lcd_open(const char *devicename,
int (*event_callback)(struct lcddev *dev, int button, void *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);

33
lcd.h
View File

@ -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,
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),
void *event_privdata);
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 timeout);
int lcd_setlines(struct lcddev *dev, int scrollspeed, const char *line1, const char *line2);
int lcdpage_init(struct lcddev *dev);
void lcdpage_free(void);
#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 "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);
}

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 <signal.h>
#include "logging.h"
int pidfile_create(const char *filename)
{
int fd = open(filename, O_CREAT | O_EXCL | O_RDWR, 0644);

177
qnapd.c
View File

@ -22,143 +22,40 @@
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/utsname.h>
#include <time.h>
#include <signal.h>
#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, "<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 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;
if (restart_var == 1) {
restart_var = 0;
return 1;
}
@ -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;
}
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)
break;
/* exited on restart / SIGUSR1 */
event_loop(check_restart, NULL, (void *)&restart_var);
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;

View File

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