Files
g15daemon/g15daemon/utility_funcs.c
T

689 lines
19 KiB
C

/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006-2008 Mike Lampard, Philip Lawatsch, and others
$Revision: 449 $ - $Date: 2008-01-24 17:42:07 +1030 (Thu, 24 Jan 2008) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <ctype.h>
#include <sys/time.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "g15daemon.h"
#include <libg15.h>
#include <stdarg.h>
#include <libg15render.h>
extern unsigned int g15daemon_debug;
extern volatile int leaving;
#define G15DAEMON_PIDFILE "/var/run/g15daemon.pid"
pthread_cond_t lcd_refresh = PTHREAD_COND_INITIALIZER;
/* if no exitfunc or eventhandler, member should be NULL */
const plugin_info_t generic_info[] = {
/* TYPE, name, initfunc, updatefreq, exitfunc, eventhandler */
{G15_PLUGIN_LCD_CLIENT, "BackwardCompatible", NULL, 0, NULL, (void*)internal_generic_eventhandler},
{G15_PLUGIN_NONE, "" , NULL, 0, NULL, NULL}
};
/* handy function from xine_utils.c */
void *g15daemon_xmalloc(size_t size) {
void *ptr;
/* prevent xmalloc(0) of possibly returning NULL */
if( !size )
size++;
if((ptr = calloc(1, size)) == NULL) {
g15daemon_log(LOG_WARNING, "g15_xmalloc() failed: %s.\n", strerror(errno));
return NULL;
}
return ptr;
}
static int refresh_pending=0;
void g15daemon_init_refresh() {
pthread_condattr_t attr;
pthread_cond_init(&lcd_refresh, &attr);
}
void g15daemon_send_refresh(lcd_t *lcd) {
if(lcd==lcd->masterlist->current->lcd||lcd->state_changed) {
pthread_cond_broadcast(&lcd_refresh);
refresh_pending++;
}
}
void g15daemon_wait_refresh() {
pthread_mutex_t dummy_mutex;
struct timespec timeout;
int retval;
if(refresh_pending<1) {
/* Create a dummy mutex which doesn't unlock for sure while waiting. */
pthread_mutex_init(&dummy_mutex, NULL);
pthread_mutex_lock(&dummy_mutex);
start:
time(&timeout.tv_sec);
timeout.tv_sec += 1;
timeout.tv_nsec = 0L;
retval=pthread_cond_timedwait(&lcd_refresh, &dummy_mutex, &timeout);
if(!leaving && retval == ETIMEDOUT)
goto start;
pthread_mutex_unlock(&dummy_mutex);
pthread_mutex_destroy(&dummy_mutex);
}
refresh_pending--;
}
void g15daemon_quit_refresh() {
pthread_cond_destroy(&lcd_refresh);
}
int uf_return_running(){
int fd;
char pidtxt[128];
int pid;
int l;
if ((fd = open(G15DAEMON_PIDFILE, O_RDWR, 0644)) < 0) {
return -1;
}
if((l = read(fd,pidtxt,sizeof(pidtxt)-1)) < 0) {
unlink (G15DAEMON_PIDFILE);
close(fd);
return -1;
}
if((pid = atoi(pidtxt)) <= 0) {
g15daemon_log(LOG_ERR,"pidfile corrupt");
unlink(G15DAEMON_PIDFILE);
close(fd);
return -1;
}
if((kill(pid,0) != 0) && errno != EPERM ) {
g15daemon_log(LOG_ERR,"Process died - removing pidfile");
unlink(G15DAEMON_PIDFILE);
close(fd);
return -1;
}
return pid;
}
int uf_create_pidfile() {
char pidtxt[128];
size_t l;
int fd;
if(!uf_return_running() && (fd = open(G15DAEMON_PIDFILE, O_CREAT|O_RDWR|O_EXCL, 0644)) < 0) {
g15daemon_log(LOG_ERR,"previous G15Daemon process died. removing pidfile");
unlink(G15DAEMON_PIDFILE);
}
if ((fd = open(G15DAEMON_PIDFILE, O_CREAT|O_RDWR|O_EXCL, 0644)) < 0) {
return 1;
}
snprintf(pidtxt, sizeof(pidtxt), "%lu\n", (unsigned long) getpid());
if (write(fd, pidtxt, l = strlen(pidtxt)) != l) {
g15daemon_log(LOG_WARNING, "write(): %s", strerror(errno));
unlink(G15DAEMON_PIDFILE);
}
if(fd>0) {
close(fd);
return 0;
}
return 1;
}
/* syslog wrapper */
int g15daemon_log (int priority, const char *fmt, ...) {
va_list argp;
va_start (argp, fmt);
int real_prio=0;
switch(g15daemon_debug) {
case 0:
case 1:
real_prio = LOG_WARNING;
break;
case 2:
real_prio = LOG_INFO;
break;
default:
real_prio = LOG_DEBUG;
}
if(real_prio>=priority) {
if(g15daemon_debug == 0) {
vsyslog(priority, fmt, argp);
} else {
vfprintf(stderr,fmt,argp);
fprintf(stderr,"\n");
}
}
va_end (argp);
return 0;
}
/* takes a 6880 byte (1byte==1pixel) buffer and packs it into libg15 format. */
void g15daemon_convert_buf(lcd_t *lcd, unsigned char * orig_buf)
{
unsigned int x,y,val;
for(x=0;x<160;x++)
for(y=0;y<43;y++)
{
unsigned int pixel_offset = y * LCD_WIDTH + x;
unsigned int byte_offset = pixel_offset / 8;
unsigned int bit_offset = 7-(pixel_offset % 8);
val = orig_buf[x+(y*160)];
if (val)
lcd->buf[byte_offset] = lcd->buf[byte_offset] | 1 << bit_offset;
else
lcd->buf[byte_offset] = lcd->buf[byte_offset] & ~(1 << bit_offset);
}
}
/* wrap the libg15 functions */
int uf_write_buf_to_g15(lcd_t *lcd)
{
int retval = 0;
#ifdef LIBUSB_BLOCKS
retval = writePixmapToLCD(lcd->buf);
#else
pthread_mutex_lock(&g15lib_mutex);
retval = writePixmapToLCD(lcd->buf);
pthread_mutex_unlock(&g15lib_mutex);
#endif
return retval;
}
int uf_read_keypresses(unsigned int *keypresses, unsigned int timeout)
{
int retval=0;
#ifdef LIBUSB_BLOCKS
retval = getPressedKeys(keypresses, timeout);
#else
pthread_mutex_lock(&g15lib_mutex);
retval = getPressedKeys(keypresses, timeout);
pthread_mutex_unlock(&g15lib_mutex);
#endif
return retval;
}
/* Sleep routine (hackish). */
void g15daemon_sleep(int seconds) {
pthread_mutex_t dummy_mutex;
static pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER;
struct timespec timeout;
/* Create a dummy mutex which doesn't unlock for sure while waiting. */
pthread_mutex_init(&dummy_mutex, NULL);
pthread_mutex_lock(&dummy_mutex);
timeout.tv_sec = time(NULL) + seconds;
timeout.tv_nsec = 0;
pthread_cond_timedwait(&dummy_cond, &dummy_mutex, &timeout);
/* pthread_cond_destroy(&dummy_cond); */
pthread_mutex_unlock(&dummy_mutex);
pthread_mutex_destroy(&dummy_mutex);
}
/* microsecond sleep routine. */
int g15daemon_usleep(int useconds) {
struct timeval timeout;
if(useconds < 10000)
useconds = 10000;
timeout.tv_sec = useconds / 1000000;
timeout.tv_usec = useconds % 1000000;
return select (0,0,0,0,&timeout);
}
/* millisecond sleep routine. */
int g15daemon_msleep(int milliseconds) {
return g15daemon_usleep(milliseconds*1000);
}
unsigned int g15daemon_gettime_ms(){
struct timeval tv;
gettimeofday(&tv,NULL);
return (tv.tv_sec*1000+tv.tv_usec/1000);
}
/* generic event handler used unless overridden (only loading a plugin will override currently)*/
int internal_generic_eventhandler(plugin_event_t *event) {
lcd_t *lcd = (lcd_t*) event->lcd;
switch (event->event)
{
case G15_EVENT_KEYPRESS: {
if(lcd->g15plugin->plugin_handle){ /* loadable plugin */
/* plugin had null for eventhandler therefore doesnt want events.. throw them away */
}
}
break;
case G15_EVENT_VISIBILITY_CHANGED:
break;
default:
break;
}
return G15_PLUGIN_OK;
}
/* free all memory used by the config subsystem */
void uf_conf_free(g15daemon_t *list)
{
config_section_t *section=list->config->sections;
config_items_t *tmpitem=NULL;
config_section_t *tmpsection=section;
while(tmpsection!=NULL){
tmpitem=section->items;
if(section->sectionname){
free(section->sectionname);
while(section->items!=NULL){
if(tmpitem->key!=NULL)
free(tmpitem->key);
if(tmpitem->value!=NULL)
free(tmpitem->value);
tmpitem=section->items->next;
free(section->items);
section->items=tmpitem;
}
}
tmpsection=section->next;
free(section);
section=tmpsection;
}
free(section);
free(list->config);
}
/* write the config file with all keys/sections */
int uf_conf_write(g15daemon_t *list,char *filename)
{
int config_fd=-1;
config_section_t *foo=list->config->sections;
config_items_t * item=NULL;
char line[1024];
config_fd = open(filename,O_CREAT|O_RDWR|O_TRUNC);
if(config_fd){
snprintf(line,1024,"# G15Daemon Configuration File\n# any items entered before a [section] header\n# will be in the Global config space\n# comments you wish to keep should start with a semicolon';'\n");
write(config_fd,line,strlen(line));
while(foo!=NULL){
item=foo->items;
memset(line,0,1024);
if(foo->sectionname!=NULL){
snprintf(line,1024,"\n[%s]\n",foo->sectionname);
write(config_fd,line,strlen(line));
while(item!=NULL){
memset(line,0,1024);
if(item->key!=NULL){
if(item->key[0]==';') // comment
snprintf(line,1024,"%s\n",item->key);
else
snprintf(line,1024,"%s: %s\n",item->key, item->value);
write(config_fd,line,strlen(line));
}
item=item->next;
}
}
foo=foo->next;
}
close(config_fd);
return 0;
}
return -1;
}
/* search the list for valid section name return pointer to section, or NULL otherwise */
config_section_t* uf_search_confsection(g15daemon_t *list,char *sectionname){
config_section_t *section=list->config->sections;
while(section!=NULL){
if(0==strcmp((char*)section->sectionname,(char*)sectionname))
break;
section=section->next;
}
return section;
}
/* search the list for valid key called "key" in section named "section" return pointer to item or NULL */
config_items_t* uf_search_confitem(config_section_t *section, char *key){
config_items_t * item=NULL;
if(section!=NULL){
item=section->items;
while(item!=NULL){
if(0==strcmp((char*)item->key,(char*)key))
break;
item=item->next;
}
}
return item;
}
/* return pointer to section, or create a new section if it doesnt exist */
config_section_t *g15daemon_cfg_load_section(g15daemon_t *masterlist,char *name) {
config_section_t *new = NULL;
if((new=uf_search_confsection(masterlist,name))!=NULL)
return new;
new = g15daemon_xmalloc(sizeof(config_section_t));
new->head = new;
new->next = NULL;;
new->sectionname=strdup(name);
if(!masterlist->config->sections){
masterlist->config->sections=new;
masterlist->config->sections->head = new;
} else {
masterlist->config->sections->head->next=new;
masterlist->config->sections->head = new;
}
return new;
}
/* cleanup whitespace */
char * uf_remove_whitespace(char *str){
int z=0;
if(str==NULL)
str=strdup(" ");
while(isspace(str[z])&&str[z])
z++;
str+=z;
return str;
}
/* add a new key, or update the value of an already existing key, or return -1 if section doesnt exist */
int g15daemon_cfg_write_string(config_section_t *section, char *key, char *val){
config_items_t *new = NULL;
if(section==NULL)
return -1;
if((uf_search_confitem(section, key))){
free(new);
new=uf_search_confitem(section, key);
new->value=strdup(val);
}else{
new=g15daemon_xmalloc(sizeof(config_items_t));
new->head=new;
new->next=NULL;
new->key=strdup(key);
new->value=strdup(val);
if(!section->items){
new->prev=NULL;
section->items=new;
section->items->head=new;
}else{
new->prev=section->items->head;
section->items->head->next=new;
section->items->head=new;
}
}
return 0;
}
/* remoe a key/value pair from named section */
int g15daemon_cfg_remove_key(config_section_t *section, char *key){
config_items_t *new = NULL;
config_items_t *next = NULL;
config_items_t *prev = NULL;
if(section==NULL)
return -1;
if((uf_search_confitem(section, key))){
new=uf_search_confitem(section, key);
prev=new->prev;
next=new->next;
if(prev){
prev->next=new->next;
}else{
if(!next) {
free(section->items);
section->items=NULL;
}
else
section->items=next;
}
if(new->head==new){
if(prev){
prev->head = prev;
section->items->head=prev;
}
if(!prev){
if(!next) {
free(section->items);
section->items=NULL;
}
}
}
if(next){
if(prev)
next->prev=prev;
else
next->prev=NULL;
}
free(new->key);
free(new->value);
free(new);
}
return 0;
}
int g15daemon_cfg_write_int(config_section_t *section, char *key, int val) {
char tmp[1024];
snprintf(tmp,1024,"%i",val);
return g15daemon_cfg_write_string(section, key, tmp);
}
int g15daemon_cfg_write_float(config_section_t *section, char *key, double val) {
char tmp[1024];
snprintf(tmp,1024,"%f",val);
return g15daemon_cfg_write_string(section, key, tmp);
}
/* simply write value as On or Off depending on whether val>0 */
int g15daemon_cfg_write_bool(config_section_t *section, char *key, unsigned int val) {
char tmp[1024];
snprintf(tmp,1024,"%s",val?"On":"Off");
return g15daemon_cfg_write_string(section, key, tmp);
}
/* the config read functions will either return a value from the config file, or the default value, which will be written to the config file if the key doesnt exist */
/* return bool as int from key in sectionname */
int g15daemon_cfg_read_bool(config_section_t *section, char *key, int defaultval) {
int retval=0;
config_items_t *item = uf_search_confitem(section, key);
if(item){
retval = 1^retval?(strncmp(item->value,"On",2)==0):1;
return retval;
}
g15daemon_cfg_write_bool(section, key, defaultval);
return defaultval;
}
/* return int from key in sectionname */
int g15daemon_cfg_read_int(config_section_t *section, char *key, int defaultval) {
config_items_t *item = uf_search_confitem(section, key);
if(item){
return atoi(item->value);
}
g15daemon_cfg_write_int(section, key, defaultval);
return defaultval;
}
/* return float from key in sectionname */
double g15daemon_cfg_read_float(config_section_t *section, char *key, double defaultval) {
config_items_t *item = uf_search_confitem(section, key);
if(item){
return atof(item->value);
}
g15daemon_cfg_write_float(section, key, defaultval);
return defaultval;
}
/* return string value from key in sectionname */
char* g15daemon_cfg_read_string(config_section_t *section, char *key, char *defaultval) {
config_items_t *item = uf_search_confitem(section, key);
if(item){
return item->value;
}
g15daemon_cfg_write_string(section, key, defaultval);
return defaultval;
}
int uf_conf_open(g15daemon_t *list, char *filename) {
char *buffer, *lines;
int config_fd=-1;
char *sect;
char *start;
char *bar = NULL;
int i;
struct stat stats;
list->config=g15daemon_xmalloc(sizeof(configfile_t));
list->config->sections=NULL;
if (lstat(filename, &stats) == -1)
return -1;
if (!(config_fd = open(filename, O_RDWR)))
return -1;
buffer = g15daemon_xmalloc(stats.st_size + 1);
if (read(config_fd, buffer, stats.st_size) != stats.st_size)
{
free(buffer);
close(config_fd);
return -1;
}
close(config_fd);
buffer[stats.st_size] = '\0';
lines=strtok_r(buffer,"\n",&bar);
config_section_t *section=NULL;
while(lines!=NULL){
sect=strdup(lines);
i=0;
while(isspace(sect[i])){
i++;
}
start=sect+i;
if(start[0]=='#'){
/* header - ignore */
/* comments start with ; and can be produced like so:
g15daemon_cfg_write_string(noload_cfg,"; Plugins in this section will not be loaded on start","");
the value parameter must not be used.
*/
} else if(strrchr(start,']')) { /* section title */
char sectiontitle[1024];
memset(sectiontitle,0,1024);
strncpy(sectiontitle,start+1,strlen(start)-2);
section = g15daemon_cfg_load_section(list,sectiontitle);
}else{
/*section keys */
if(section==NULL){
/* create an internal section "Global" which is the default for items not under a [section] header */
section=g15daemon_cfg_load_section(list,"Global");
}
char *foo=NULL;
char *key = uf_remove_whitespace( strtok_r(start,":=",&foo) );
char *val = uf_remove_whitespace( strtok_r(NULL,":=", &foo) );
g15daemon_cfg_write_string(section,key,val);
}
free(sect);
lines=strtok_r(NULL,"\n",&bar);
}
free(buffer);
return 0;
}
int uf_screendump_pbm(unsigned char *buffer,char *filename) {
FILE *f;
int x,y;
#define WIDTH 40
g15canvas *canvas=g15daemon_xmalloc(sizeof(g15canvas));
memcpy(canvas->buffer,buffer,LCD_BUFSIZE);
f = fopen(filename,"w+");
fprintf(f,"P1\n160 43\n");
fprintf(f,"# G15 screendump - %s\n\n",filename);
for(y=0;y<43;y++)
for(x=0;x<160;x++) {
fprintf(f,"%i",g15r_getPixel(canvas,x,y));
if(x%WIDTH==WIDTH-1)
fprintf(f,"\n");
}
fclose(f);
free(canvas);
return 0;
}