diff options
Diffstat (limited to 'remote.c')
-rw-r--r-- | remote.c | 519 |
1 files changed, 90 insertions, 429 deletions
@@ -1,12 +1,10 @@ /* - * remote.c: Interface to the Remote Control Unit + * remote.c: General Remote Control handling * * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * Ported to LIRC by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16. - * - * $Id: remote.c 1.27 2002/05/18 12:55:39 kls Exp $ + * $Id: remote.c 1.28 2002/09/29 12:51:26 kls Exp $ */ #include "remote.h" @@ -18,487 +16,150 @@ #include <termios.h> #include <unistd.h> -#if defined REMOTE_LIRC -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/un.h> -#endif - #if defined REMOTE_KBD #include <ncurses.h> #endif -#include "config.h" #include "tools.h" -// --- cRcIoBase ------------------------------------------------------------- +// --- cRemote --------------------------------------------------------------- -cRcIoBase::cRcIoBase(void) -{ - t = 0; -} +eKeys cRemote::keys[MaxKeys]; +int cRemote::in = 0; +int cRemote::out = 0; +bool cRemote::learning = false; +char *cRemote::unknownCode = NULL; +cMutex cRemote::mutex; +cCondVar cRemote::keyPressed; -cRcIoBase::~cRcIoBase() +cRemote::cRemote(const char *Name) { + if (Name) + name = strdup(Name); + Remotes.Add(this); } -// --- cRcIoKBD -------------------------------------------------------------- - -#if defined REMOTE_KBD - -cRcIoKBD::cRcIoKBD(void) +cRemote::~cRemote() { - f.Open(0); // stdin + free(name); } -cRcIoKBD::~cRcIoKBD() +const char *cRemote::GetSetup(void) { + return Keys.GetSetup(Name()); } -void cRcIoKBD::Flush(int WaitMs) +void cRemote::PutSetup(const char *Setup) { - int t0 = time_ms(); - - timeout(10); - for (;;) { - while (getch() > 0) - t0 = time_ms(); - if (time_ms() - t0 >= WaitMs) - break; - } + Keys.PutSetup(Name(), Setup); } -bool cRcIoKBD::InputAvailable(void) +void cRemote::Clear(void) { - return f.Ready(false); -} - -bool cRcIoKBD::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) -{ - if (Command) { - *Command = getch(); - return int(*Command) > 0; + cMutexLock MutexLock(&mutex); + in = out = 0; + if (learning) { + free(unknownCode); + unknownCode = NULL; } - return false; } -// --- cRcIoRCU -------------------------------------------------------------- - -#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)) >= 0) { - struct termios t; - if (tcgetattr(f, &t) == 0) { - cfsetspeed(&t, B9600); - cfmakeraw(&t); - if (tcsetattr(f, TCSAFLUSH, &t) == 0) { - Start(); - return; - } +bool cRemote::Put(eKeys Key) +{ + if (Key != kNone) { + cMutexLock MutexLock(&mutex); + if ((Key & k_Release) != 0) + Clear(); + int d = out - in; + if (d <= 0) + d = MaxKeys + d; + if (d - 1 > 0) { + keys[in] = Key; + if (++in >= MaxKeys) + in = 0; + keyPressed.Broadcast(); + return true; } - LOG_ERROR_STR(DeviceName); - close(f); + return false; } - else - LOG_ERROR_STR(DeviceName); - f = -1; -} - -cRcIoRCU::~cRcIoRCU() -{ - Cancel(); + return true; // only a real key shall report an overflow! } -void cRcIoRCU::Action(void) +bool cRemote::Put(uint64 Code, bool Repeat, bool Release) { -#pragma pack(1) - union { - struct { - unsigned short address; - unsigned int command; - } data; - unsigned char raw[6]; - } buffer; -#pragma pack() - - dsyslog("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; - } + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%016LX", Code); + return Put(buffer, Repeat, Release); } -int cRcIoRCU::ReceiveByte(int TimeoutMs) +bool cRemote::Put(const char *Code, bool Repeat, bool Release) { - // Returns the byte if one was received within a timeout, -1 otherwise - if (cFile::FileReady(f, TimeoutMs)) { - unsigned char b; - if (safe_read(f, &b, 1) == 1) - return b; - else - LOG_ERROR; + eKeys Key = Keys.Get(Name(), Code); + if (Key != kNone) { + if (Repeat) + Key = eKeys(Key | k_Repeat); + if (Release) + Key = eKeys(Key | k_Release); + return Put(Key); } - return -1; -} - -bool cRcIoRCU::SendByteHandshake(unsigned char c) -{ - if (f >= 0) { - int w = write(f, &c, 1); - if (w == 1) { - 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() < 0) - return false; - } - } - else - return false; - } - } - LOG_ERROR; + if (learning) { + free(unknownCode); + unknownCode = strdup(Code); + keyPressed.Broadcast(); } return false; } -bool cRcIoRCU::SendByte(unsigned char c) +eKeys cRemote::Get(int WaitMs, char **UnknownCode) { - LOCK_THREAD; - - for (int retry = 5; retry--;) { - if (SendByteHandshake(c)) - return true; - } - return false; -} - -bool cRcIoRCU::SetCode(unsigned char Code, unsigned short Address) -{ - code = Code; - address = Address; - return SendCommand(code); -} - -bool cRcIoRCU::SetMode(unsigned char Mode) -{ - mode = Mode; - return SendCommand(mode); -} - -void cRcIoRCU::Flush(int WaitMs) -{ - LOCK_THREAD; - - int t0 = time_ms(); for (;;) { - while (ReceiveByte() >= 0) - t0 = time_ms(); - if (time_ms() - t0 >= WaitMs) - break; - } - receivedData = receivedRepeat = false; -} - -bool cRcIoRCU::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) -{ - 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; - } - } - if (time(NULL) - t > 60) { - SendCommand(code); // in case the PIC listens to the wrong code - t = time(NULL); - } - return false; -} - -bool cRcIoRCU::SendCommand(unsigned char Cmd) -{ - return SendByte(Cmd | 0x80); -} - -bool cRcIoRCU::Digit(int n, int v) -{ - return SendByte(((n & 0x03) << 5) | (v & 0x0F) | (((dp >> n) & 0x01) << 4)); -} - -bool cRcIoRCU::Number(int n, bool Hex) -{ - LOCK_THREAD; - - if (!Hex) { - char buf[8]; - sprintf(buf, "%4d", n & 0xFFFF); - n = 0; - for (char *d = buf; *d; d++) { - if (*d == ' ') - *d = 0xF; - n = (n << 4) | ((*d - '0') & 0x0F); + cMutexLock MutexLock(&mutex); + if (in != out) { + eKeys k = keys[out]; + if (++out >= MaxKeys) + out = 0; + return k; + } + else if (!WaitMs || !keyPressed.TimedWait(mutex, WaitMs)) { + if (learning && UnknownCode) { + *UnknownCode = unknownCode; + unknownCode = NULL; + } + return kNone; } - } - lastNumber = n; - for (int i = 0; i < 4; i++) { - if (!Digit(i, n)) - return false; - n >>= 4; } - return SendCommand(mode); } -bool cRcIoRCU::String(char *s) -{ - LOCK_THREAD; +// --- cRemotes -------------------------------------------------------------- - const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP "; - int n = 0; +cRemotes Remotes; - for (int i = 0; *s && i < 4; s++, i++) { - n <<= 4; - for (const char *c = chars; *c; c++) { - if (*c == *s) { - n |= c - chars; - break; - } - } - } - return Number(n, true); -} - -void cRcIoRCU::SetPoints(unsigned char Dp, bool On) -{ - if (On) - dp |= Dp; - else - dp &= ~Dp; - Number(lastNumber, true); -} +// --- cKbdRemote ------------------------------------------------------------ -bool cRcIoRCU::DetectCode(unsigned char *Code, unsigned short *Address) -{ - // Caller should initialize 'Code' to 0 and call DetectCode() - // until it returns true. Whenever DetectCode() returns false - // and 'Code' is not 0, the caller can use 'Code' to display - // a message like "Trying code '%c'". If false is returned and - // 'Code' is 0, all possible codes have been tried and the caller - // can either stop calling DetectCode() (and give some error - // message), or start all over again. - if (*Code < 'A' || *Code > 'D') { - *Code = 'A'; - return false; - } - if (*Code <= 'D') { - SetMode(modeH); - char buf[5]; - sprintf(buf, "C0D%c", *Code); - String(buf); - SetCode(*Code, 0); - delay_ms(REPEATDELAY); - receivedData = receivedRepeat = 0; - delay_ms(REPEATDELAY); - if (GetCommand()) { - *Address = receivedAddress; - SetMode(modeB); - String("----"); - return true; - } - if (*Code < 'D') { - (*Code)++; - return false; - } - } - *Code = 0; - return false; -} - -// --- cRcIoLIRC ------------------------------------------------------------- - -#elif defined REMOTE_LIRC - -#define REPEATLIMIT 20 // ms -#define REPEATDELAY 350 // ms +#if defined REMOTE_KBD -cRcIoLIRC::cRcIoLIRC(char *DeviceName) +cKbdRemote::cKbdRemote(void) +:cRemote("KBD") { - *keyName = 0; - receivedData = receivedRepeat = false; - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, DeviceName); - 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(f); - } - else - LOG_ERROR_STR(DeviceName); - f = -1; + Start(); } -cRcIoLIRC::~cRcIoLIRC() +cKbdRemote::~cKbdRemote() { Cancel(); } -void cRcIoLIRC::Action(void) +void cKbdRemote::Action(void) { - dsyslog("LIRC remote control thread started (pid=%d)", getpid()); - - int FirstTime = 0; - int LastTime = 0; - char buf[LIRC_BUFFER_SIZE]; - char LastKeyName[LIRC_KEY_BUF]; - - for (; f >= 0;) { - - LOCK_THREAD; - - if (cFile::FileReady(f, REPEATLIMIT) && safe_read(f, buf, sizeof(buf)) > 21) { - if (!receivedData) { // only accept new data the previous data has been fetched - int count; - sscanf(buf, "%*x %x %29s", &count, LastKeyName); // '29' in '%29s' 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; - receivedRelease = false; - } - LastTime = Now; - 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 - if (time_ms() - LastTime > REPEATDELAY) { - 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 - if (time_ms() - LastTime > REPEATDELAY) { - receivedData = receivedRelease = true; - receivedRepeat = false; - WakeUp(); - } - } + dsyslog("KBD remote control thread started (pid=%d)", getpid()); + cPoller Poller(STDIN_FILENO); + for (;;) {//XXX + int Command = getch(); + if (Command != EOF) + Put(Command); + Poller.Poll(100); } -} - -bool cRcIoLIRC::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) -{ - 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; - } - } - return false; + dsyslog("KBD remote control thread ended (pid=%d)", getpid()); } #endif - |