• 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 <sys/file.h>
00006 #include <poll.h>
00007 #include <unistd.h>
00008 #include <sstream>
00009 
00010 #include "FCam/Event.h" 
00011 #include "FCam/Time.h" 
00012 
00013 #include "ButtonListener.h"
00014 #include "../Debug.h"
00015 
00016 
00017 
00018 
00019 namespace FCam { 
00020     namespace N900 {
00021 
00022         void *button_listener_thread_(void *arg) {
00023             ButtonListener *b = (ButtonListener *)arg;
00024             b->run();    
00025             pthread_exit(NULL);
00026             return NULL;
00027         }
00028         
00029         ButtonListener *ButtonListener::instance() {
00030             // Return a pointer to a static function variable. I feel
00031             // dirty doing this, but it guarantees that 
00032             // 1) The buttonlistener is created on first use
00033             // 2) The destructor gets called on program exit
00034 
00035             // See http://www.research.ibm.com/designpatterns/pubs/ph-jun96.txt
00036             // for an interesting discussion of ways to make sure singletons get deleted.
00037 
00038             static ButtonListener _instance;
00039             return &_instance;
00040         }
00041         
00042         ButtonListener::ButtonListener() : stop(false) {
00043             pthread_attr_t attr;
00044             struct sched_param param;
00045             
00046             // make the thread
00047             
00048             param.sched_priority = sched_get_priority_max(SCHED_OTHER);            
00049             
00050             pthread_attr_init(&attr);
00051             
00052             if ((errno =
00053                  -(pthread_attr_setschedparam(&attr, &param) ||
00054                    pthread_attr_setschedpolicy(&attr, SCHED_OTHER) ||
00055                    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) ||
00056                    pthread_create(&thread, &attr, button_listener_thread_, this)))) {
00057                 error(Event::InternalError, "Error creating button listener thread");
00058             }
00059 
00060         }
00061 
00062         ButtonListener::~ButtonListener() {
00063             stop = true;
00064             pthread_join(thread, NULL);
00065         }
00066 
00067         void ButtonListener::run() {
00068             // TODO: The below is a horrible hack to prevent the built-in
00069             // camera program from stealing shutter press events. I really
00070             // wish there was a better way to do this.
00071             
00072             // kill the built-in camera program if it was launched at boot
00073             if (!fork()) {
00074                 dprintf(2, "Killing camera-ui using dsmetool\n");
00075                 // suppress output
00076                 close(STDOUT_FILENO);
00077                 close(STDERR_FILENO);
00078                 execl("/usr/sbin/dsmetool",
00079                       "/usr/sbin/dsmetool",
00080                       "-k", "/usr/bin/camera-ui",
00081                       (char *)NULL);
00082                 exit(0);
00083             }
00084             
00085             if (!fork()) {
00086                 // Give the dsmetool a chance to do it's
00087                 // thing. However, if the camera was launched from the
00088                 // App menu it may not work, so use killall as well.
00089                 usleep(100000);
00090                 dprintf(2, "Killing camera-ui using killall\n");
00091                 close(STDOUT_FILENO);
00092                 close(STDERR_FILENO);
00093                 execl("/usr/bin/killall", "/usr/bin/killall", "camera-ui", (char *)NULL);
00094                 exit(0);
00095             }
00096             
00097             // Start a watchdog process that respawns the camera-ui
00098             // when the fcam program terminates (even if it crashes)
00099 
00100             // Create the file to be locked and lock it.
00101             int lockFD = open("/tmp/fcam.lock", O_RDWR | O_CREAT);
00102             int ret = flock(lockFD, LOCK_EX | LOCK_NB);
00103             if (ret == EWOULDBLOCK) {
00104                 // someone already has this file locked. Must be
00105                 // another fcam process. The user will find out when
00106                 // the try to instantiate a sensor so let's silently
00107                 // bail out here.
00108                 return;                
00109             }
00110 
00111             if (!fork()) {
00112                 // make my own process group, so signals sent to the
00113                 // parent (eg SIGSEGV or SIGKILL) don't kill me
00114                 // too. Unfortunately this also means I can't just use
00115                 // waitpid.
00116                 setpgrp();
00117                 // close the duplicated lockFD from the parent
00118                 close(lockFD);
00119                 // wait for the parent to terminate by locking the same file
00120                 flock(open("/tmp/fcam.lock", O_RDWR | O_CREAT), LOCK_EX);
00121                 // respawn the camera-ui
00122                 dprintf(2, "Respawning camera-ui");
00123                 close(STDOUT_FILENO);
00124                 close(STDERR_FILENO);
00125                 execl("/usr/sbin/dsmetool", 
00126                       "/usr/sbin/dsmetool", 
00127                       "-U", "user", 
00128                       "-o", "/usr/bin/camera-ui", 
00129                       (char *)NULL);                
00130             }
00131 
00132             const int BUTTONS = 4;
00133 
00134             const char *fnames[BUTTONS] = {"/sys/devices/platform/gpio-switch/cam_shutter/state",
00135                                            "/sys/devices/platform/gpio-switch/cam_focus/state",
00136                                            "/sys/devices/platform/gpio-switch/cam_launch/state",
00137                                            "/sys/devices/platform/gpio-switch/slide/state"};
00138                                                
00139             char buf[81];
00140 
00141             bool state[BUTTONS];
00142 
00143             int event[BUTTONS*2] = {Event::N900LensOpened,
00144                                     Event::N900LensClosed,
00145                                     Event::FocusPressed,
00146                                     Event::FocusReleased,
00147                                     Event::ShutterPressed,
00148                                     Event::ShutterReleased,
00149                                     Event::N900SlideOpened,
00150                                     Event::N900SlideClosed};
00151 
00152             std::string descriptions[BUTTONS*2] = {"Lens cover opened",
00153                                                    "Lens cover closed",
00154                                                    "Focus button pressed",
00155                                                    "Focus button released",
00156                                                    "Shutter button pressed",
00157                                                    "Shutter button released",
00158                                                    "Keyboard slide opened",
00159                                                    "Keyboard slide closed"};
00160 
00161             // open all the devices
00162             int rval;
00163             struct pollfd fds[BUTTONS];
00164             for (int i = 0; i < BUTTONS; i++) {
00165                 fds[i].fd = open(fnames[i], O_RDONLY);
00166                 fds[i].events = POLLPRI;
00167                 fds[i].revents = 0;
00168             }
00169 
00170             // read the initial state
00171             for (int i = 0; i < BUTTONS; i++) {
00172                 rval = read(fds[i].fd, &buf, 80);
00173                 buf[rval] = 0;
00174                 switch (buf[0]) {
00175                 case 'c': // closed
00176                 case 'i': // inactive
00177                     state[i] = false;
00178                     break;
00179                 case 'o': // open
00180                 case 'a': // active
00181                     state[i] = true;
00182                     break;
00183                 default:                    
00184                     error(Event::InternalError, "ButtonListener: Unknown state: %s", buf);
00185                 }
00186             }            
00187 
00188             while (!stop) {               
00189                 // wait for a change
00190                 rval = poll(fds, BUTTONS, 1000);
00191                 if (rval == -1) {
00192                     // this fails once on load, not sure why
00193                     dprintf(2, "ButtonListener: poll failed");
00194                     //error(Event::InternalError, "ButtonListener: poll failed");
00195                     continue;
00196                 }
00197                 if (rval == 0) continue; // timeout
00198 
00199                 for (int i = 0; i < BUTTONS; i++) {
00200                     if (fds[i].revents & POLLPRI) {
00201                         close(fds[i].fd);
00202                         fds[i].fd = open(fnames[i], O_RDONLY, 0);
00203                         rval = read(fds[i].fd, &buf, 80);
00204                         buf[rval] = 0;
00205                         switch (buf[0]) {
00206                         case 'c': // closed
00207                         case 'i': // inactive
00208                             if (state[i] != false) {
00209                                 state[i] = false;
00210                                 postEvent(event[i*2+1], 0, descriptions[i*2+1]);
00211                             }
00212                             break;
00213                         case 'o': // open
00214                         case 'a': // active
00215                             if (state[i] != true) {
00216                                 state[i] = true;
00217                                 postEvent(event[i*2], 0, descriptions[i*2]);
00218                             }
00219                             break;
00220                         default:
00221                             error(Event::InternalError, "ButtonListener: Unknown state: %s", buf);
00222                         }
00223                     }
00224                 }                
00225             }
00226 
00227             dprintf(2, "Button listener shutting down\n");
00228 
00229             for (int i = 0; i < BUTTONS; i++) {
00230                 close(fds[i].fd);
00231             }
00232             close(lockFD);
00233         }
00234     }
00235 }
00236 
00237 

Generated on Fri Sep 24 2010 15:53:00 for FCam by  doxygen 1.7.1