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
*/
// 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
} 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 );
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?
*/
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 );
// sucks
return ( 0 );
}
-
+
return ( 1 );
}
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
}
// first -- are we critical yet? if so, shut down!
- if ( batlevel <= b_shutdown && b_shutdown_script ) {
- int mamps = 0;
+ if ( batlevel <= b_shutdown && b_shutdown_script) {
- if ( pnd_device_get_charge_current ( &mamps ) && mamps > 100 ) {
- // critical battery, but charging, so relax.
+ if ( uamps > 100 ) {
+ // critical battery, but charging, so relax.
+ b_warned = 0;
} else {
- int x;
+ 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
- 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 );
- }
+ // charge monitoring
+ now = time(NULL);
+ if ( bc_enable && bc_charge_devices != NULL && (unsigned int)(now - last_charge_check) > 60 ) {
- 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 );
- }
+ 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 {
- } // charging
+ 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?
// 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 );
}
// 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;