2
This file is part of g15daemon.
4
g15daemon is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
g15daemon is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with g15daemon; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
(c) 2006 Mike Lampard, Philip Lawatsch, and others
20
$Revision: 302 $ - $Date: 2007-09-10 09:57:53 +0200 (Mon, 10 Sep 2007) $ $Author: mlampard $
22
This daemon listens on localhost port 15550 for client connections,
23
and arbitrates LCD display. Allows for multiple simultaneous clients.
24
Client screens can be cycled through by pressing the 'L1' key.
33
#include <sys/types.h>
34
#include <sys/socket.h>
44
#include <libg15render.h>
45
#include "g15daemon.h"
47
#ifndef LIBG15_VERSION
48
#define LIBG15_VERSION 1000
51
/* all threads will exit if leaving >0 */
53
int keyboard_backlight_off_onexit = 0;
54
unsigned int g15daemon_debug = 0;
55
unsigned int cycle_key;
56
unsigned int client_handles_keys = 0;
57
struct lcd_t *keyhandler = NULL;
59
/* send event to foreground client's eventlistener */
60
int g15daemon_send_event(void *caller, unsigned int event, unsigned long value)
63
case G15_EVENT_KEYPRESS: {
64
static unsigned long lastkeys;
65
if(!(value & cycle_key) && !(lastkeys & cycle_key)){
66
lcd_t *lcd = (lcd_t*)caller;
67
int *(*plugin_listener)(plugin_event_t *newevent) = (void*)lcd->g15plugin->info->event_handler;
68
plugin_event_t *newevent=g15daemon_xmalloc(sizeof(plugin_event_t));
69
newevent->event = event;
70
newevent->value = value;
72
(*plugin_listener)((void*)newevent);
73
/* hack - keyboard events are always sent from the foreground even when they aren't
74
send keypress event to the OS keyboard_handler plugin */
75
if(lcd->masterlist->keyboard_handler != NULL && lcd->masterlist->remote_keyhandler_sock==0) {
76
int *(*keyboard_handler)(plugin_event_t *newevent) = (void*)lcd->masterlist->keyboard_handler;
77
(*keyboard_handler)((void*)newevent);
79
// if we have a remote keyhandler, send the key. FIXME: we should do this from the net plugin
80
if(lcd->masterlist->remote_keyhandler_sock!=0) {
81
if((send(lcd->masterlist->remote_keyhandler_sock,(void *)&newevent->value,sizeof(newevent->value),0))<0)
82
g15daemon_log(LOG_WARNING,"Error in send: %s\n",strerror(errno));
84
if(value & G15_KEY_LIGHT){ // the backlight key was pressed - maintain user-selected state
85
lcd->masterlist->kb_backlight_state++;
86
if(lcd->masterlist->kb_backlight_state>2)
87
lcd->masterlist->kb_backlight_state=0;
91
/* hacky attempt to double-time the use of L1, if the key is pressed less than half a second, it cycles the screens. If held for longer, the key is sent to the application for use instead */
92
lcd_t *lcd = (lcd_t*)caller;
93
g15daemon_t* masterlist = lcd->masterlist;
94
static unsigned int clicktime;
95
if(value & cycle_key) {
96
clicktime=g15daemon_gettime_ms();
98
unsigned int unclick=g15daemon_gettime_ms();
99
if ((unclick-clicktime)<500) {
100
g15daemon_lcdnode_cycle(masterlist);
104
plugin_event_t *clickevent=g15daemon_xmalloc(sizeof(plugin_event_t));
105
int *(*plugin_listener)(plugin_event_t *clickevent) = (void*)lcd->g15plugin->info->event_handler;
106
clickevent->event = event;
107
clickevent->value = value|cycle_key;
108
clickevent->lcd = lcd;
109
(*plugin_listener)((void*)clickevent);
110
clickevent->event = event;
111
clickevent->value = value&~cycle_key;
112
clickevent->lcd = lcd;
113
(*plugin_listener)((void*)clickevent);
121
case G15_EVENT_CYCLE_PRIORITY:{
122
lcd_t *lcd = (lcd_t*)caller;
123
g15daemon_t* masterlist = lcd->masterlist;
125
g15daemon_lcdnode_cycle(masterlist);
128
case G15_EVENT_REQ_PRIORITY: {
129
lcdnode_t *lcdnode=(lcdnode_t*)caller;
130
/* client wants to switch priorities */
131
pthread_mutex_lock(&lcdlist_mutex);
132
if(lcdnode->list->current != lcdnode){
133
lcdnode->last_priority = lcdnode->list->current;
134
lcdnode->list->current = lcdnode;
137
if(lcdnode->list->current == lcdnode->last_priority){
138
lcdnode->list->current = lcdnode->list->current->prev;
140
if(lcdnode->last_priority != NULL) {
141
lcdnode->list->current = lcdnode->last_priority;
142
lcdnode->last_priority = NULL;
145
lcdnode->list->current = lcdnode->list->current->prev;
148
pthread_mutex_unlock(&lcdlist_mutex);
152
lcd_t *lcd = (lcd_t*)caller;
153
int *(*plugin_listener)(plugin_event_t *newevent) = (void*)lcd->g15plugin->info->event_handler;
154
plugin_event_t *newevent=g15daemon_xmalloc(sizeof(plugin_event_t));
155
newevent->event = event;
156
newevent->value = value;
158
(*plugin_listener)((void*)newevent);
165
static void *keyboard_watch_thread(void *lcdlist){
167
g15daemon_t *masterlist = (g15daemon_t*)(lcdlist);
169
unsigned int keypresses = 0;
173
pthread_mutex_lock(&g15lib_mutex);
174
retval = getPressedKeys(&keypresses, 40);
175
pthread_mutex_unlock(&g15lib_mutex);
177
/* every 2nd packet contains the codes we want.. immediately try again */
178
while (retval == G15_ERROR_TRY_AGAIN){
179
pthread_mutex_lock(&g15lib_mutex);
180
retval = getPressedKeys(&keypresses, 40);
181
pthread_mutex_unlock(&g15lib_mutex);
184
if(retval == G15_NO_ERROR){
185
g15daemon_send_event(masterlist->current->lcd,
186
G15_EVENT_KEYPRESS, keypresses);
188
if(retval == -ENODEV && LIBG15_VERSION>=1200) {
189
pthread_mutex_lock(&g15lib_mutex);
190
while((retval=re_initLibG15() != G15_NO_ERROR) && !leaving){
193
if(!leaving) { masterlist->current->lcd->state_changed=1; masterlist->current->lcd->ident=random();}
194
pthread_mutex_unlock(&g15lib_mutex);
197
g15daemon_msleep(10);
203
static void *lcd_draw_thread(void *lcdlist){
205
g15daemon_t *masterlist = (g15daemon_t*)(lcdlist);
206
static long int lastlcd = 1;
207
static unsigned int lastscreentime;
208
/* unsigned int fps = 0; */
209
lcd_t *displaying = masterlist->tail->lcd;
210
char *lastdisplayed=NULL;
211
memset(displaying->buf,0,1024);
216
pthread_mutex_lock(&lcdlist_mutex);
218
displaying = masterlist->current->lcd;
220
if(displaying->ident != lastlcd){
221
/* monitor 'fps' - due to the TCP protocol, some frames will be bunched up.
222
discard excess to reduce load on the bus */
223
/* fps = 1000 / (g15daemon_gettime_ms() - lastscreentime); */
224
/* if the current screen is less than 20ms from the previous (equivelant to 50fps) delay it */
225
/* this allows a real-world fps of 40fps with no almost frame loss and reduces peak usb bus-load */
227
if((g15daemon_gettime_ms() - lastscreentime)>=20||(char*)displaying!=lastdisplayed){
228
uf_write_buf_to_g15(displaying);
229
lastscreentime = g15daemon_gettime_ms();
230
lastdisplayed = (char*)displaying;
231
lastlcd = displaying->ident;
235
if(displaying->state_changed){
236
pthread_mutex_lock(&g15lib_mutex);
237
setLCDContrast(displaying->contrast_state);
238
if(displaying->masterlist->remote_keyhandler_sock==0) // only allow mled control if the macro recorder isnt running
239
setLEDs(displaying->mkey_state);
240
if(masterlist->kb_backlight_state)
241
setLCDBrightness(displaying->backlight_state);
243
setLCDBrightness(masterlist->kb_backlight_state);
244
pthread_mutex_unlock(&g15lib_mutex);
245
displaying->state_changed = 0;
248
pthread_mutex_unlock(&lcdlist_mutex);
255
void g15daemon_sighandler(int sig) {
258
keyboard_backlight_off_onexit = 1;
269
int main (int argc, char *argv[])
274
int cycle_cmdline_override=0;
275
struct sigaction new_action;
276
cycle_key = G15_KEY_L1;
277
unsigned char user[256];
279
pthread_t keyboard_thread;
280
pthread_t lcd_thread;
283
for (i=0;i<argc;i++) {
285
memset(daemonargs,0,20);
286
strncpy(daemonargs,argv[i],19);
287
if (!strncmp(daemonargs, "-k",2) || !strncmp(daemonargs, "--kill",6)) {
288
daemonpid = uf_return_running();
290
kill(daemonpid,SIGINT);
292
printf("G15Daemon not running\n");
295
if (!strncmp(daemonargs, "-K",2) || !strncmp(daemonargs, "--KILL",6)) {
296
daemonpid = uf_return_running();
298
kill(daemonpid,SIGUSR1);
300
printf("G15Daemon not running\n");
303
if (!strncmp(daemonargs, "-v",2) || !strncmp(daemonargs, "--version",9)) {
304
float lg15ver = LIBG15_VERSION;
305
printf("G15Daemon version %s - %s\n",VERSION,uf_return_running() >= 0 ?"Loaded & Running":"Not Running");
306
printf("compiled with libg15 version %.3f\n\n",lg15ver/1000);
310
if (!strncmp(daemonargs, "-h",2) || !strncmp(daemonargs, "--help",6)) {
311
printf("G15Daemon version %s - %s\n",VERSION,uf_return_running() >= 0 ?"Loaded & Running":"Not Running");
312
printf("%s -h (--help) or -k (--kill) or -s (--switch) or -d (--debug) or -v (--version)\n\n -k will kill a previous incarnation",argv[0]);
313
#ifdef LIBG15_VERSION
314
#if LIBG15_VERSION >= 1200
315
printf(", if uppercase -K or -KILL turn off the keyboard backlight on the way out.");
318
printf("\n -h shows this help\n -s changes the screen-switch key from MR to L1\n -d debug mode - stay in foreground and output all debug messages to STDERR\n -v show version\n");
322
if (!strncmp(daemonargs, "-s",2) || !strncmp(daemonargs, "--switch",8)) {
323
cycle_key = G15_KEY_MR;
324
cycle_cmdline_override=1;
327
if (!strncmp(daemonargs, "-d",2) || !strncmp(daemonargs, "--debug",7)) {
329
if((argv[i+1])!=NULL)
330
if(isdigit(argv[i+1][0])){
331
g15daemon_debug = atoi(argv[i+1]);
332
if(g15daemon_debug==0) g15daemon_debug = 1;
336
if (!strncmp(daemonargs, "-u",2) || !strncmp(daemonargs, "--user",7)) {
338
strncpy((char*)user,argv[i+1],128);
344
if(uf_return_running()>=0) {
345
g15daemon_log(LOG_ERR,"G15Daemon already running.. Exiting");
349
/* set libg15 debugging to our debug setting */
350
if(LIBG15_VERSION>=1200)
351
libg15Debug(g15daemon_debug);
354
/* OS X: load codeless kext */
355
retval = system("/sbin/kextload " "/System/Library/Extensions/libusbshield.kext");
357
if (WIFEXITED(retval)){
358
if (WEXITSTATUS(retval) !=0){
359
g15daemon_log(LOG_ERR,"Unable to load USB shield kext...exiting");
363
g15daemon_log(LOG_ERR,"Unable to launch kextload...exiting");
368
/* init stuff here.. */
369
if((retval=initLibG15())!=G15_NO_ERROR){
370
g15daemon_log(LOG_ERR,"Unable to attach to the G15 Keyboard... exiting");
377
if(uf_create_pidfile() == 0) {
379
g15daemon_t *lcdlist;
380
config_section_t *global_cfg=NULL;
382
struct passwd *nobody;
383
unsigned char location[1024];
385
openlog("g15daemon", LOG_PID, LOG_DAEMON);
386
if(strlen((char*)user)==0){
387
nobody = getpwnam("nobody");
389
nobody = getpwnam((char*)user);
393
nobody = getpwuid(geteuid());
394
g15daemon_log(LOG_WARNING,"BEWARE: running as effective uid %i\n",nobody->pw_uid);
397
/* initialise the linked list */
398
lcdlist = ll_lcdlist_init();
399
lcdlist->nobody = nobody;
403
lcdlist->kb_backlight_state=1;
404
setLCDBrightness(lcdlist->kb_backlight_state);
406
#ifdef LIBG15_VERSION
407
#if LIBG15_VERSION >= 1200
408
setKBBrightness(lcdlist->kb_backlight_state);
412
uf_conf_open(lcdlist, "/etc/g15daemon.conf");
413
global_cfg=g15daemon_cfg_load_section(lcdlist,"Global");
414
if(!cycle_cmdline_override){
415
cycle_key = 1==g15daemon_cfg_read_bool(global_cfg,"Use MR as Cycle Key",0)?G15_KEY_MR:G15_KEY_L1;
417
/* all other processes/threads should be seteuid nobody */
419
seteuid(nobody->pw_uid);
420
setegid(nobody->pw_gid);
422
pthread_mutex_init(&g15lib_mutex, NULL);
423
pthread_attr_init(&attr);
424
pthread_attr_setstacksize(&attr,512*1024); /* set stack to 512k - dont need 8Mb !! */
425
pthread_attr_setscope(&attr,PTHREAD_SCOPE_SYSTEM);
426
int thread_policy=SCHED_RR;
427
pthread_attr_setschedpolicy(&attr,thread_policy);
429
if (pthread_create(&keyboard_thread, &attr, keyboard_watch_thread, lcdlist) != 0) {
430
g15daemon_log(LOG_ERR,"Unable to create keyboard listener thread. Exiting");
433
pthread_attr_setstacksize(&attr,128*1024);
434
/* all other threads have a lower priority... maybe */
435
pthread_attr_setscope(&attr,PTHREAD_SCOPE_PROCESS);
436
thread_policy=SCHED_OTHER;
437
pthread_attr_setschedpolicy(&attr,thread_policy);
439
if (pthread_create(&lcd_thread, &attr, lcd_draw_thread, lcdlist) != 0) {
440
g15daemon_log(LOG_ERR,"Unable to create display thread. Exiting");
443
g15daemon_log(LOG_INFO,"%s loaded\n",PACKAGE_STRING);
445
snprintf((char*)location,1024,"%s/%s",DATADIR,"g15daemon/splash/g15logo2.wbmp");
446
g15canvas *canvas = (g15canvas *)g15daemon_xmalloc (sizeof (g15canvas));
447
memset (canvas->buffer, 0, G15_BUFFER_LEN);
448
canvas->mode_cache = 0;
449
canvas->mode_reverse = 0;
450
canvas->mode_xor = 0;
451
g15r_loadWbmpSplash(canvas,(char*)location);
452
memcpy (lcdlist->tail->lcd->buf, canvas->buffer, G15_BUFFER_LEN);
454
uf_write_buf_to_g15(lcdlist->tail->lcd);
456
snprintf((char*)location,1024,"%s",PLUGINDIR);
458
g15_open_all_plugins(lcdlist,(char*)location);
460
new_action.sa_handler = g15daemon_sighandler;
461
new_action.sa_flags = 0;
462
sigaction(SIGINT, &new_action, NULL);
463
sigaction(SIGQUIT, &new_action, NULL);
464
sigaction(SIGUSR1, &new_action, NULL);
469
} while( leaving == 0);
471
g15daemon_log(LOG_INFO,"Leaving by request");
473
pthread_join(lcd_thread,NULL);
474
pthread_join(keyboard_thread,NULL);
475
/* switch off the lcd backlight */
477
#ifdef LIBG15_VERSION
478
#if LIBG15_VERSION >= 1200
479
/* if SIGUSR1 was sent to kill us, switch off the keyboard backlight as well */
480
if(keyboard_backlight_off_onexit==1)
485
#ifdef LIBG15_VERSION
486
#if LIBG15_VERSION >= 1100
490
ll_lcdlist_destroy(&lcdlist);
493
/* return to root privilages for the final countdown */
497
uf_conf_write(lcdlist,"/etc/g15daemon.conf");
498
uf_conf_free(lcdlist);
499
unlink("/var/run/g15daemon.pid");