• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/N900/ButtonListener.cpp

00001 #include <stdlib.h>
00002 #include <stdio.h>
00003 #include <errno.h>
00004 #include <sys/fcntl.h>
00005 #include <poll.h>
00006 #include <unistd.h>
00007 #include <sstream>
00008 
00009 #include "FCam/Event.h" 
00010 #include "FCam/Time.h" 
00011 
00012 #include "ButtonListener.h"
00013 #include "../Debug.h"
00014 
00015 
00016 
00017 
00018 namespace FCam { 
00019     namespace N900 {
00020 
00021         void *button_listener_thread_(void *arg) {
00022             ButtonListener *b = (ButtonListener *)arg;
00023             b->run();    
00024             pthread_exit(NULL);
00025             return NULL;
00026         }
00027         
00028         ButtonListener *ButtonListener::instance() {
00029             // Return a pointer to a static function variable. I feel
00030             // dirty doing this, but it guarantees that 
00031             // 1) The buttonlistener is created on first use
00032             // 2) The destructor gets called on program exit
00033 
00034             // See http://www.research.ibm.com/designpatterns/pubs/ph-jun96.txt
00035             // for an interesting discussion of ways to make sure singletons get deleted.
00036 
00037             static ButtonListener _instance;
00038             return &_instance;
00039         }
00040         
00041         ButtonListener::ButtonListener() : stop(false) {
00042             pthread_attr_t attr;
00043             struct sched_param param;
00044             
00045             // make the thread
00046             
00047             param.sched_priority = sched_get_priority_max(SCHED_OTHER);            
00048             
00049             pthread_attr_init(&attr);
00050             
00051             if ((errno =
00052                  -(pthread_attr_setschedparam(&attr, &param) ||
00053                    pthread_attr_setschedpolicy(&attr, SCHED_OTHER) ||
00054                    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) ||
00055                    pthread_create(&thread, &attr, button_listener_thread_, this)))) {
00056                 error(Event::InternalError, "Error creating button listener thread");
00057             }
00058 
00059         }
00060 
00061         ButtonListener::~ButtonListener() {
00062             stop = true;
00063             pthread_join(thread, NULL);
00064         }
00065 
00066         void ButtonListener::run() {
00067             // TODO: The below is a horrible hack to prevent the built-in
00068             // camera program from stealing shutter press events. I really
00069             // wish there was a better way to do this.
00070             
00071             // kill the built-in camera program if it was launched at boot
00072             if (!fork()) {
00073                 dprintf(2, "Killing camera-ui using dsmetool\n");
00074                 // suppress output
00075                 close(STDOUT_FILENO);
00076                 close(STDERR_FILENO);
00077                 execl("/usr/sbin/dsmetool",
00078                       "/usr/sbin/dsmetool",
00079                       "-k", "/usr/bin/camera-ui",
00080                       (char *)NULL);
00081                 exit(0);
00082             }
00083             
00084             if (!fork()) {
00085                 // Give the dsmetool a chance to do it's thing                
00086                 usleep(100000);
00087                 dprintf(2, "Killing camera-ui using killall\n");
00088                 // suppress output
00089                 close(STDOUT_FILENO);
00090                 close(STDERR_FILENO);
00091                 execl("/usr/bin/killall", "/usr/bin/killall", "camera-ui", (char *)NULL);
00092                 exit(0);
00093             }
00094             
00095             const int BUTTONS = 4;
00096 
00097             const char *fnames[BUTTONS] = {"/sys/devices/platform/gpio-switch/cam_shutter/state",
00098                                            "/sys/devices/platform/gpio-switch/cam_focus/state",
00099                                            "/sys/devices/platform/gpio-switch/cam_launch/state",
00100                                            "/sys/devices/platform/gpio-switch/slide/state"};
00101                                                
00102             char buf[81];
00103 
00104             bool state[BUTTONS];
00105 
00106             int event[BUTTONS*2] = {Event::N900LensOpened,
00107                                     Event::N900LensClosed,
00108                                     Event::FocusPressed,
00109                                     Event::FocusReleased,
00110                                     Event::ShutterPressed,
00111                                     Event::ShutterReleased,
00112                                     Event::N900SlideOpened,
00113                                     Event::N900SlideClosed};
00114 
00115             std::string descriptions[BUTTONS*2] = {"Lens cover opened",
00116                                                    "Lens cover closed",
00117                                                    "Focus button pressed",
00118                                                    "Focus button released",
00119                                                    "Shutter button pressed",
00120                                                    "Shutter button released",
00121                                                    "Keyboard slide opened",
00122                                                    "Keyboard slide closed"};
00123 
00124             // open all the devices
00125             int rval;
00126             struct pollfd fds[BUTTONS];
00127             for (int i = 0; i < BUTTONS; i++) {
00128                 fds[i].fd = open(fnames[i], O_RDONLY);
00129                 fds[i].events = POLLPRI;
00130                 fds[i].revents = 0;
00131             }
00132 
00133             // read the initial state
00134             for (int i = 0; i < BUTTONS; i++) {
00135                 rval = read(fds[i].fd, &buf, 80);
00136                 buf[rval] = 0;
00137                 switch (buf[0]) {
00138                 case 'c': // closed
00139                 case 'i': // inactive
00140                     state[i] = false;
00141                     break;
00142                 case 'o': // open
00143                 case 'a': // active
00144                     state[i] = true;
00145                     break;
00146                 default:                    
00147                     error(Event::InternalError, "ButtonListener: Unknown state: %s", buf);
00148                 }
00149             }            
00150 
00151             while (!stop) {               
00152                 // wait for a change
00153                 rval = poll(fds, BUTTONS, 1000);
00154                 if (rval == -1) {
00155                     // this fails once on load, not sure why
00156                     dprintf(2, "ButtonListener: poll failed");
00157                     //error(Event::InternalError, "ButtonListener: poll failed");
00158                     continue;
00159                 }
00160                 if (rval == 0) continue; // timeout
00161 
00162                 for (int i = 0; i < BUTTONS; i++) {
00163                     if (fds[i].revents & POLLPRI) {
00164                         close(fds[i].fd);
00165                         fds[i].fd = open(fnames[i], O_RDONLY, 0);
00166                         rval = read(fds[i].fd, &buf, 80);
00167                         buf[rval] = 0;
00168                         switch (buf[0]) {
00169                         case 'c': // closed
00170                         case 'i': // inactive
00171                             if (state[i] != false) {
00172                                 state[i] = false;
00173                                 postEvent(event[i*2+1], 0, descriptions[i*2+1]);
00174                             }
00175                             break;
00176                         case 'o': // open
00177                         case 'a': // active
00178                             if (state[i] != true) {
00179                                 state[i] = true;
00180                                 postEvent(event[i*2], 0, descriptions[i*2]);
00181                             }
00182                             break;
00183                         default:
00184                             error(Event::InternalError, "ButtonListener: Unknown state: %s", buf);
00185                         }
00186                     }
00187                 }                
00188             }
00189 
00190             dprintf(2, "Button listener shutting down\n");
00191 
00192             for (int i = 0; i < BUTTONS; i++) {
00193                 close(fds[i].fd);
00194             }
00195             
00196             // restart the built-in camera program
00197             if (!fork()) {
00198                 // on success, this function never returns
00199                 execl("/usr/sbin/dsmetool", 
00200                       "/usr/sbin/dsmetool", 
00201                       "-U", "user", 
00202                       "-o", "/usr/bin/camera-ui", 
00203                       (char *)NULL);
00204                 // it returned, so there was a failure
00205                 error(Event::InternalError, "Error restarting camera-ui");
00206                 exit(0);
00207             }
00208         }
00209     }
00210 }
00211 
00212 

Generated on Thu Jul 22 2010 17:50:34 for FCam by  doxygen 1.7.1