~ubuntu-branches/ubuntu/trusty/g15daemon/trusty-proposed

« back to all changes in this revision

Viewing changes to g15daemon/main.c

  • Committer: Bazaar Package Importer
  • Author(s): Giacomo Catenazzi
  • Date: 2007-10-09 13:28:56 UTC
  • Revision ID: james.westby@ubuntu.com-20071009132856-hptc4j3kitessuaj
Tags: upstream-1.9.0-wip.20070910
ImportĀ upstreamĀ versionĀ 1.9.0-wip.20070910

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    This file is part of g15daemon.
 
3
 
 
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.
 
8
 
 
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.
 
13
 
 
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
 
17
    
 
18
    (c) 2006 Mike Lampard, Philip Lawatsch, and others
 
19
    
 
20
    $Revision: 302 $ -  $Date: 2007-09-10 09:57:53 +0200 (Mon, 10 Sep 2007) $ $Author: mlampard $
 
21
    
 
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.
 
25
*/
 
26
 
 
27
#include <pthread.h>
 
28
#include <stdio.h>
 
29
#include <stdlib.h>
 
30
#include <signal.h>
 
31
#include <errno.h>
 
32
#include <string.h>
 
33
#include <sys/types.h>
 
34
#include <sys/socket.h>
 
35
#include <sys/stat.h>
 
36
#include <sys/time.h>
 
37
#include <fcntl.h>
 
38
#include <unistd.h>
 
39
#include <pwd.h>
 
40
#include <ctype.h>
 
41
 
 
42
#include <config.h>
 
43
#include <libg15.h>
 
44
#include <libg15render.h>
 
45
#include "g15daemon.h"
 
46
 
 
47
#ifndef LIBG15_VERSION
 
48
#define LIBG15_VERSION 1000
 
49
#endif
 
50
 
 
51
/* all threads will exit if leaving >0 */
 
52
int 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;
 
58
 
 
59
/* send event to foreground client's eventlistener */
 
60
int g15daemon_send_event(void *caller, unsigned int event, unsigned long value)
 
61
{
 
62
    switch(event) {
 
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;
 
71
                newevent->lcd = lcd;
 
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);
 
78
                }
 
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));
 
83
                }
 
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;
 
88
                }
 
89
                free(newevent);
 
90
            }else{
 
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();
 
97
                }else{
 
98
                    unsigned int unclick=g15daemon_gettime_ms();
 
99
                    if ((unclick-clicktime)<500) {
 
100
                        g15daemon_lcdnode_cycle(masterlist);
 
101
                    }
 
102
                    else 
 
103
                    {
 
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);
 
114
                        free(clickevent);
 
115
                    }
 
116
                }
 
117
            }
 
118
            lastkeys = value;
 
119
            break;
 
120
        }
 
121
        case G15_EVENT_CYCLE_PRIORITY:{
 
122
            lcd_t *lcd = (lcd_t*)caller;
 
123
            g15daemon_t* masterlist = lcd->masterlist;
 
124
            if(value)
 
125
                g15daemon_lcdnode_cycle(masterlist);
 
126
            break;
 
127
        }
 
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;
 
135
            }
 
136
            else {
 
137
                if(lcdnode->list->current == lcdnode->last_priority){
 
138
                    lcdnode->list->current = lcdnode->list->current->prev;
 
139
                } else{
 
140
                    if(lcdnode->last_priority != NULL) {
 
141
                        lcdnode->list->current = lcdnode->last_priority;
 
142
                        lcdnode->last_priority = NULL;
 
143
                    }
 
144
                    else
 
145
                        lcdnode->list->current = lcdnode->list->current->prev;
 
146
                }
 
147
            }
 
148
            pthread_mutex_unlock(&lcdlist_mutex);
 
149
            break;
 
150
        }
 
151
        default: {
 
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;
 
157
            newevent->lcd = lcd;
 
158
            (*plugin_listener)((void*)newevent);
 
159
            free(newevent);
 
160
        }
 
161
    }
 
162
    return 0;
 
163
}
 
164
 
 
165
static void *keyboard_watch_thread(void *lcdlist){
 
166
    
 
167
    g15daemon_t *masterlist = (g15daemon_t*)(lcdlist);
 
168
    
 
169
    unsigned int keypresses = 0;
 
170
    int retval = 0;
 
171
    while (!leaving) {
 
172
        
 
173
        pthread_mutex_lock(&g15lib_mutex);
 
174
        retval = getPressedKeys(&keypresses, 40);
 
175
        pthread_mutex_unlock(&g15lib_mutex);
 
176
        
 
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);
 
182
        }
 
183
 
 
184
        if(retval == G15_NO_ERROR){
 
185
            g15daemon_send_event(masterlist->current->lcd, 
 
186
                                 G15_EVENT_KEYPRESS, keypresses);
 
187
        }
 
