X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-libraries.git;a=blobdiff_plain;f=apps%2Fpndevmapperd.c;h=516b82c8e2ce7acbf39583fee323b5f787ad75dc;hp=c31cade78e704a9dd665d9dc863839cc20941077;hb=5c3c97f377fd3be4ceecf16fba765852d1a9572b;hpb=14fa7e3a9bee2d870cad9aa2046c7a3944e00f03 diff --git a/apps/pndevmapperd.c b/apps/pndevmapperd.c index c31cade..516b82c 100644 --- a/apps/pndevmapperd.c +++ b/apps/pndevmapperd.c @@ -6,7 +6,8 @@ // woot for writing code while sick. // this code begs a rewrite, but should work fine; its just arranged goofily -// -> I mean, why the racial divide between keys and other events +// -> I mean, why the racial divide between keys and other events? +// -> now that I've put together pnd_io_evdev, should leverage that; be much cleaner. #include /* for printf, NULL */ #include /* for free */ @@ -59,8 +60,23 @@ typedef struct { keycode_t keycodes[] = { { KEY_A, "a" }, + { KEY_B, "b" }, { KEY_MENU, "pandora" }, { KEY_POWER, "power" }, + { KEY_DELETE, "del" }, + { KEY_COMMA, "comma" }, + { KEY_1, "1" }, + { KEY_2, "2" }, + { KEY_3, "3" }, + { KEY_4, "4" }, + { KEY_5, "5" }, + { KEY_6, "6" }, + { KEY_7, "7" }, + { KEY_8, "8" }, + { KEY_9, "9" }, + { KEY_0, "0" }, + { KEY_BRIGHTNESSDOWN, "lcdbrightdown" }, + { KEY_BRIGHTNESSUP, "lcdbrightup" }, { -1, NULL } }; @@ -86,7 +102,7 @@ typedef struct { void *reqs; // scancode/etc for the event in question char *script; // script to invoke - //unsigned int hold_min; // minimum hold-time to trigger + unsigned int maxhold; // maximum hold-time before forcing script invocation /* state */ @@ -98,6 +114,7 @@ typedef struct { #define MAXEVENTS 255 evmap_t g_evmap [ MAXEVENTS ]; unsigned int g_evmap_max = 0; +unsigned int g_queued_keyups = 0; // battery unsigned char b_threshold = 5; // %battery @@ -106,7 +123,14 @@ unsigned int b_blinkfreq = 2; // blink every 2sec unsigned int b_blinkdur = 1000; // blink duration (uSec), 0sec + uSec is assumed unsigned char b_active = 0; // 0=inactive, 1=active and waiting to blink, 2=blink is on, waiting to turn off unsigned char b_shutdown = 1; // %age battery to force a shutdown! +unsigned int b_shutdelay = 30; // delay for shutdown script +unsigned char b_warned = 0; // Shutdown attempted char *b_shutdown_script = NULL; +unsigned char bc_enable = 1; // enable charger control +unsigned char bc_stopcap = 99; // battery capacity threshold as stop condition 1 +unsigned int bc_stopcur = 80000; // charge current threshold as stop condition 2, in uA +unsigned char bc_startcap = 95; // battery capacity threshold to resume charging +char *bc_charge_devices = NULL; // charger /sys/class/power_supply/ devices, changes between kernel versions /* get to it */ @@ -206,7 +230,7 @@ int main ( int argc, char *argv[] ) { // umask umask ( 022 ); // emitted files can be rwxr-xr-x - + } // set up daemon /* hmm, seems to not like working right after boot.. do we depend on another daemon or @@ -292,8 +316,22 @@ int main ( int argc, char *argv[] ) { if ( p -> keycode != -1 ) { g_evmap [ g_evmap_max ].key_p = 1; // its a key, not an event g_evmap [ g_evmap_max ].reqs = p; // note the keycode - g_evmap [ g_evmap_max ].script = n; // note the script to activate in response - pnd_log ( pndn_rem, "Registered key %s [%d] to script %s\n", p -> keyname, p -> keycode, (char*) n ); + + // note the script to activate in response + if ( strchr ( n, ' ' ) ) { + char *foo = strdup ( n ); + char *t = strchr ( foo, ' ' ); + *t = '\0'; + g_evmap [ g_evmap_max ].script = foo; + g_evmap [ g_evmap_max ].maxhold = atoi ( t + 1 ); + } else { + g_evmap [ g_evmap_max ].script = n; + g_evmap [ g_evmap_max ].maxhold = 0; + } + + pnd_log ( pndn_rem, "Registered key %s [%d] to script %s with maxhold %d\n", + p -> keyname, p -> keycode, (char*) n, g_evmap [ g_evmap_max ].maxhold ); + g_evmap_max++; } else { pnd_log ( pndn_warning, "WARNING! Key '%s' is not handled by pndevmapperd yet! Skipping.", k ); @@ -334,6 +372,9 @@ int main ( int argc, char *argv[] ) { } else if ( strncmp ( k, "battery.", 8 ) == 0 ) { // not consumed here, skip silently + } else if ( strncmp ( k, "battery_charge.", 15 ) == 0 ) { + // not consumed here, skip silently + } else { // uhhh pnd_log ( pndn_warning, "Unknown config key '%s'; skipping.\n", k ); @@ -374,10 +415,34 @@ int main ( int argc, char *argv[] ) { b_shutdown = pnd_conf_get_as_int ( evmaph, "battery.shutdown_threshold" ); pnd_log ( pndn_rem, "Battery shutdown threshold set to %u", b_shutdown ); } + if ( pnd_conf_get_as_int ( evmaph, "battery.shutdown_delay" ) != PND_CONF_BADNUM ) { + b_shutdelay = pnd_conf_get_as_int ( evmaph, "battery.shutdown_delay" ); + pnd_log ( pndn_rem, "Battery shutdown delay set to %u", b_shutdelay ); + } if ( pnd_conf_get_as_char ( evmaph, "battery.shutdown_script" ) != NULL ) { b_shutdown_script = strdup ( pnd_conf_get_as_char ( evmaph, "battery.shutdown_script" ) ); pnd_log ( pndn_rem, "Battery shutdown script set to %s", b_shutdown_script ); } + if ( pnd_conf_get_as_int ( evmaph, "battery_charge.enable" ) != PND_CONF_BADNUM ) { + bc_enable = pnd_conf_get_as_int ( evmaph, "battery_charge.enable" ); + pnd_log ( pndn_rem, "Battery charge enable set to %u", bc_enable ); + } + if ( pnd_conf_get_as_int ( evmaph, "battery_charge.stop_capacity" ) != PND_CONF_BADNUM ) { + bc_stopcap = pnd_conf_get_as_int ( evmaph, "battery_charge.stop_capacity" ); + pnd_log ( pndn_rem, "Battery charge stop capacity set to %u", bc_stopcap ); + } + if ( pnd_conf_get_as_int ( evmaph, "battery_charge.stop_current" ) != PND_CONF_BADNUM ) { + bc_stopcur = pnd_conf_get_as_int ( evmaph, "battery_charge.stop_current" ); + pnd_log ( pndn_rem, "Battery charge stop current set to %u", bc_stopcur ); + } + if ( pnd_conf_get_as_int ( evmaph, "battery_charge.start_capacity" ) != PND_CONF_BADNUM ) { + bc_startcap = pnd_conf_get_as_int ( evmaph, "battery_charge.start_capacity" ); + pnd_log ( pndn_rem, "Battery charge start capacity set to %u", bc_startcap ); + } + if ( pnd_conf_get_as_char ( evmaph, "battery_charge.devices" ) != NULL ) { + bc_charge_devices = strdup ( pnd_conf_get_as_char ( evmaph, "battery_charge.devices" ) ); + pnd_log ( pndn_rem, "Battery charge devices set to %s", bc_charge_devices ); + } /* do we have anything to do? */ @@ -439,19 +504,19 @@ int main ( int argc, char *argv[] ) { pnd_log ( pndn_rem, "%s maps to %s\n", fname, name ); - if ( strcmp ( name, "omap_twl4030keypad" ) == 0 ) { + if ( strcmp ( name, PND_EVDEV_KEYPAD/*"omap_twl4030keypad"*/ ) == 0 ) { fds [ 0 ] = fd; } else if ( strcmp ( name, "gpio-keys" ) == 0) { fds [ 1 ] = fd; } else if ( strcmp ( name, "AT Translated Set 2 keyboard" ) == 0) { // for vmware, my dev environment fds [ 0 ] = fd; - } else if ( strcmp ( name, "triton2-pwrbutton" ) == 0) { + } else if ( strcmp ( name, PND_EVDEV_POWER/*"triton2-pwrbutton"*/ ) == 0) { fds [ 2 ] = fd; - } else if ( strcmp ( name, "ADS784x Touchscreen" ) == 0) { + } else if ( strcmp ( name, PND_EVDEV_TS/*"ADS784x Touchscreen"*/ ) == 0) { fds [ 3 ] = fd; - } else if ( strcmp ( name, "vsense66" ) == 0) { + } else if ( strcmp ( name, PND_EVDEV_NUB1/*"vsense66"*/ ) == 0) { fds [ 4 ] = fd; - } else if ( strcmp ( name, "vsense67" ) == 0) { + } else if ( strcmp ( name, PND_EVDEV_NUB1/*"vsense67"*/ ) == 0) { fds [ 5 ] = fd; } else { pnd_log ( pndn_rem, "Ignoring unknown device '%s'\n", name ); @@ -488,6 +553,7 @@ int main ( int argc, char *argv[] ) { int fd = -1, rd, ret; fd_set fdset; + // set up fd list FD_ZERO ( &fdset ); imaxfd = 0; @@ -502,74 +568,117 @@ int main ( int argc, char *argv[] ) { } } - ret = select ( imaxfd + 1, &fdset, NULL, NULL, NULL ); + // figure out if we can block forever, or not + unsigned char do_block = 1; + struct timeval tv; + tv.tv_usec = 0; + tv.tv_sec = 1; + + for ( i = i; i < g_evmap_max; i++ ) { + if ( g_evmap [ i ].keydown_time && g_evmap [ i ].maxhold ) { + do_block = 0; + break; + } + } + + // wait for fd's or timeout + ret = select ( imaxfd + 1, &fdset, NULL, NULL, do_block ? NULL /* no timeout */ : &tv ); if ( ret == -1 ) { pnd_log ( pndn_error, "ERROR! select(2) failed with: %s\n", strerror ( errno ) ); continue; // retry! - } - for ( i = 0; i < max_fd; i++ ) { - if ( fds [ i ] != -1 && FD_ISSET ( fds [ i ], &fdset ) ) { - fd = fds [ i ]; - } // fd is set? - } // for + } else if ( ret == 0 ) { // select returned with timeout (no fd) - /* buttons or keypad */ - rd = read ( fd, ev, sizeof(struct input_event) * 64 ); - if ( rd < (int) sizeof(struct input_event) ) { - pnd_log ( pndn_error, "ERROR! read(2) input_event failed with: %s\n", strerror ( errno ) ); - break; - } + // timeout occurred; should only happen when 1 or more keys are being held down and + // they're "maxhold" keys, so we have to see if their timer has passed + unsigned int now = time ( NULL ); + + for ( i = i; i < g_evmap_max; i++ ) { + + if ( g_evmap [ i ].keydown_time && + g_evmap [ i ].maxhold && + now - g_evmap [ i ].keydown_time >= g_evmap [ i ].maxhold ) + { + keycode_t *k = (keycode_t*) g_evmap [ i ].reqs; + dispatch_key ( k -> keycode, 0 /* key up */ ); + } - for (i = 0; i < rd / sizeof(struct input_event); i++ ) { + } // for + + } else { // an fd was fiddled with + + for ( i = 0; i < max_fd; i++ ) { + if ( fds [ i ] != -1 && FD_ISSET ( fds [ i ], &fdset ) ) { + fd = fds [ i ]; + } // fd is set? + } // for + + /* buttons or keypad */ + rd = read ( fd, ev, sizeof(struct input_event) * 64 ); + if ( rd < (int) sizeof(struct input_event) ) { + pnd_log ( pndn_error, "ERROR! read(2) input_event failed with: %s\n", strerror ( errno ) ); + break; + } - if ( ev[i].type == EV_SYN ) { - continue; - } else if ( ev[i].type == EV_KEY ) { + for (i = 0; i < rd / sizeof(struct input_event); i++ ) { - // do we even know about this key at all? - keycode_t *p = keycodes; - while ( p -> keycode != -1 ) { - if ( p -> keycode == ev [ i ].code ) { - break; + if ( ev[i].type == EV_SYN ) { + continue; + } else if ( ev[i].type == EV_KEY ) { + + // do we even know about this key at all? + keycode_t *p = keycodes; + while ( p -> keycode != -1 ) { + if ( p -> keycode == ev [ i ].code ) { + break; + } + p++; } - p++; - } - // if we do, hand it off to dispatcher to look up if we actually do something with it - if ( p -> keycode != -1 ) { - pnd_log ( pndn_debug, "Key Event: key %s [%d] value %d\n", p -> keyname, p -> keycode, ev [ i ].value ); - dispatch_key ( p -> keycode, ev [ i ].value ); - } else { - pnd_log ( pndn_warning, "Unknown Key Event: keycode %d value %d\n", ev [ i ].code, ev [ i ].value ); - } + // if we do, hand it off to dispatcher to look up if we actually do something with it + if ( p -> keycode != -1 ) { + if ( logall >= 0 ) { + pnd_log ( pndn_debug, "Key Event: key %s [%d] value %d\n", p -> keyname, p -> keycode, ev [ i ].value ); + } + dispatch_key ( p -> keycode, ev [ i ].value ); + } else { + if ( logall >= 0 ) { + pnd_log ( pndn_warning, "Unknown Key Event: keycode %d value %d\n", ev [ i ].code, ev [ i ].value ); + } + } - } else if ( ev[i].type == EV_SW ) { + } else if ( ev[i].type == EV_SW ) { - // do we even know about this event at all? - generic_event_t *p = generics; - while ( p -> code != -1 ) { - if ( p -> code == ev [ i ].code ) { - break; + // do we even know about this event at all? + generic_event_t *p = generics; + while ( p -> code != -1 ) { + if ( p -> code == ev [ i ].code ) { + break; + } + p++; + } + + // if we do, hand it off to dispatcher to look up if we actually do something with it + if ( p -> code != -1 ) { + if ( logall >= 0 ) { + pnd_log ( pndn_debug, "Generic Event: event %s [%d] value %d\n", p -> name, p -> code, ev [ i ].value ); + } + dispatch_event ( p -> code, ev [ i ].value ); + } else { + if ( logall >= 0 ) { + pnd_log ( pndn_warning, "Unknown Generic Event: code %d value %d\n", ev [ i ].code, ev [ i ].value ); + } } - p++; - } - // if we do, hand it off to dispatcher to look up if we actually do something with it - if ( p -> code != -1 ) { - pnd_log ( pndn_debug, "Generic Event: event %s [%d] value %d\n", p -> name, p -> code, ev [ i ].value ); - dispatch_event ( p -> code, ev [ i ].value ); } else { - pnd_log ( pndn_warning, "Unknown Generic Event: code %d value %d\n", ev [ i ].code, ev [ i ].value ); - } + pnd_log ( pndn_debug, "DEBUG: Unexpected event type %i received\n", ev[i].type ); + continue; + } // type? - } else { - pnd_log ( pndn_debug, "DEBUG: Unexpected event type %i received\n", ev[i].type ); - continue; - } // type? + } // for - } // for + } // an fd was touched } // while @@ -592,49 +701,64 @@ void dispatch_key ( int keycode, int val ) { // 2 - down again (hold) // 0 - up (released) - pnd_log ( pndn_rem, "Dispatching Key..\n" ); - for ( i = 0; i < g_evmap_max; i++ ) { if ( ( g_evmap [ i ].key_p ) && ( ((keycode_t*) (g_evmap [ i ].reqs)) -> keycode == keycode ) && ( g_evmap [ i ].script ) ) { + unsigned char invoke_it = 0; // is this a keydown or a keyup? if ( val == 1 ) { // keydown g_evmap [ i ].keydown_time = time ( NULL ); - } else if ( val == 0 ) { - // keyup + } else if ( val == 2 && g_evmap [ i ].keydown_time ) { + // key is being held; we should check if max-hold is set - char holdtime [ 128 ]; - sprintf ( holdtime, "%d", (int)( time(NULL) - g_evmap [ i ].keydown_time ) ); + if ( g_evmap [ i ].maxhold && + time ( NULL ) - g_evmap [ i ].keydown_time >= g_evmap [ i ].maxhold ) + { + invoke_it = 1; + } + + } else if ( val == 0 && g_evmap [ i ].keydown_time ) { + // keyup (while key is down) if ( time ( NULL ) - g_evmap [ i ].last_trigger_time >= g_minimum_separation ) { - int x; + invoke_it = 1; + } else { + pnd_log ( pndn_rem, "Skipping invokation.. falls within minimum_separation threshold\n" ); + } - g_evmap [ i ].last_trigger_time = time ( NULL ); + } // key up or down? - pnd_log ( pndn_rem, "Will attempt to invoke: %s %s\n", g_evmap [ i ].script, holdtime ); + if ( invoke_it ) { - if ( ( x = fork() ) < 0 ) { - pnd_log ( pndn_error, "ERROR: Couldn't fork()\n" ); - exit ( -3 ); - } + char holdtime [ 128 ]; + sprintf ( holdtime, "%d", (int)( time(NULL) - g_evmap [ i ].keydown_time ) ); + pnd_log ( pndn_rem, "Will attempt to invoke: %s %s\n", g_evmap [ i ].script, holdtime ); - if ( x == 0 ) { - execl ( g_evmap [ i ].script, g_evmap [ i ].script, holdtime, (char*)NULL ); - pnd_log ( pndn_error, "ERROR: Couldn't exec(%s)\n", g_evmap [ i ].script ); - exit ( -4 ); - } + // state + g_evmap [ i ].keydown_time = 0; // clear the keydown-ness + g_evmap [ i ].last_trigger_time = time ( NULL ); - } else { - pnd_log ( pndn_rem, "Skipping invokation.. falls within minimum_separation threshold\n" ); + // invocation + int x; + + if ( ( x = fork() ) < 0 ) { + pnd_log ( pndn_error, "ERROR: Couldn't fork()\n" ); + exit ( -3 ); } - } // key up or down? + if ( x == 0 ) { + execl ( g_evmap [ i ].script, g_evmap [ i ].script, holdtime, (char*)NULL ); + pnd_log ( pndn_error, "ERROR: Couldn't exec(%s)\n", g_evmap [ i ].script ); + exit ( -4 ); + } + + } // invoke the script! return; } // found matching event for keycode @@ -737,7 +861,7 @@ unsigned char set_next_alarm ( unsigned int secs, unsigned int usecs ) { // sucks return ( 0 ); } - + return ( 1 ); } @@ -745,30 +869,84 @@ void sigalrm_handler ( int n ) { pnd_log ( pndn_debug, "---[ SIGALRM ]---\n" ); + static time_t last_charge_check, last_charge_worka; int batlevel = pnd_device_get_battery_gauge_perc(); + int uamps = 0; + time_t now; + + pnd_device_get_charge_current ( &uamps ); if ( batlevel < 0 ) { +#if 0 // couldn't read the battery level, so just assume low and make blinks? batlevel = 4; // low, but not cause a shutdown +#else + // couldn't read the battery level, so just assume ok! + batlevel = 50; +#endif } // first -- are we critical yet? if so, shut down! - if ( batlevel <= b_shutdown && b_shutdown_script ) { - int x; + if ( batlevel <= b_shutdown && b_shutdown_script) { - pnd_log ( pndn_error, "CRITICAL BATTERY LEVEL -- shutdown the system down! Invoke: %s\n", b_shutdown_script ); + if ( uamps > 100 ) { + // critical battery, but charging, so relax. + b_warned = 0; + } else { + if (b_warned == 0) { + // Avoid warning again till re-powered + b_warned = 1; + int x; + pnd_log ( pndn_error, "Battery Current: %d\n", uamps ); + pnd_log ( pndn_error, "CRITICAL BATTERY LEVEL -- shutdown the system down! Invoke: %s\n", + b_shutdown_script ); + + if ( ( x = fork() ) < 0 ) { + pnd_log ( pndn_error, "ERROR: Couldn't fork()\n" ); + exit ( -3 ); + } + + if ( x == 0 ) { + char value [ 100 ]; + sprintf ( value, "%d", b_shutdelay ); + execl ( b_shutdown_script, b_shutdown_script, value, (char*)NULL ); + pnd_log ( pndn_error, "ERROR: Couldn't exec(%s)\n", b_shutdown_script ); + exit ( -4 ); + } + } + } // charging - if ( ( x = fork() ) < 0 ) { - pnd_log ( pndn_error, "ERROR: Couldn't fork()\n" ); - exit ( -3 ); - } + } - if ( x == 0 ) { - execl ( b_shutdown_script, b_shutdown_script, (char*)NULL ); - pnd_log ( pndn_error, "ERROR: Couldn't exec(%s)\n", b_shutdown_script ); - exit ( -4 ); - } + // charge monitoring + now = time(NULL); + if ( bc_enable && bc_charge_devices != NULL && (unsigned int)(now - last_charge_check) > 60 ) { + + int charge_enabled = pnd_device_get_charger_enable ( bc_charge_devices ); + if ( charge_enabled < 0 ) + pnd_log ( pndn_error, "ERROR: Couldn't read charger enable control\n" ); + else { + if ( charge_enabled && batlevel >= bc_stopcap && 0 < uamps && uamps < bc_stopcur ) { + pnd_log ( pndn_debug, "Charge stop conditions reached, disabling charging\n" ); + pnd_device_set_charger_enable ( bc_charge_devices, 0 ); + } + else if ( !charge_enabled && batlevel <= bc_startcap ) { + pnd_log ( pndn_debug, "Charge start conditions reached, enabling charging\n" ); + pnd_device_set_charger_enable ( bc_charge_devices, 1 ); + } + + // for some unknown reason it just stops charging randomly (happens once per week or so), + // and does not restart, resulting in a flat battery if machine is unattended. + // What seems to help here is writing to chip registers, we can do it here indirectly + // by writing to enable. Doing it occasionally should do no harm even with missing charger. + if ( batlevel <= bc_startcap && (unsigned int)(now - last_charge_worka) > 20*60 ) { + pnd_log ( pndn_debug, "Charge workaround trigger\n" ); + pnd_device_set_charger_enable ( bc_charge_devices, 1 ); + last_charge_worka = now; + } + } + last_charge_check = now; } // is battery warning already active? @@ -777,25 +955,27 @@ void sigalrm_handler ( int n ) { // is user charging up? if so, stop blinking. // perhaps we shoudl check if charger is connected, and not blink at all in that case.. - if ( batlevel > b_threshold + 1 /* allow for error in read */ ) { + if ( uamps > 0 ) { + //Re-arm warning + b_warned = 0; pnd_log ( pndn_debug, "Battery is high again, flipping to non-blinker mode\n" ); b_active = 0; set_next_alarm ( b_frequency, 0 ); - pnd_device_set_led_power_brightness ( 250 ); + pnd_device_set_led_charger_brightness ( 250 ); return; } if ( b_active == 1 ) { // turn LED on pnd_log ( pndn_debug, "Blink on\n" ); - pnd_device_set_led_power_brightness ( 200 ); + pnd_device_set_led_charger_brightness ( 200 ); // set timer to short duration b_active = 2; set_next_alarm ( 0, b_blinkdur ); } else if ( b_active == 2 ) { // turn LED off pnd_log ( pndn_debug, "Blink off\n" ); - pnd_device_set_led_power_brightness ( 10 ); + pnd_device_set_led_charger_brightness ( 10 ); // back to longer duration b_active = 1; set_next_alarm ( b_blinkfreq, 0 ); @@ -805,7 +985,7 @@ void sigalrm_handler ( int n ) { } // warning is off.. - if ( batlevel <= b_threshold ) { + if ( batlevel <= b_threshold && uamps < 0 ) { // battery seems low, go to active mode pnd_log ( pndn_debug, "Battery is low, flipping to blinker mode\n" ); b_active = 1;