From 97c3bb61482855769f0208062610543475f02006 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 8 Oct 2000 09:25:20 +0200 Subject: Remote control uses threads --- Makefile | 11 +-- config.h | 4 +- dvbosd.c | 8 +- interface.c | 30 ++++--- interface.h | 4 +- remote.c | 289 +++++++++++++++++++++++++++++++++++++----------------------- remote.h | 42 ++++----- thread.c | 105 ++++++++++++++++++++++ thread.h | 57 ++++++++++++ tools.c | 18 +++- tools.h | 3 +- 11 files changed, 415 insertions(+), 156 deletions(-) create mode 100644 thread.c create mode 100644 thread.h diff --git a/Makefile b/Makefile index 15757744..8b32be2d 100644 --- a/Makefile +++ b/Makefile @@ -4,13 +4,13 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.12 2000/10/01 14:27:12 kls Exp $ +# $Id: Makefile 1.13 2000/10/07 16:24:08 kls Exp $ DVBDIR = ../DVB INCLUDES = -I$(DVBDIR)/driver OBJS = config.o dvbapi.o dvbosd.o eit.o font.o interface.o menu.o osd.o\ - recording.o remote.o svdrp.o tools.o vdr.o videodir.o + recording.o remote.o svdrp.o thread.o tools.o vdr.o videodir.o OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 @@ -40,12 +40,13 @@ dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tool dvbosd.o : dvbosd.c dvbosd.h font.h tools.h eit.o : eit.c eit.h tools.h font.o : font.c font.h fontosd.c tools.h -interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h tools.h +interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h menu.o : menu.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h osd.o : osd.c config.h dvbapi.h dvbosd.h font.h interface.h osd.h svdrp.h tools.h recording.o: recording.c config.h dvbapi.h dvbosd.h font.h interface.h recording.h svdrp.h tools.h videodir.h -remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h tools.h +remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h thread.h tools.h svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h +thread.o : thread.c thread.h tools.o : tools.c tools.h vdr.o : vdr.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h videodir.o : videodir.c tools.h videodir.h @@ -53,7 +54,7 @@ videodir.o : videodir.c tools.h videodir.h # The main program: vdr: $(OBJS) - g++ -g -O2 $(OBJS) -lncurses -ljpeg -o vdr + g++ -g -O2 $(OBJS) -lncurses -ljpeg -lpthread -o vdr # The font file: diff --git a/config.h b/config.h index 224a7b3b..99a57eba 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.22 2000/10/01 14:14:18 kls Exp $ + * $Id: config.h 1.23 2000/10/07 17:34:23 kls Exp $ */ #ifndef __CONFIG_H @@ -17,7 +17,7 @@ #include "dvbapi.h" #include "tools.h" -#define VDRVERSION "0.65" +#define VDRVERSION "0.66" #define MaxBuffer 10000 diff --git a/dvbosd.c b/dvbosd.c index 1e2c354e..97c79322 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,10 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.2 2000/10/03 13:34:13 kls Exp $ + * $Id: dvbosd.c 1.3 2000/10/07 14:42:48 kls Exp $ */ #include "dvbosd.h" +#include #include #include #include @@ -138,11 +139,16 @@ void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co dc.x1 = x1; dc.y1 = y1; dc.data = (void *)data; + // must block all signals, otherwise the command might not be fully executed + sigset_t set, oldset; + sigfillset(&set); + sigprocmask(SIG_BLOCK, &set, &oldset); ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc); usleep(10); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places // XXX and sometimes the OSD was no longer displayed). // XXX Increase the value if the problem still persists on your particular system. // TODO Check if this is still necessary with driver versions after 0.7. + sigprocmask(SIG_SETMASK, &oldset, NULL); } } diff --git a/interface.c b/interface.c index a0fca0ea..485a5dd0 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.21 2000/10/03 13:28:02 kls Exp $ + * $Id: interface.c 1.22 2000/10/07 16:42:37 kls Exp $ */ #include "interface.h" @@ -60,17 +60,16 @@ void cInterface::Close(void) unsigned int cInterface::GetCh(bool Wait) { - if (RcIo.InputAvailable(Wait)) { - unsigned int Command; - return RcIo.GetCommand(&Command, NULL) ? Command : 0; - } - return 0; + if (open) + cDvbApi::PrimaryDvbApi->Flush(); + if (!RcIo.InputAvailable()) + cFile::AnyFileReady(-1, Wait ? 1000 : 0); + unsigned int Command; + return RcIo.GetCommand(&Command) ? Command : 0; } eKeys cInterface::GetKey(bool Wait) { - if (open) - cDvbApi::PrimaryDvbApi->Flush(); if (SVDRP) SVDRP->Process(); eKeys Key = keyFromWait != kNone ? keyFromWait : Keys.Get(GetCh(Wait)); @@ -85,12 +84,15 @@ void cInterface::PutKey(eKeys Key) eKeys cInterface::Wait(int Seconds, bool KeepChar) { - eKeys Key = kNone; if (open) cDvbApi::PrimaryDvbApi->Flush(); - RcIo.Flush(500); - if (cFile::AnyFileReady(-1, Seconds * 1000)) - Key = GetKey(); + eKeys Key = kNone; + time_t timeout = time(NULL) + Seconds; + for (;;) { + Key = GetKey(); + if (Key != kNone || time(NULL) > timeout) + break; + } if (KeepChar) keyFromWait = Key; return Key; @@ -220,9 +222,11 @@ void cInterface::Help(const char *Red, const char *Green, const char *Yellow, co void cInterface::QueryKeys(void) { Keys.Clear(); + Clear(); WriteText(1, 1, "Learning Remote Control Keys"); WriteText(1, 3, "Phase 1: Detecting RC code type"); WriteText(1, 5, "Press any key on the RC unit"); + cDvbApi::PrimaryDvbApi->Flush(); #ifndef REMOTE_KBD unsigned char Code = 0; unsigned short Address; @@ -238,9 +242,11 @@ void cInterface::QueryKeys(void) Keys.address = Address; WriteText(1, 5, "RC code detected!"); WriteText(1, 6, "Do not press any key..."); + cDvbApi::PrimaryDvbApi->Flush(); RcIo.Flush(3000); ClearEol(0, 5); ClearEol(0, 6); + cDvbApi::PrimaryDvbApi->Flush(); break; } #endif diff --git a/interface.h b/interface.h index 8f7f1b8d..c5592983 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.13 2000/09/18 22:29:31 kls Exp $ + * $Id: interface.h 1.14 2000/10/07 16:17:53 kls Exp $ */ #ifndef __INTERFACE_H @@ -38,7 +38,7 @@ public: void ClearEol(int x, int y, eDvbColor Color = clrBackground); void SetCols(int *c); void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); - void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBlack); + void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); void Title(const char *s); void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan); void Info(const char *s); diff --git a/remote.c b/remote.c index 1bf81085..968184a5 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.16 2000/10/08 09:25:20 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) { if (Command) { *Command = getch(); @@ -87,36 +82,119 @@ 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 = 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() { } -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()); + + unsigned int LastCommand = 0; + int FirstTime = 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; + int Now = time_ms(); + if (Command != LastCommand) { + receivedAddress = Address; + receivedCommand = Command; + receivedData = true; + 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 drop it + //XXX replace it with "released"??? + receivedData = receivedRepeat = false; + LastCommand = 0; + //XXX WakeUp(); + } + } + else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat + //XXX replace it with "released"??? + //XXX receivedData = 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 +206,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 +230,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 +254,31 @@ 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) { - return f.Ready(Wait); -} + if (receivedData) { // first we check the boolean flag without a lock, to avoid delays -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; - } + LOCK_THREAD; + + if (receivedData) { // need to check again, since the status might have changed while waiting for the lock + if (Command) + *Command = receivedCommand; + //XXX repeat!!! + 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 +299,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 +322,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 +367,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 +389,90 @@ 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() { } -const char *cRcIoLIRC::ReceiveString(void) +void cRcIoLIRC::Action(void) { - int oldrepeat = 1; + dsyslog(LOG_INFO, "LIRC remote control thread started (pid=%d)", getpid()); - if (repeat != 0) { - Flush(); - if (repeat != 0) { - oldrepeat = repeat; - Flush(REPEATLIMIT); - } - } + int FirstTime = 0; + char buf[LIRC_BUFFER_SIZE]; - if (repeat == 0) { - firstTime = time_ms(); - repeat = 1; - return keyName; - } + for (; f >= 0;) { - if ((repeat > 1) && (repeat != oldrepeat) && (time_ms() > firstTime + REPEATDELAY)) { - repeat = 1; - return keyName; - } + LOCK_THREAD; - return NULL; + if (cFile::FileReady(f, REPEATLIMIT) && read(f, buf, sizeof(buf)) > 21) { + int count; + sscanf(buf, "%*x %x %7s", &count, keyName); // '7' in '%7s' is LIRC_KEY_BUF-1! + int Now = time_ms(); + if (count == 0) { + receivedData = true; + 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 drop it + //XXX replace it with "released"??? + receivedData = receivedRepeat = false; + *keyName = 0; + //XXX WakeUp(); + } + } + else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat + //XXX replace it with "released"??? + //XXX receivedData = true; + receivedRepeat = false; + *keyName = 0; + WakeUp(); + } + else + *keyName = 0; + } } -void cRcIoLIRC::Flush(int WaitMs) +bool cRcIoLIRC::GetCommand(unsigned int *Command) { - 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)); -} + if (receivedData) { // first we check the boolean flag without a lock, to avoid delays -bool cRcIoLIRC::InputAvailable(bool Wait) -{ - return f.Ready(Wait); -} + LOCK_THREAD; -bool cRcIoLIRC::GetCommand(unsigned int *Command, unsigned short *) -{ - if (Command) { - const char *cmd = ReceiveString(); - if (cmd) { - *Command = Keys.Encode(cmd); + if (receivedData) { // need to check again, since the status might have changed while waiting for the lock + if (Command) + *Command = Keys.Encode(keyName); + //XXX repeat!!! + receivedData = false; return true; } } diff --git a/remote.h b/remote.h index 75dc4ac1..b9e79b4d 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.10 2000/10/03 10:45:35 kls Exp $ + * $Id: remote.h 1.11 2000/10/07 18:50:51 kls Exp $ */ #ifndef __REMOTE_H @@ -12,13 +12,12 @@ #include #include +#include "thread.h" #include "tools.h" class cRcIoBase { protected: time_t t; - int firstTime, lastTime; - unsigned int lastCommand; cRcIoBase(void); virtual ~cRcIoBase(); public: @@ -29,9 +28,9 @@ public: virtual void SetPoints(unsigned char Dp, bool On) {} virtual bool String(char *s) { return true; } virtual bool DetectCode(unsigned char *Code, unsigned short *Address) { return true; } - virtual void Flush(int WaitMs = 0) = 0; - virtual bool InputAvailable(bool Wait = false) = 0; - virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL) = 0; + virtual void Flush(int WaitMs = 0) {} + virtual bool InputAvailable(void) = 0; + virtual bool GetCommand(unsigned int *Command = NULL) = 0; }; #if defined REMOTE_KBD @@ -43,23 +42,27 @@ public: cRcIoKBD(void); virtual ~cRcIoKBD(); virtual void Flush(int WaitMs = 0); - virtual bool InputAvailable(bool Wait = false); - virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); + virtual bool InputAvailable(void); + virtual bool GetCommand(unsigned int *Command = NULL); }; #elif defined REMOTE_RCU -class cRcIoRCU : public cRcIoBase { +class cRcIoRCU : public cRcIoBase, private cThread { private: - cFile f; + int f; unsigned char dp, code, mode; unsigned short address; + unsigned short receivedAddress; + unsigned int receivedCommand; + bool receivedData, receivedRepeat; int lastNumber; bool SendCommand(unsigned char Cmd); - int ReceiveByte(bool Wait = true); + int ReceiveByte(int TimeoutMs = 0); bool SendByteHandshake(unsigned char c); bool SendByte(unsigned char c); bool Digit(int n, int v); + virtual void Action(void); public: cRcIoRCU(char *DeviceName); virtual ~cRcIoRCU(); @@ -70,25 +73,24 @@ public: virtual bool String(char *s); virtual bool DetectCode(unsigned char *Code, unsigned short *Address); virtual void Flush(int WaitMs = 0); - virtual bool InputAvailable(bool Wait = false); - virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); + virtual bool InputAvailable(void) { return receivedData; } + virtual bool GetCommand(unsigned int *Command = NULL); }; #elif defined REMOTE_LIRC -class cRcIoLIRC : public cRcIoBase { +class cRcIoLIRC : public cRcIoBase, private cThread { private: enum { LIRC_KEY_BUF = 8, LIRC_BUFFER_SIZE = 128 }; - cFile f; + int f; char keyName[LIRC_KEY_BUF]; - int repeat; - const char *ReceiveString(void); + bool receivedData, receivedRepeat; + virtual void Action(void); public: cRcIoLIRC(char *DeviceName); virtual ~cRcIoLIRC(); - virtual void Flush(int WaitMs = 0); - virtual bool InputAvailable(bool Wait = false); - virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); + virtual bool InputAvailable(void) { return receivedData; } + virtual bool GetCommand(unsigned int *Command = NULL); }; #else diff --git a/thread.c b/thread.c new file mode 100644 index 00000000..7e3ee939 --- /dev/null +++ b/thread.c @@ -0,0 +1,105 @@ +/* + * thread.c: A simple thread base class + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: thread.c 1.1 2000/10/07 17:31:39 kls Exp $ + */ + +#include "thread.h" +#include +#include + +// --- cThread --------------------------------------------------------------- + +// The signal handler is necessary to be able to use SIGIO to wake up any +// pending 'select()' call. + +bool cThread::signalHandlerInstalled = false; + +cThread::cThread(void) +{ + if (!signalHandlerInstalled) { + signal(SIGIO, SignalHandler); + signalHandlerInstalled = true; + } + pthread_mutex_init(&mutex, NULL); + running = false; + parentPid = lockingPid = 0; + locked = 0; +} + +cThread::~cThread() +{ + pthread_mutex_destroy(&mutex); +} + +void cThread::SignalHandler(int signum) +{ + signal(signum, SignalHandler); +} + +void *cThread::StartThread(cThread *Thread) +{ + Thread->Action(); + return NULL; +} + +bool cThread::Start(void) +{ + if (!running) { + running = true; + parentPid = getpid(); + pthread_create(&thread, NULL, &StartThread, (void *)this); + } + return true; //XXX return value of pthread_create()??? +} + +void cThread::Stop(void) +{ + pthread_exit(NULL); +} + +bool cThread::Lock(void) +{ + if (!lockingPid || lockingPid != getpid()) { + pthread_mutex_lock(&mutex); + lockingPid = getpid(); + } + locked++; + return true; +} + +void cThread::Unlock(void) +{ + if (!--locked) { + lockingPid = 0; + pthread_mutex_unlock(&mutex); + } +} + +void cThread::WakeUp(void) +{ + kill(parentPid, SIGIO); // makes any waiting 'select()' call return immediately +} + +// --- cThreadLock ----------------------------------------------------------- + +cThreadLock::cThreadLock(cThread *Thread) +{ + thread = Thread; + locked = Thread->Lock(); +} + +cThreadLock::~cThreadLock() +{ + if (locked) + thread->Unlock(); +} + +bool cThreadLock::Locked(void) +{ + return locked; +} + diff --git a/thread.h b/thread.h new file mode 100644 index 00000000..86b9e922 --- /dev/null +++ b/thread.h @@ -0,0 +1,57 @@ +/* + * thread.h: A simple thread base class + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: thread.h 1.1 2000/10/08 08:36:21 kls Exp $ + */ + +#ifndef __THREAD_H +#define __THREAD_H + +#include +#include + +class cThread { + friend class cThreadLock; +private: + pthread_t thread; + pthread_mutex_t mutex; + pid_t parentPid, lockingPid; + int locked; + bool running; + static bool signalHandlerInstalled; + static void SignalHandler(int signum); + static void *StartThread(cThread *Thread); + bool Lock(void); + void Unlock(void); +protected: + void WakeUp(void); + virtual void Action(void) = 0; + void Stop(void); +public: + cThread(void); + virtual ~cThread(); + bool Start(void); + }; + +// cThreadLock can be used to easily set a lock in a thread and make absolutely +// sure that it will be unlocked when the block will be left. Several locks can +// be stacked, so a function that makes many calls to another function which uses +// cThreadLock may itself use a cThreadLock to make one longer lock instead of many +// short ones. + +class cThreadLock { +private: + cThread *thread; + bool locked; +public: + cThreadLock(cThread *Thread); + ~cThreadLock(); + bool Locked(void); + }; + +#define LOCK_THREAD cThreadLock ThreadLock(this) + +#endif //__THREAD_H diff --git a/tools.c b/tools.c index 5bb56e6d..fc15a985 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.20 2000/09/29 16:19:28 kls Exp $ + * $Id: tools.c 1.21 2000/10/07 18:02:24 kls Exp $ */ #define _GNU_SOURCE @@ -393,6 +393,22 @@ bool cFile::AnyFileReady(int FileDes, int TimeoutMs) return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && (FileDes < 0 || FD_ISSET(FileDes, &set)); } +bool cFile::FileReady(int FileDes, int TimeoutMs) +{ +#ifdef DEBUG_OSD + refresh(); +#endif + fd_set set; + struct timeval timeout; + FD_ZERO(&set); + FD_SET(FileDes, &set); + if (TimeoutMs < 100) + TimeoutMs = 100; + timeout.tv_sec = 0; + timeout.tv_usec = TimeoutMs * 1000; + return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set); +} + // --- cListObject ----------------------------------------------------------- cListObject::cListObject(void) diff --git a/tools.h b/tools.h index 441f5715..17b643ff 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.16 2000/09/29 16:19:31 kls Exp $ + * $Id: tools.h 1.17 2000/10/07 18:00:21 kls Exp $ */ #ifndef __TOOLS_H @@ -68,6 +68,7 @@ public: int ReadString(char *Buffer, int Size); bool Ready(bool Wait = true); static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000); + static bool FileReady(int FileDes, int TimeoutMs = 1000); }; class cListObject { -- cgit v1.2.3