vdr
1.7.27
|
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 }