work work
This commit is contained in:
parent
86e94cce91
commit
031b7e540d
240
lcd.c
240
lcd.c
@ -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
33
lcd.h
@ -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
225
lcdpage.c
Normal 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
196
pic.c
@ -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
64
pic.h
Normal 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_ */
|
@ -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
169
qnapd.c
@ -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;
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user