188
        if(retval == -ENODEV && LIBG15_VERSION>=1200) {
 
189
          pthread_mutex_lock(&g15lib_mutex);
 
190
          while((retval=re_initLibG15() != G15_NO_ERROR) && !leaving){
 
191
           sleep(1);
 
192
          }
 
193
          if(!leaving) { masterlist->current->lcd->state_changed=1; masterlist->current->lcd->ident=random();}
 
194
          pthread_mutex_unlock(&g15lib_mutex); 
 
195
        }
 
196
 
 
197
        g15daemon_msleep(10);
 
198
    }
 
199
    
 
200
    return NULL;
 
201
}
 
202
 
 
203
static void *lcd_draw_thread(void *lcdlist){
 
204
 
 
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);
 
212
    
 
213
    g15daemon_sleep(2);
 
214
 
 
215
    while (!leaving) {
 
216
        pthread_mutex_lock(&lcdlist_mutex);
 
217
        
 
218
        displaying = masterlist->current->lcd;
 
219
        
 
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 */
 
226
                        
 
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;
 
232
            }
 
233
        }
 
234
        
 
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);
 
242
            else
 
243
              setLCDBrightness(masterlist->kb_backlight_state);
 
244
            pthread_mutex_unlock(&g15lib_mutex);
 
245
            displaying->state_changed = 0;
 
246
        }
 
247
            
 
248
        pthread_mutex_unlock(&lcdlist_mutex);
 
249
        
 
250
        g15daemon_msleep(5);
 
251
    }
 
252
    return NULL;
 
253
}
 
254
 
 
255
void g15daemon_sighandler(int sig) {
 
256
    switch(sig){
 
257
         case SIGUSR1:
 
258
              keyboard_backlight_off_onexit = 1;
 
259
         case SIGINT:
 
260
         case SIGQUIT:
 
261
              leaving = 1;
 
262
               break;
 
263
         case SIGPIPE:
 
264
               break;
 
265
    }
 
266
}
 
267
 
 
268
 
 
269
int main (int argc, char *argv[])
 
270
{
 
271
    pid_t daemonpid;
 
272
    int retval;
 
273
    int i;
 
274
    int cycle_cmdline_override=0;
 
275
    struct sigaction new_action;
 
276
    cycle_key = G15_KEY_L1;
 
277
    unsigned char user[256];
 
278
       
 
279
    pthread_t keyboard_thread;
 
280
    pthread_t lcd_thread;
 
281
    memset(user,0,256); 
 
282
 
 
283
    for (i=0;i<argc;i++) {
 
284
        char daemonargs[20];
 
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();
 
289
                   if(daemonpid>0) {
 
290
                       kill(daemonpid,SIGINT);
 
291
                   } else
 
292
                       printf("G15Daemon not running\n");
 
293
                   exit(0);
 
294
        }
 
295
        if (!strncmp(daemonargs, "-K",2) || !strncmp(daemonargs, "--KILL",6)) {
 
296
                   daemonpid = uf_return_running();
 
297
                   if(daemonpid>0) {
 
298
                       kill(daemonpid,SIGUSR1);
 
299
                   } else
 
300
                       printf("G15Daemon not running\n");
 
301
                   exit(0);
 
302
        }
 
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);
 
307
            exit(0);
 
308
        }    
 
309
        
 
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.");
 
316
            #endif
 
317
            #endif
 
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");
 
319
            exit(0);
 
320
        }
 
321
 
 
322
        if (!strncmp(daemonargs, "-s",2) || !strncmp(daemonargs, "--switch",8)) {
 
323
            cycle_key = G15_KEY_MR;
 
324
            cycle_cmdline_override=1;
 
325
        }
 
326
 
 
327
        if (!strncmp(daemonargs, "-d",2) || !strncmp(daemonargs, "--debug",7)) {
 
328
            g15daemon_debug = 1;
 
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;
 
333
            }
 
334
        }
 
335
        
 
336
        if (!strncmp(daemonargs, "-u",2) || !strncmp(daemonargs, "--user",7)) {
 
337
            if(argv[i+1]!=NULL){
 
338
                strncpy((char*)user,argv[i+1],128);
 
339
                i++;
 
340
            }
 
341
        }
 
342
 
 
343
    }
 
344
    if(uf_return_running()>=0) {
 
345
        g15daemon_log(LOG_ERR,"G15Daemon already running.. Exiting");
 
346
        exit(0);
 
347
    }
 
348
 
 
349
    /* set libg15 debugging to our debug setting */
 
350
    if(LIBG15_VERSION>=1200)
 
351
        libg15Debug(g15daemon_debug);
 
352
    
 
353
#ifdef OSTYPE_DARWIN
 
354
     /* OS X: load codeless kext */
 
355
     retval = system("/sbin/kextload " "/System/Library/Extensions/libusbshield.kext");
 
