diff options
Diffstat (limited to 'remote.c')
-rw-r--r-- | remote.c | 309 |
1 files changed, 192 insertions, 117 deletions
@@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16. * - * $Id: remote.c 1.15 2000/10/03 10:49:58 kls Exp $ + * $Id: remote.c 1.18 2000/10/08 16:49:41 kls Exp $ */ #include "remote.h" @@ -27,16 +27,11 @@ #include "config.h" #include "tools.h" -#define REPEATLIMIT 100 // ms -#define REPEATDELAY 250 // ms - // --- cRcIoBase ------------------------------------------------------------- cRcIoBase::cRcIoBase(void) { t = 0; - firstTime = lastTime = 0; - lastCommand = 0; } cRcIoBase::~cRcIoBase() @@ -69,12 +64,12 @@ void cRcIoKBD::Flush(int WaitMs) } } -bool cRcIoKBD::InputAvailable(bool Wait) +bool cRcIoKBD::InputAvailable(void) { - return f.Ready(Wait); + return f.Ready(false); } -bool cRcIoKBD::GetCommand(unsigned int *Command, unsigned short *) +bool cRcIoKBD::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) { if (Command) { *Command = getch(); @@ -87,36 +82,122 @@ bool cRcIoKBD::GetCommand(unsigned int *Command, unsigned short *) #elif defined REMOTE_RCU +#define REPEATLIMIT 20 // ms +#define REPEATDELAY 350 // ms + cRcIoRCU::cRcIoRCU(char *DeviceName) { dp = 0; mode = modeB; code = 0; address = 0xFFFF; + receivedAddress = 0; + receivedCommand = 0; + receivedData = receivedRepeat = receivedRelease = false; lastNumber = 0; - if (f.Open(DeviceName, O_RDWR | O_NONBLOCK)) { + if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) { struct termios t; if (tcgetattr(f, &t) == 0) { cfsetspeed(&t, B9600); cfmakeraw(&t); - if (tcsetattr(f, TCSAFLUSH, &t) == 0) + if (tcsetattr(f, TCSAFLUSH, &t) == 0) { + Start(); return; + } } LOG_ERROR_STR(DeviceName); - f.Close(); + close(f); } else LOG_ERROR_STR(DeviceName); + f = -1; } cRcIoRCU::~cRcIoRCU() { + Stop(); } -int cRcIoRCU::ReceiveByte(bool Wait) +void cRcIoRCU::Action(void) +{ +#pragma pack(1) + union { + struct { + unsigned short address; + unsigned int command; + } data; + unsigned char raw[6]; + } buffer; +#pragma pack() + + dsyslog(LOG_INFO, "RCU remote control thread started (pid=%d)", getpid()); + + int FirstTime = 0; + unsigned int LastCommand = 0; + + for (; f >= 0;) { + + LOCK_THREAD; + + if (ReceiveByte(REPEATLIMIT) == 'X') { + for (int i = 0; i < 6; i++) { + int b = ReceiveByte(); + if (b >= 0) { + buffer.raw[i] = b; + if (i == 5) { + unsigned short Address = ntohs(buffer.data.address); // the PIC sends bytes in "network order" + unsigned int Command = ntohl(buffer.data.command); + if (code == 'B' && address == 0x0000 && Command == 0x00004000) + // Well, well, if it isn't the "d-box"... + // This remote control sends the above command before and after + // each keypress - let's just drop this: + break; + if (!receivedData) { // only accept new data the previous data has been fetched + int Now = time_ms(); + if (Command != LastCommand) { + receivedAddress = Address; + receivedCommand = Command; + receivedData = true; + receivedRepeat = receivedRelease = false; + FirstTime = Now; + } + else { + if (Now - FirstTime < REPEATDELAY) + break; // repeat function kicks in after a short delay + receivedData = receivedRepeat = true; + } + LastCommand = Command; + WakeUp(); + } + } + } + else + break; + } + } + else if (receivedData) { // the last data before releasing the key hasn't been fetched yet + if (receivedRepeat) { // it was a repeat, so let's make it a release + receivedRepeat = false; + receivedRelease = true; + LastCommand = 0; + WakeUp(); + } + } + else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat, so let's generate a release + receivedData = receivedRelease = true; + receivedRepeat = false; + LastCommand = 0; + WakeUp(); + } + else + LastCommand = 0; + } +} + +int cRcIoRCU::ReceiveByte(int TimeoutMs) { // Returns the byte if one was received within a timeout, -1 otherwise - if (InputAvailable(Wait)) { + if (cFile::FileReady(f, TimeoutMs)) { unsigned char b; if (read(f, &b, 1) == 1) return b; @@ -128,16 +209,16 @@ int cRcIoRCU::ReceiveByte(bool Wait) bool cRcIoRCU::SendByteHandshake(unsigned char c) { - if (f.IsOpen()) { + if (f >= 0) { int w = write(f, &c, 1); if (w == 1) { - for (int reply = ReceiveByte(); reply >= 0;) { + for (int reply = ReceiveByte(REPEATLIMIT); reply >= 0;) { if (reply == c) return true; else if (reply == 'X') { // skip any incoming RC code - it will come again for (int i = 6; i--;) { - if (ReceiveByte(false) < 0) + if (ReceiveByte() < 0) return false; } } @@ -152,6 +233,8 @@ bool cRcIoRCU::SendByteHandshake(unsigned char c) bool cRcIoRCU::SendByte(unsigned char c) { + LOCK_THREAD; + for (int retry = 5; retry--;) { if (SendByteHandshake(c)) return true; @@ -174,66 +257,34 @@ bool cRcIoRCU::SetMode(unsigned char Mode) void cRcIoRCU::Flush(int WaitMs) { - int t0 = time_ms(); + LOCK_THREAD; + int t0 = time_ms(); for (;;) { - while (ReceiveByte(false) >= 0) + while (ReceiveByte() >= 0) t0 = time_ms(); if (time_ms() - t0 >= WaitMs) break; } + receivedData = receivedRepeat = false; } -bool cRcIoRCU::InputAvailable(bool Wait) +bool cRcIoRCU::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) { - return f.Ready(Wait); -} - -bool cRcIoRCU::GetCommand(unsigned int *Command, unsigned short *Address) -{ -#pragma pack(1) - union { - struct { - unsigned short address; - unsigned int command; - } data; - unsigned char raw[6]; - } buffer; -#pragma pack() - - Flush(); - if (Command && ReceiveByte() == 'X') { - for (int i = 0; i < 6; i++) { - int b = ReceiveByte(false); - if (b >= 0) - buffer.raw[i] = b; - else - return false; - } - if (Address) - *Address = ntohs(buffer.data.address); // the PIC sends bytes in "network order" - else if (address != ntohs(buffer.data.address)) - return false; - *Command = ntohl(buffer.data.command); - if (code == 'B' && address == 0x0000 && *Command == 0x00004000) - // Well, well, if it isn't the "d-box"... - // This remote control sends the above command before and after - // each keypress - let's just drop this: - return false; - if (*Command == lastCommand) { - // let's have a timeout to avoid getting overrun by commands - int now = time_ms(); - int delta = now - lastTime; - lastTime = now; - if (delta < REPEATLIMIT) { // if commands come in rapidly... - if (now - firstTime < REPEATDELAY) - return false; // ...repeat function kicks in after a short delay - return true; - } + if (receivedData) { // first we check the boolean flag without a lock, to avoid delays + + LOCK_THREAD; + + if (receivedData) { // need to check again, since the status might have changed while waiting for the lock + if (Command) + *Command = receivedCommand; + if (Repeat) + *Repeat = receivedRepeat; + if (Release) + *Release = receivedRelease; + receivedData = false; + return true; } - lastTime = firstTime = time_ms(); - lastCommand = *Command; - return true; } if (time(NULL) - t > 60) { SendCommand(code); // in case the PIC listens to the wrong code @@ -254,6 +305,8 @@ bool cRcIoRCU::Digit(int n, int v) bool cRcIoRCU::Number(int n, bool Hex) { + LOCK_THREAD; + if (!Hex) { char buf[8]; sprintf(buf, "%4d", n & 0xFFFF); @@ -275,6 +328,8 @@ bool cRcIoRCU::Number(int n, bool Hex) bool cRcIoRCU::String(char *s) { + LOCK_THREAD; + const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP "; int n = 0; @@ -318,8 +373,11 @@ bool cRcIoRCU::DetectCode(unsigned char *Code, unsigned short *Address) sprintf(buf, "C0D%c", *Code); String(buf); SetCode(*Code, 0); - unsigned int Command; - if (GetCommand(&Command, Address)) { + delay_ms(REPEATDELAY); + receivedData = receivedRepeat = 0; + delay_ms(REPEATDELAY); + if (GetCommand()) { + *Address = receivedAddress; SetMode(modeB); String("----"); return true; @@ -337,77 +395,94 @@ bool cRcIoRCU::DetectCode(unsigned char *Code, unsigned short *Address) #elif defined REMOTE_LIRC +#define REPEATLIMIT 20 // ms +#define REPEATDELAY 350 // ms + cRcIoLIRC::cRcIoLIRC(char *DeviceName) { - repeat = 1; + *keyName = 0; + receivedData = receivedRepeat = false; struct sockaddr_un addr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, DeviceName); - int sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock >= 0) { - if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) >= 0) { - f.Open(sock); + if ((f = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) { + if (connect(f, (struct sockaddr *)&addr, sizeof(addr)) >= 0) { + Start(); return; } LOG_ERROR_STR(DeviceName); - close(sock); + close(f); } else LOG_ERROR_STR(DeviceName); + f = -1; } cRcIoLIRC::~cRcIoLIRC() { + Stop(); } -const char *cRcIoLIRC::ReceiveString(void) +void cRcIoLIRC::Action(void) { - int oldrepeat = 1; - - if (repeat != 0) { - Flush(); - if (repeat != 0) { - oldrepeat = repeat; - Flush(REPEATLIMIT); - } - } - - if (repeat == 0) { - firstTime = time_ms(); - repeat = 1; - return keyName; - } - - if ((repeat > 1) && (repeat != oldrepeat) && (time_ms() > firstTime + REPEATDELAY)) { - repeat = 1; - return keyName; - } + dsyslog(LOG_INFO, "LIRC remote control thread started (pid=%d)", getpid()); - return NULL; -} - -void cRcIoLIRC::Flush(int WaitMs) -{ + int FirstTime = 0; char buf[LIRC_BUFFER_SIZE]; - int t0 = time_ms(); - - do { - if (InputAvailable(false) && (read(f, buf, sizeof(buf)) > 21)) - sscanf(buf, "%*x %x %7s", &repeat, keyName); // '7' in '%7s' is LIRC_KEY_BUF-1! - } while ((repeat != 0) && (time_ms() < t0 + WaitMs)); -} - -bool cRcIoLIRC::InputAvailable(bool Wait) -{ - return f.Ready(Wait); + char LastKeyName[LIRC_KEY_BUF]; + + for (; f >= 0;) { + + LOCK_THREAD; + + if (cFile::FileReady(f, REPEATLIMIT) && read(f, buf, sizeof(buf)) > 21) { + if (!receivedData) { // only accept new data the previous data has been fetched + int count; + sscanf(buf, "%*x %x %7s", &count, LastKeyName); // '7' in '%7s' is LIRC_KEY_BUF-1! + int Now = time_ms(); + if (count == 0) { + strcpy(keyName, LastKeyName); + receivedData = true; + receivedRepeat = receivedRelease = false; + FirstTime = Now; + } + else { + if (Now - FirstTime < REPEATDELAY) + continue; // repeat function kicks in after a short delay + receivedData = receivedRepeat = true; + } + WakeUp(); + } + } + else if (receivedData) { // the last data before releasing the key hasn't been fetched yet + if (receivedRepeat) { // it was a repeat, so let's make it a release + receivedRepeat = false; + receivedRelease = true; + WakeUp(); + } + } + else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat, so let's generate a release + receivedData = receivedRelease = true; + receivedRepeat = false; + WakeUp(); + } + } } -bool cRcIoLIRC::GetCommand(unsigned int *Command, unsigned short *) +bool cRcIoLIRC::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) { - if (Command) { - const char *cmd = ReceiveString(); - if (cmd) { - *Command = Keys.Encode(cmd); + if (receivedData) { // first we check the boolean flag without a lock, to avoid delays + + LOCK_THREAD; + + if (receivedData) { // need to check again, since the status might have changed while waiting for the lock + if (Command) + *Command = Keys.Encode(keyName); + if (Repeat) + *Repeat = receivedRepeat; + if (Release) + *Release = receivedRelease; + receivedData = false; return true; } } |