vdr  1.7.27
lirc.c
Go to the documentation of this file.
00001 /*
00002  * lirc.c: LIRC remote control
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * LIRC support added by Carsten Koch <Carsten.Koch@icem.de>  2000-06-16.
00008  *
00009  * $Id: lirc.c 2.1 2011/03/08 15:35:13 kls Exp $
00010  */
00011 
00012 #include "lirc.h"
00013 #include <netinet/in.h>
00014 #include <sys/socket.h>
00015 
00016 #define REPEATDELAY 350 // ms
00017 #define REPEATFREQ 100 // ms
00018 #define REPEATTIMEOUT 500 // ms
00019 #define RECONNECTDELAY 3000 // ms
00020 
00021 cLircRemote::cLircRemote(const char *DeviceName)
00022 :cRemote("LIRC")
00023 ,cThread("LIRC remote control")
00024 {
00025   addr.sun_family = AF_UNIX;
00026   strcpy(addr.sun_path, DeviceName);
00027   if (Connect()) {
00028      Start();
00029      return;
00030      }
00031   f = -1;
00032 }
00033 
00034 cLircRemote::~cLircRemote()
00035 {
00036   int fh = f;
00037   f = -1;
00038   Cancel();
00039   if (fh >= 0)
00040      close(fh);
00041 }
00042 
00043 bool cLircRemote::Connect(void)
00044 {
00045   if ((f = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) {
00046      if (connect(f, (struct sockaddr *)&addr, sizeof(addr)) >= 0)
00047         return true;
00048      LOG_ERROR_STR(addr.sun_path);
00049      close(f);
00050      f = -1;
00051      }
00052   else
00053      LOG_ERROR_STR(addr.sun_path);
00054   return false;
00055 }
00056 
00057 bool cLircRemote::Ready(void)
00058 {
00059   return f >= 0;
00060 }
00061 
00062 void cLircRemote::Action(void)
00063 {
00064   cTimeMs FirstTime;
00065   cTimeMs LastTime;
00066   char buf[LIRC_BUFFER_SIZE];
00067   char LastKeyName[LIRC_KEY_BUF] = "";
00068   bool repeat = false;
00069   int timeout = -1;
00070 
00071   while (Running() && f >= 0) {
00072 
00073         bool ready = cFile::FileReady(f, timeout);
00074         int ret = ready ? safe_read(f, buf, sizeof(buf)) : -1;
00075 
00076         if (ready && ret <= 0 ) {
00077            esyslog("ERROR: lircd connection broken, trying to reconnect every %.1f seconds", float(RECONNECTDELAY) / 1000);
00078            close(f);
00079            f = -1;
00080            while (Running() && f < 0) {
00081                  cCondWait::SleepMs(RECONNECTDELAY);
00082                  if (Connect()) {
00083                     isyslog("reconnected to lircd");
00084                     break;
00085                     }
00086                  }
00087            }
00088 
00089         if (ready && ret > 0) {
00090            buf[ret - 1] = 0;
00091            int count;
00092            char KeyName[LIRC_KEY_BUF];
00093            if (sscanf(buf, "%*x %x %29s", &count, KeyName) != 2) { // '29' in '%29s' is LIRC_KEY_BUF-1!
00094               esyslog("ERROR: unparseable lirc command: %s", buf);
00095               continue;
00096               }
00097            if (count == 0) {
00098               if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < REPEATDELAY)
00099                  continue; // skip keys coming in too fast
00100               if (repeat)
00101                  Put(LastKeyName, false, true);
00102               strcpy(LastKeyName, KeyName);
00103               repeat = false;
00104               FirstTime.Set();
00105               timeout = -1;
00106               }
00107            else {
00108               if (LastTime.Elapsed() < REPEATFREQ)
00109                  continue; // repeat function kicks in after a short delay (after last key instead of first key)
00110               if (FirstTime.Elapsed() < REPEATDELAY)
00111                  continue; // skip keys coming in too fast (for count != 0 as well)
00112               repeat = true;
00113               timeout = REPEATDELAY;
00114               }
00115            LastTime.Set();
00116            Put(KeyName, repeat);
00117            }
00118         else if (repeat) { // the last one was a repeat, so let's generate a release
00119            if (LastTime.Elapsed() >= REPEATTIMEOUT) {
00120               Put(LastKeyName, false, true);
00121               repeat = false;
00122               *LastKeyName = 0;
00123               timeout = -1;
00124               }
00125            }
00126         }
00127 }