summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2000-10-08 09:25:20 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2000-10-08 09:25:20 +0200
commit97c3bb61482855769f0208062610543475f02006 (patch)
tree98ed285302e4b4a9fcc6186587b2da234776ec14
parent60958ab1323d4f4750338165b89a99f4f2fbe4a7 (diff)
downloadvdr-97c3bb61482855769f0208062610543475f02006.tar.gz
vdr-97c3bb61482855769f0208062610543475f02006.tar.bz2
Remote control uses threads
-rw-r--r--Makefile11
-rw-r--r--config.h4
-rw-r--r--dvbosd.c8
-rw-r--r--interface.c30
-rw-r--r--interface.h4
-rw-r--r--remote.c289
-rw-r--r--remote.h42
-rw-r--r--thread.c105
-rw-r--r--thread.h57
-rw-r--r--tools.c18
-rw-r--r--tools.h3
11 files changed, 415 insertions, 156 deletions
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 <signal.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/unistd.h>
@@ -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 <Carsten.Koch@icem.de> 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 <stdio.h>
#include <time.h>
+#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 <signal.h>
+#include <unistd.h>
+
+// --- 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 <pthread.h>
+#include <sys/types.h>
+
+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 {