Files
lcdproc/server/driver.c
T

548 lines
13 KiB
C
Raw Normal View History

2001-12-30 00:15:25 +00:00
/*
* driver.c
* This file is part of LCDd, the lcdproc server.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2001, Joris Robijn
*
*
* This code does all actions on the driver object.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
2003-07-20 00:55:54 +00:00
#ifndef WIN32
# include <sys/errno.h>
# include <dlfcn.h>
2003-07-20 00:55:54 +00:00
#else
# include <windows.h>
2003-07-20 00:55:54 +00:00
#endif
#include <string.h>
2001-12-30 00:15:25 +00:00
#ifdef HAVE_CONFIG_H
# include "config.h"
2001-12-30 00:15:25 +00:00
#endif
#include "main.h" /* for timer */
2001-12-30 00:15:25 +00:00
#include "shared/report.h"
2002-06-29 16:37:18 +00:00
#include "shared/configfile.h"
2001-12-30 00:15:25 +00:00
#include "widget.h"
2001-12-30 00:15:25 +00:00
#include "driver.h"
#include "drivers.h"
#include "drivers/lcd.h"
/* lcd.h is used for the driver API definition */
2002-02-21 22:50:12 +00:00
typedef struct driver_symbols {
2007-04-02 21:29:53 +00:00
const char *name;
2002-02-21 22:50:12 +00:00
short offset; /* offset in Driver structure */
short required;
} DriverSymbols;
DriverSymbols driver_symbols[] = {
2007-04-02 21:29:53 +00:00
{ "api_version", offsetof(Driver, api_version), 1 },
2002-02-21 22:50:12 +00:00
{ "stay_in_foreground", offsetof(Driver, stay_in_foreground), 1 },
2007-04-02 21:29:53 +00:00
{ "supports_multiple", offsetof(Driver, supports_multiple), 1 },
{ "symbol_prefix", offsetof(Driver, symbol_prefix), 1 },
{ "init", offsetof(Driver, init), 1 },
{ "close", offsetof(Driver, close), 1 },
{ "width", offsetof(Driver, width), 0 },
{ "height", offsetof(Driver, height), 0 },
{ "clear", offsetof(Driver, clear), 0 },
{ "flush", offsetof(Driver, flush), 0 },
{ "string", offsetof(Driver, string), 0 },
{ "chr", offsetof(Driver, chr), 0 },
{ "vbar", offsetof(Driver, vbar), 0 },
{ "hbar", offsetof(Driver, hbar), 0 },
{ "num", offsetof(Driver, num), 0 },
{ "heartbeat", offsetof(Driver, heartbeat), 0 },
{ "icon", offsetof(Driver, icon), 0 },
{ "cursor", offsetof(Driver, cursor), 0 },
{ "set_char", offsetof(Driver, set_char), 0 },
{ "get_free_chars", offsetof(Driver, get_free_chars), 0 },
{ "cellwidth", offsetof(Driver, cellwidth), 0 },
{ "cellheight", offsetof(Driver, cellheight), 0 },
{ "get_contrast", offsetof(Driver, get_contrast), 0 },
{ "set_contrast", offsetof(Driver, set_contrast), 0 },
{ "get_brightness", offsetof(Driver, get_brightness), 0 },
{ "set_brightness", offsetof(Driver, set_brightness), 0 },
{ "backlight", offsetof(Driver, backlight), 0 },
{ "output", offsetof(Driver, output), 0 },
{ "get_key", offsetof(Driver, get_key), 0 },
{ "get_info", offsetof(Driver, get_info), 0 },
2002-02-21 22:50:12 +00:00
{ NULL, 0, 0 }
};
2001-12-30 00:15:25 +00:00
/* Functions for the driver */
2007-04-02 21:29:53 +00:00
static int request_display_width(void);
static int request_display_height(void);
static int driver_store_private_ptr(Driver *driver, void *private_data);
2001-12-30 00:15:25 +00:00
Driver *
2007-04-02 21:29:53 +00:00
driver_load(const char *name, const char *filename)
2001-12-30 00:15:25 +00:00
{
2007-04-02 21:29:53 +00:00
Driver *driver = NULL;
2001-12-30 00:15:25 +00:00
int res;
2007-04-02 21:29:53 +00:00
report(RPT_DEBUG, "%s(name=\"%.40s\", filename=\"%.80s\")", __FUNCTION__, name, filename);
2001-12-30 00:15:25 +00:00
/* Allocate memory for new driver struct */
2007-04-02 21:29:53 +00:00
driver = malloc(sizeof(Driver));
memset(driver, 0, sizeof(Driver));
2001-12-30 00:15:25 +00:00
/* And store its name and filename */
2007-04-02 21:29:53 +00:00
driver->name = malloc(strlen(name) + 1);
strcpy(driver->name, name);
driver->filename = malloc(strlen(filename) + 1);
strcpy(driver->filename, filename);
2001-12-30 00:15:25 +00:00
2002-02-21 22:50:12 +00:00
/* Load and bind the driver module and locate the symbols */
2007-04-02 21:29:53 +00:00
if (driver_bind_module(driver) < 0) {
report(RPT_ERR, "Driver [%.40s] binding failed", name);
free(driver->name);
free(driver->filename);
free(driver);
2001-12-30 00:15:25 +00:00
return NULL;
}
2002-02-21 22:50:12 +00:00
/* Check module version */
2007-04-02 21:29:53 +00:00
if (strcmp(*(driver->api_version), API_VERSION) != 0) {
report(RPT_ERR, "Driver [%.40s] is of an incompatible version", name);
driver_unbind_module(driver);
free(driver->name);
free(driver->filename);
free(driver);
2001-12-30 00:15:25 +00:00
return NULL;
}
2002-02-21 22:50:12 +00:00
/* Call the init function */
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s: Calling driver [%.40s] init function", __FUNCTION__, driver->name);
res = driver->init(driver);
if (res < 0) {
report(RPT_ERR, "Driver [%.40s] init failed, return code < 0", driver->name);
2002-02-21 22:50:12 +00:00
/* Driver load failed, driver should not be added to list
* Free driver structure again
*/
2007-04-02 21:29:53 +00:00
driver_unbind_module(driver);
free(driver->name);
free(driver->filename);
free(driver);
2002-02-21 22:50:12 +00:00
return NULL;
}
2007-04-02 21:29:53 +00:00
debug(RPT_NOTICE, "Driver [%.40s] loaded", driver->name);
2001-12-30 00:15:25 +00:00
return driver;
}
int
2007-04-02 21:29:53 +00:00
driver_unload(Driver *driver)
2001-12-30 00:15:25 +00:00
{
2007-04-02 21:29:53 +00:00
debug(RPT_NOTICE, "Closing driver [%.40s]", driver->name);
if (driver->close)
driver->close(driver);
2001-12-30 00:15:25 +00:00
2002-02-21 22:50:12 +00:00
/* Unlaod the module */
2007-04-02 21:29:53 +00:00
driver_unbind_module(driver);
2001-12-30 00:15:25 +00:00
/* Free its data */
2007-04-02 21:29:53 +00:00
free(driver->filename);
free(driver->name);
free(driver);
debug(RPT_DEBUG, "%s: Driver unloaded", __FUNCTION__);
2001-12-30 00:15:25 +00:00
return 0;
}
int
2007-04-02 21:29:53 +00:00
driver_bind_module(Driver *driver)
2001-12-30 00:15:25 +00:00
{
2002-02-21 22:50:12 +00:00
int i;
int missing_symbols = 0;
2001-12-30 00:15:25 +00:00
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s(driver=[%.40s])", __FUNCTION__, driver->name);
2002-02-21 22:50:12 +00:00
/* Load the module */
2003-07-20 00:55:54 +00:00
#ifndef WIN32
2007-04-02 21:29:53 +00:00
driver->module_handle = dlopen(driver->filename, RTLD_NOW);
2003-07-20 00:55:54 +00:00
#else
2007-04-02 21:29:53 +00:00
driver->module_handle = LoadLibraryEx((driver->filename), NULL, 0);
2003-07-20 00:55:54 +00:00
#endif
2007-04-02 21:29:53 +00:00
if (driver->module_handle == NULL) {
2003-07-20 00:55:54 +00:00
#ifndef WIN32
2007-04-02 21:29:53 +00:00
report(RPT_ERR, "Could not open driver module %.40s: %s", driver->filename, dlerror());
2003-07-20 00:55:54 +00:00
#else
/* REVISIT: replace dlerror() */
2007-04-02 21:29:53 +00:00
report(RPT_ERR, "Could not open driver module %.40s.", driver->filename);
2003-07-20 00:55:54 +00:00
#endif
2002-02-21 22:50:12 +00:00
return -1;
}
2001-12-30 00:15:25 +00:00
2002-02-21 22:50:12 +00:00
/* And locate the symbols */
2007-04-02 21:29:53 +00:00
for (i = 0; driver_symbols[i].name; i++) {
2002-02-21 22:50:12 +00:00
void (**p)();
2007-04-02 21:29:53 +00:00
p = (void(**)()) ((size_t)driver + (driver_symbols[i].offset));
2002-02-21 22:50:12 +00:00
*p = NULL;
/* Add the symbol_prefix */
2007-04-02 21:29:53 +00:00
if (driver->symbol_prefix) {
char *s = malloc(strlen(*(driver->symbol_prefix)) + strlen(driver_symbols[i].name) + 1);
strcpy(s, *(driver->symbol_prefix));
strcat(s, driver_symbols[i].name);
debug(RPT_DEBUG, "%s: finding symbol: %s", __FUNCTION__, s);
2003-07-20 00:55:54 +00:00
#ifndef WIN32
2007-04-02 21:29:53 +00:00
*p = dlsym(driver->module_handle, s);
2003-07-20 00:55:54 +00:00
#else
2007-04-02 21:29:53 +00:00
*p = (void(*)()) (GetProcAddress(driver->module_handle, s));
2003-07-20 00:55:54 +00:00
#endif
2007-04-02 21:29:53 +00:00
free(s);
2002-02-21 22:50:12 +00:00
}
/* Retrieve the symbol */
2007-04-02 21:29:53 +00:00
if (!*p) {
debug(RPT_DEBUG, "%s: finding symbol: %s", __FUNCTION__, driver_symbols[i].name);
2003-07-20 00:55:54 +00:00
#ifndef WIN32
2007-04-02 21:29:53 +00:00
*p = dlsym(driver->module_handle, driver_symbols[i].name);
2003-07-20 00:55:54 +00:00
#else
2007-04-02 21:29:53 +00:00
*p = (void(*)()) (GetProcAddress(driver->module_handle, driver_symbols[i].name));
2003-07-20 00:55:54 +00:00
#endif
2002-02-21 22:50:12 +00:00
}
2007-04-02 21:29:53 +00:00
if (*p) {
debug(RPT_DEBUG, "%s: found symbol at: %p", __FUNCTION__, *p);
2002-02-21 22:50:12 +00:00
}
/* Was the symbol required but not found ? */
2007-04-02 21:29:53 +00:00
if (!*p && driver_symbols[i].required) {
report(RPT_ERR, "Driver [%.40s] does not have required symbol: %s", driver->name, driver_symbols[i].name);
2002-02-21 22:50:12 +00:00
missing_symbols = 1;
}
}
/* If errors, leave now while we can :) */
2007-04-02 21:29:53 +00:00
if (missing_symbols) {
report(RPT_ERR, "Driver [%.40s] does not have all obligatory symbols", driver->name);
2003-07-20 00:55:54 +00:00
#ifndef WIN32
2007-04-02 21:29:53 +00:00
dlclose(driver->module_handle);
2003-07-20 00:55:54 +00:00
#else
2007-04-02 21:29:53 +00:00
FreeLibrary(driver->module_handle);
2003-07-20 00:55:54 +00:00
#endif
2002-02-21 22:50:12 +00:00
return -1;
}
2001-12-30 00:15:25 +00:00
/* Add our exported functions */
/* Config file functions */
driver->config_get_bool = config_get_bool;
driver->config_get_int = config_get_int;
driver->config_get_float = config_get_float;
driver->config_get_string = config_get_string;
driver->config_has_section = config_has_section;
driver->config_has_key = config_has_key;
/* Reporting */
driver->report = report;
/* Driver private data */
driver->store_private_ptr = driver_store_private_ptr;
/* Display size request */
driver->request_display_width = request_display_width;
driver->request_display_height = request_display_height;
return 0;
}
int
2007-04-02 21:29:53 +00:00
driver_unbind_module(Driver *driver)
2001-12-30 00:15:25 +00:00
{
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s(driver=[%.40s])", __FUNCTION__, driver->name);
2003-07-20 00:55:54 +00:00
#ifndef WIN32
2007-04-02 21:29:53 +00:00
dlclose(driver->module_handle);
2003-07-20 00:55:54 +00:00
#else
2007-04-02 21:29:53 +00:00
FreeLibrary(driver->module_handle);
2003-07-20 00:55:54 +00:00
#endif
2002-02-21 22:50:12 +00:00
2001-12-30 00:15:25 +00:00
return 0;
}
bool
2007-04-02 21:29:53 +00:00
driver_does_output(Driver *driver)
2001-12-30 00:15:25 +00:00
{
return (driver->width != NULL
|| driver->height != NULL
|| driver->clear != NULL
|| driver->string != NULL
|| driver->chr != NULL) ? 1 : 0;
2001-12-30 00:15:25 +00:00
}
bool
2007-04-02 21:29:53 +00:00
driver_does_input(Driver *driver)
2001-12-30 00:15:25 +00:00
{
return (driver->get_key != NULL) ? 1 : 0;
2001-12-30 00:15:25 +00:00
}
bool
2007-04-02 21:29:53 +00:00
driver_stay_in_foreground(Driver *driver)
2001-12-30 00:15:25 +00:00
{
return *driver->stay_in_foreground;
}
bool
2007-04-02 21:29:53 +00:00
driver_supports_multiple(Driver *driver)
2001-12-30 00:15:25 +00:00
{
return *driver->supports_multiple;
}
static int
2007-04-02 21:29:53 +00:00
driver_store_private_ptr(Driver *driver, void *private_data)
2001-12-30 00:15:25 +00:00
{
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s(driver=[%.40s], ptr=%p)", __FUNCTION__, driver->name, private_data);
2001-12-30 00:15:25 +00:00
driver->private_data = private_data;
return 0;
}
static int
2007-04-02 21:29:53 +00:00
request_display_width(void)
2001-12-30 00:15:25 +00:00
{
2007-04-02 21:29:53 +00:00
if (!display_props)
2001-12-30 00:15:25 +00:00
return 0;
return display_props->width;
}
static int
2007-04-02 21:29:53 +00:00
request_display_height(void)
2001-12-30 00:15:25 +00:00
{
2007-04-02 21:29:53 +00:00
if (!display_props)
2001-12-30 00:15:25 +00:00
return 0;
return display_props->height;
}
void
2007-04-02 21:29:53 +00:00
driver_alt_vbar(Driver *drv, int x, int y, int len, int promille, int pattern)
{
int pos;
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)", __FUNCTION__, drv->name, x, y, len, promille, pattern);
if (!drv->chr)
return;
2007-04-02 21:29:53 +00:00
for (pos = 0; pos < len; pos++) {
if (2 * pos < ((long) promille * len / 500 + 1)) {
drv->chr(drv, x, y-pos, '|');
} else {
; /* print nothing */
}
}
}
void
2007-04-02 21:29:53 +00:00
driver_alt_hbar(Driver *drv, int x, int y, int len, int promille, int pattern)
{
int pos;
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)", __FUNCTION__, drv->name, x, y, len, promille, pattern);
if (!drv->chr)
return;
2007-04-02 21:29:53 +00:00
for (pos = 0; pos < len; pos++) {
if (2 * pos < ((long) promille * len / 500 + 1)) {
drv->chr(drv, x+pos, y, '-');
} else {
; /* print nothing */
}
}
}
void
2007-04-02 21:29:53 +00:00
driver_alt_num(Driver *drv, int x, int num)
{
/* Ugly code extracted by David GLAUDE from lcdm001.c ;)*/
/* Moved to driver.c by Joris Robijn */
static char num_map[][4][4] = {
{ /* 0 */
" _ ",
"| |",
"|_|",
" " },
{ /* 1 */
" ",
" |",
" |",
" " },
{ /* 2 */
" _ ",
" _|",
"|_ ",
" " },
{ /* 3 */
" _ ",
" _|",
" _|",
" " },
{ /* 4 */
" ",
"|_|",
" |",
" " },
{ /* 5 */
" _ ",
"|_ ",
" _|",
" " },
{ /* 6 */
" _ ",
"|_ ",
"|_|",
" " },
{ /* 7 */
" _ ",
" |",
" |",
" " },
{ /* 8 */
" _ ",
"|_|",
"|_|",
" " },
{ /* 9 */
" _ ",
"|_|",
" _|",
" " },
{ /* colon */
" ",
".",
".",
" " }
};
/* End of ugly code ;) by Rene Wagner */
/* I like this code ! Joris */
int y, dx;
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, num=%d)", __FUNCTION__, drv->name, x, num);
if ((num < 0) || (num > 10))
return;
if (!drv->chr)
return;
for (y = 0; y < 4; y++)
for (dx = 0; num_map[num][y][dx] != '\0'; dx++)
2007-04-02 21:29:53 +00:00
drv->chr(drv, x + dx, y+1, num_map[num][y][dx]);
}
void
2007-04-02 21:29:53 +00:00
driver_alt_heartbeat(Driver *drv, int state)
{
int icon;
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s(drv=[%.40s], state=%d)", __FUNCTION__, drv->name, state);
if (state == HEARTBEAT_OFF)
return;
/* Don't display anything */
if (!drv->width)
return;
/* Hmm, is this a good method ?
* Or should we use clock() ? Or ftime ? Or gettimeofday ?
*/
icon = (timer & 5) ? ICON_HEART_FILLED : ICON_HEART_OPEN;
if (drv->icon)
2007-04-02 21:29:53 +00:00
drv->icon(drv, drv->width(drv), 1, icon);
else
2007-04-02 21:29:53 +00:00
driver_alt_icon(drv, drv->width(drv), 1, icon);
}
void
2007-04-02 21:29:53 +00:00
driver_alt_icon(Driver *drv, int x, int y, int icon)
{
2002-05-18 23:42:46 +00:00
char ch1 = '?';
2007-04-02 21:29:53 +00:00
char ch2 = '\0';
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, icon=ICON_%s)", __FUNCTION__, drv->name, x, y, widget_icon_to_iconname(icon));
if (!drv->chr)
return;
switch (icon) {
2002-05-18 23:42:46 +00:00
case ICON_BLOCK_FILLED: ch1 = '#'; break;
case ICON_HEART_OPEN: ch1 = '-'; break;
case ICON_HEART_FILLED: ch1 = '#'; break;
case ICON_ARROW_UP: ch1 = '^'; break;
case ICON_ARROW_DOWN: ch1 = 'v'; break;
case ICON_ARROW_LEFT: ch1 = '<'; break;
case ICON_ARROW_RIGHT: ch1 = '>'; break;
2002-05-23 18:03:36 +00:00
case ICON_CHECKBOX_OFF: ch1 = 'N'; break;
case ICON_CHECKBOX_ON: ch1 = 'Y'; break;
case ICON_CHECKBOX_GRAY: ch1 = 'o'; break;
case ICON_SELECTOR_AT_LEFT: ch1 = '>'; break;
case ICON_SELECTOR_AT_RIGHT: ch1 = '<'; break;
case ICON_ELLIPSIS: ch1 = '_'; break;
2002-05-18 23:42:46 +00:00
case ICON_STOP: ch1 = '['; ch2 = ']'; break;
case ICON_PAUSE: ch1 = '|'; ch2 = '|'; break;
case ICON_PLAY: ch1 = '>'; ch2 = ' '; break;
case ICON_PLAYR: ch1 = '<'; ch2 = ' '; break;
case ICON_FF: ch1 = '>'; ch2 = '>'; break;
case ICON_FR: ch1 = '<'; ch2 = '<'; break;
case ICON_NEXT: ch1 = '>'; ch2 = '|'; break;
case ICON_PREV: ch1 = '|'; ch2 = '<'; break;
case ICON_REC: ch1 = '('; ch2 = ')'; break;
}
2007-04-02 21:29:53 +00:00
drv->chr(drv, x, y, ch1);
2002-05-18 23:42:46 +00:00
if (ch2)
2007-04-02 21:29:53 +00:00
drv->chr(drv, x+1, y, ch2);
}
2007-04-02 21:29:53 +00:00
void driver_alt_cursor(Driver *drv, int x, int y, int state)
{
/* Same question about timer in this function... */
2007-04-02 21:29:53 +00:00
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, state=%d)", __FUNCTION__, drv->name, x, y, state);
2007-04-02 21:29:53 +00:00
switch (state) {
case CURSOR_BLOCK:
case CURSOR_DEFAULT_ON:
2002-05-26 19:21:23 +00:00
if (timer & 2 && drv->chr) {
if (drv->icon) {
2007-04-02 21:29:53 +00:00
drv->icon(drv, x, y, ICON_BLOCK_FILLED);
2002-05-26 19:21:23 +00:00
} else {
2007-04-02 21:29:53 +00:00
driver_alt_icon(drv, x, y, ICON_BLOCK_FILLED);
2002-05-26 19:21:23 +00:00
}
}
break;
case CURSOR_UNDER:
2002-05-26 19:21:23 +00:00
if (timer & 2 && drv->chr) {
2007-04-02 21:29:53 +00:00
drv->chr(drv, x, y, '_');
2002-05-26 19:21:23 +00:00
}
break;
}
}