356
                
 
357
     if (WIFEXITED(retval)){
 
358
        if (WEXITSTATUS(retval) !=0){
 
359
                g15daemon_log(LOG_ERR,"Unable to load USB shield kext...exiting");
 
360
                exit(1);
 
361
        }
 
362
     } else {
 
363
        g15daemon_log(LOG_ERR,"Unable to launch kextload...exiting");
 
364
        exit(1);
 
365
     }
 
366
#endif
 
367
 
 
368
    /* init stuff here..  */
 
369
    if((retval=initLibG15())!=G15_NO_ERROR){
 
370
        g15daemon_log(LOG_ERR,"Unable to attach to the G15 Keyboard... exiting");
 
371
        exit(1);
 
372
    }
 
373
 
 
374
    if(!g15daemon_debug)
 
375
        daemon(0,0);
 
376
 
 
377
    if(uf_create_pidfile() == 0) {
 
378
        
 
379
        g15daemon_t *lcdlist;
 
380
        config_section_t *global_cfg=NULL;
 
381
        pthread_attr_t attr;
 
382
        struct passwd *nobody;
 
383
        unsigned char location[1024];
 
384
 
 
385
        openlog("g15daemon", LOG_PID, LOG_DAEMON);
 
386
        if(strlen((char*)user)==0){
 
387
            nobody = getpwnam("nobody");
 
388
        }else {
 
389
            nobody = getpwnam((char*)user);
 
390
        }
 
391
        if (nobody==NULL)
 
392
        {
 
393
            nobody = getpwuid(geteuid());
 
394
            g15daemon_log(LOG_WARNING,"BEWARE: running as effective uid %i\n",nobody->pw_uid);
 
395
        }
 
396
        
 
397
        /* initialise the linked list */
 
398
        lcdlist = ll_lcdlist_init();
 
399
        lcdlist->nobody = nobody;
 
400
 
 
401
        setLCDContrast(1); 
 
402
        setLEDs(0);
 
403
        lcdlist->kb_backlight_state=1;
 
404
        setLCDBrightness(lcdlist->kb_backlight_state);
 
405
 
 
406
#ifdef LIBG15_VERSION
 
407
#if LIBG15_VERSION >= 1200
 
408
        setKBBrightness(lcdlist->kb_backlight_state);
 
409
#endif
 
410
#endif                      
 
411
        
 
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;
 
416
        }
 
417
               /* all other processes/threads should be seteuid nobody */
 
418
        if(nobody!=NULL) {
 
419
            seteuid(nobody->pw_uid);
 
420
            setegid(nobody->pw_gid);
 
421
        }
 
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);
 
428
 
 
429
        if (pthread_create(&keyboard_thread, &attr, keyboard_watch_thread, lcdlist) != 0) {
 
430
            g15daemon_log(LOG_ERR,"Unable to create keyboard listener thread.  Exiting");
 
431
            goto exitnow;
 
432
        }
 
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);
 
438
 
 
439
        if (pthread_create(&lcd_thread, &attr, lcd_draw_thread, lcdlist) != 0) {
 
440
            g15daemon_log(LOG_ERR,"Unable to create display thread.  Exiting");
 
441
            goto exitnow;
 
442
        }
 
443
        g15daemon_log(LOG_INFO,"%s loaded\n",PACKAGE_STRING);
 
444
        
 
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);
 
453
        free (canvas);
 
454
        uf_write_buf_to_g15(lcdlist->tail->lcd);
 
455
        
 
456
        snprintf((char*)location,1024,"%s",PLUGINDIR);
 
457
 
 
458
        g15_open_all_plugins(lcdlist,(char*)location);
 
459
 
 
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);
 
465
        
 
466
        do {
 
467
            sleep(1);
 
468
  
 
469
        } while( leaving == 0);
 
470
 
 
471
        g15daemon_log(LOG_INFO,"Leaving by request");
 
472
 
 
473
        pthread_join(lcd_thread,NULL);
 
474
        pthread_join(keyboard_thread,NULL);
 
475
        /* switch off the lcd backlight */
 
476
        setLCDBrightness(0);
 
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)
 
481
          setKBBrightness(0);
 
482
#endif
 
483
#endif
 
484
            
 
485
#ifdef LIBG15_VERSION
 
486
#if LIBG15_VERSION >= 1100
 
487
        exitLibG15(); 
 
488
#endif
 
489
#endif
 
490
        ll_lcdlist_destroy(&lcdlist);
 
491
 
 
492
exitnow:
 
493
    /* return to root privilages for the final countdown */
 
494
    seteuid(0);
 
495
    setegid(0);
 
496
    closelog();
 
497
    uf_conf_write(lcdlist,"/etc/g15daemon.conf");
 
498
    uf_conf_free(lcdlist);
 
499
    unlink("/var/run/g15daemon.pid");
 
500
    }
 
501
    return 0;
 
502
}