mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Remote control uses threads
This commit is contained in:
parent
60958ab132
commit
97c3bb6148
11
Makefile
11
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:
|
||||
|
||||
|
4
config.h
4
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
|
||||
|
||||
|
8
dvbosd.c
8
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
26
interface.c
26
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)) {
|
||||
if (open)
|
||||
cDvbApi::PrimaryDvbApi->Flush();
|
||||
if (!RcIo.InputAvailable())
|
||||
cFile::AnyFileReady(-1, Wait ? 1000 : 0);
|
||||
unsigned int Command;
|
||||
return RcIo.GetCommand(&Command, NULL) ? Command : 0;
|
||||
}
|
||||
return 0;
|
||||
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))
|
||||
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
|
||||
|
@ -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);
|
||||
|
289
remote.c
289
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,67 +254,32 @@ 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()
|
||||
LOCK_THREAD;
|
||||
|
||||
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
|
||||
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
|
||||
t = time(NULL);
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
if (repeat == 0) {
|
||||
firstTime = time_ms();
|
||||
repeat = 1;
|
||||
return keyName;
|
||||
}
|
||||
|
||||
if ((repeat > 1) && (repeat != oldrepeat) && (time_ms() > firstTime + REPEATDELAY)) {
|
||||
repeat = 1;
|
||||
return keyName;
|
||||
}
|
||||
|
||||
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));
|
||||
for (; f >= 0;) {
|
||||
|
||||
LOCK_THREAD;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool cRcIoLIRC::InputAvailable(bool Wait)
|
||||
bool cRcIoLIRC::GetCommand(unsigned int *Command)
|
||||
{
|
||||
return f.Ready(Wait);
|
||||
}
|
||||
if (receivedData) { // first we check the boolean flag without a lock, to avoid delays
|
||||
|
||||
bool cRcIoLIRC::GetCommand(unsigned int *Command, unsigned short *)
|
||||
{
|
||||
if (Command) {
|
||||
const char *cmd = ReceiveString();
|
||||
if (cmd) {
|
||||
*Command = Keys.Encode(cmd);
|
||||
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);
|
||||
//XXX repeat!!!
|
||||
receivedData = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
42
remote.h
42
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
|
||||
|
105
thread.c
Normal file
105
thread.c
Normal file
@ -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;
|
||||
}
|
||||
|
57
thread.h
Normal file
57
thread.h
Normal file
@ -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
|
18
tools.c
18
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)
|
||||
|
3
tools.h
3
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user