From a379eb714f7f5ef9a12efbe7588bb3509faba056 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 8 Oct 2000 18:00:00 +0200 Subject: Version 0.66 - Remote control data is now received in a separate thread, which makes things a lot smoother. - Repeat and release of remote control keys is now explicitly distinguished. - In replay mode the search forward/back and skip functions now have two modes: Pressing the key shortly and releasing it starts the function, and pressing it again stops it. Pressing and holding down the key starts the function and releasing the key stops it. - The '@' character that marks an "instant recording" can now be turned off in the "Setup" menu (thanks to Matthias Schniedermeyer). - Pressing the "Back" button while replaying now stops replaying and brings up the "Recordings" menu (suggested by Carsten Koch). This can be used to easily delete a recording after watching it, or to switch to a different recording. - The "Recordings" menu now places the cursor on the last replayed recording, if that file still exists. - The "Blue" button in the "Main" menu can now be used to "Resume" a previously stopped replay session (suggested by Martin Hammerschmid). - The low and high LNB frequencies can now be changed in the "Setup" menu. --- remote.c | 309 +++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 192 insertions(+), 117 deletions(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index 1bf8108..f60d768 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 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; } } -- cgit v1.2.3