eventmap: use Yen (Fn-l) to switch layers as F12 conflicts
[pandora-libraries.git] / apps / pndevmapperd.c
index c42b942..cb7d9b6 100644 (file)
@@ -77,6 +77,22 @@ keycode_t keycodes[] = {
   { KEY_0, "0" },
   { KEY_BRIGHTNESSDOWN, "lcdbrightdown" },
   { KEY_BRIGHTNESSUP, "lcdbrightup" },
+  { KEY_COFFEE, "hold" }, /* coffee? lol */
+  { KEY_F1, "f1" },
+  { KEY_F2, "f2" },
+  { KEY_F3, "f3" },
+  { KEY_F4, "f4" },
+  { KEY_F5, "f5" },
+  { KEY_F6, "f6" },
+  { KEY_F7, "f7" },
+  { KEY_F8, "f8" },
+  { KEY_F9, "f9" },
+  { KEY_F10, "f10" },
+  { KEY_F11, "f11" },
+  { KEY_F12, "f12" },
+  { KEY_F18, "f18" },
+  { KEY_F23, "f23" },
+  { KEY_YEN, "yen" },
   { -1, NULL }
 };
 
@@ -91,6 +107,12 @@ generic_event_t generics[] = {
   { -1, -1, NULL }
 };
 
+// FAKESCRIPT_ entries are to better handle a virtual script name; if we have to parse
+// "TOGGLE_HOLD" for every key down, it seems a little inefficient; at conf-time, if we
+// see this string for example, why not change it to a magic number .. and if we see that
+// down the road, we can act with just an integer compare, instead of a string compare..
+#define FAKESCRIPT_TOGGLE_HOLD 0001
+
 // event-to-sh mapping
 //
 typedef struct {
@@ -123,7 +145,18 @@ 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
+
+// fd's; pulled from main() so I can be lazy
+int fds [ 8 ] = { -1, -1, -1, -1, -1, -1, -1, -1 }; // 0 = keypad, 1 = gpio keys
+int imaxfd = 0;
 
 /* get to it
  */
@@ -132,6 +165,8 @@ void dispatch_event ( int code, int val );
 void sigchld_handler ( int n );
 unsigned char set_next_alarm ( unsigned int secs, unsigned int usecs );
 void sigalrm_handler ( int n );
+void fakescript_hold_on ( void );
+void fakescript_hold_off ( void );
 
 static void usage ( char *argv[] ) {
   printf ( "%s [-d]\n", argv [ 0 ] );
@@ -223,7 +258,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
@@ -320,6 +355,11 @@ int main ( int argc, char *argv[] ) {
        } else {
          g_evmap [ g_evmap_max ].script = n;
          g_evmap [ g_evmap_max ].maxhold = 0;
+
+         if ( strcmp ( n, "TOGGLE_HOLD" ) == 0 ) {
+           g_evmap [ g_evmap_max ].script = (char*)FAKESCRIPT_TOGGLE_HOLD;
+         }
+
        }
 
        pnd_log ( pndn_rem, "Registered key %s [%d] to script %s with maxhold %d\n",
@@ -365,6 +405,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 );
@@ -405,10 +448,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?
    */
@@ -449,8 +516,6 @@ int main ( int argc, char *argv[] ) {
 
   // try to locate the appropriate devices
   int id;
-  int fds [ 8 ] = { -1, -1, -1, -1, -1, -1, -1, -1 }; // 0 = keypad, 1 = gpio keys
-  int imaxfd = 0;
 
   for ( id = 0; ; id++ ) {
     char fname[64];
@@ -476,9 +541,9 @@ int main ( int argc, char *argv[] ) {
       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, PND_EVDEV_NUB1/*"vsense66"*/ ) == 0) {
       fds [ 4 ] = fd;
@@ -678,7 +743,22 @@ void dispatch_key ( int keycode, int val ) {
       // is this a keydown or a keyup?
       if ( val == 1 ) {
        // keydown
-       g_evmap [ i ].keydown_time = time ( NULL );
+
+       if ( g_evmap [ i ].maxhold == 0 ) {
+
+         // is this a special internally handled key, or normal key?
+         if ( g_evmap [ i ].script == (char*)FAKESCRIPT_TOGGLE_HOLD ) {
+           // handle this specially
+           fakescript_hold_on();
+         } else {
+           // normal key, with script to run
+           g_evmap [ i ].keydown_time = 0;
+           invoke_it = 1;
+         }
+
+       } else {
+         g_evmap [ i ].keydown_time = time ( NULL );
+       }
 
       } else if ( val == 2 && g_evmap [ i ].keydown_time ) {
        // key is being held; we should check if max-hold is set
@@ -689,13 +769,21 @@ void dispatch_key ( int keycode, int val ) {
          invoke_it = 1;
        }
 
-      } else if ( val == 0 && g_evmap [ i ].keydown_time ) {
-       // keyup (while key is down)
+      } else if ( val == 0 ) {
+
+       if ( g_evmap [ i ].script == (char*)FAKESCRIPT_TOGGLE_HOLD ) {
+         // handle this specially
+         fakescript_hold_off();
+
+       } else if ( g_evmap [ i ].keydown_time ) {
+         // keyup (while key is down)
+
+         if ( time ( NULL ) - g_evmap [ i ].last_trigger_time >= g_minimum_separation ) {
+           invoke_it = 1;
+         } else {
+           pnd_log ( pndn_rem, "Skipping invokation.. falls within minimum_separation threshold\n" );
+         }
 
-       if ( time ( NULL ) - g_evmap [ i ].last_trigger_time >= g_minimum_separation ) {
-         invoke_it = 1;
-       } else {
-         pnd_log ( pndn_rem, "Skipping invokation.. falls within minimum_separation threshold\n" );
        }
 
       } // key up or down?
@@ -827,7 +915,7 @@ unsigned char set_next_alarm ( unsigned int secs, unsigned int usecs ) {
     // sucks
     return ( 0 );
   }
-  
+
   return ( 1 );
 }
 
@@ -835,7 +923,12 @@ 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
@@ -848,30 +941,66 @@ void sigalrm_handler ( int n ) {
   }
 
   // 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?
@@ -880,7 +1009,9 @@ 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 );
@@ -908,7 +1039,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;
@@ -917,3 +1048,25 @@ void sigalrm_handler ( int n ) {
 
   return;
 }
+
+void fakescript_hold_on ( void ) {
+  pnd_log ( pndn_rem, "HOLD is being enabled.\n" );
+
+  int i;
+  for ( i = 0; i < imaxfd; i++ ) {
+    ioctl ( fds [ i ], EVIOCGRAB, 1 /* enable */ );
+  }
+
+  return;
+}
+
+void fakescript_hold_off ( void ) {
+  pnd_log ( pndn_rem, "HOLD is being disabled.\n" );
+
+  int i;
+  for ( i = 0; i < imaxfd; i++ ) {
+    ioctl ( fds [ i ], EVIOCGRAB, 0 /* disable */ );
+  }
+
+  return;
+}