Version 1.1.11

- Fixed an incomplete initialization of the filter parameters in eit.c (thanks
  to Jeremy Hall).
- Fixed the 'newplugin' script for use with the NEWSTRUCT driver (thanks to
  Andreas Schultz for reporting this one). If you have already created a plugin
  directory and Makefile with 'newplugin', please apply the following patch to it:

  -------------------------------------------------------
  --- Makefile    2002/06/10 16:24:06     1.4
  +++ Makefile    2002/09/17 15:36:36     1.5
  @@ -15,7 +15,12 @@

   ### The directory environment:

  +ifdef NEWSTRUCT
  +DVBDIR = ../../../../DVB/include
  +DEFINES += -DNEWSTRUCT
  +else
   DVBDIR = ../../../../DVB/ost/include
  +endif
   VDRDIR = ../../..
   VDRINC = $(VDRDIR)/include
   LIBDIR = ../../lib
  @@ -34,7 +39,7 @@

   INCLUDES = -I$(VDRINC) -I$(DVBDIR)

  -DEFINES = -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
  +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'

   ### The object files (add further files here):
  -------------------------------------------------------

  This is the diff for the 'setup' example that comes with VDR, so your line
  numbers may be different.
- Added a missing 'public' keyword in device.h (thanks to Martin Hammerschmid).
- Fixed a race condition when starting 'Transfer Mode'.
- Rearranged the remote control key handling to allow plugins to implement
  additional types of remote controls (see PLUGINS.html, section "Remote Control").
  The previously used files 'keys.conf' and 'keys-pc.conf' have been replaced
  by the file 'remote.conf', which holds the key definitions of all remote controls.
- The LIRC remote control keys are now handled just like the keyboard and RCU keys.
  This means that you can use the lircd.conf file as is for your remote control,
  without the need of editing it to make the key names the same as used in VDR.
  When first starting VDR it will go into the "Learning keys" mode and ask you
  to press the various keys. The resulting key assignment will be stored in
  the file 'remote.conf'.
  Since I have no way of testing the LIRC support, I hope I didn't break it in
  the process...
- While learning the remote control keys it is now possible to press the 'Menu'
  key to skip the definition of keys that are not available on your particular
  RC unit.
- Fixed handling DVD subtitles in the SPU decoder (thanks to Andreas Schultz).
- Avoiding restarts due to 'panic level' when switching channels on the primary
  device during EPG scan.
This commit is contained in:
Klaus Schmidinger
2002-09-29 18:00:00 +02:00
parent 346f4cd142
commit d08073815d
40 changed files with 1313 additions and 1084 deletions

581
remote.c
View File

@@ -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)
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;
cRemote::cRemote(const char *Name)
{
t = 0;
if (Name)
name = strdup(Name);
Remotes.Add(this);
}
cRcIoBase::~cRcIoBase()
cRemote::~cRemote()
{
free(name);
}
// --- cRcIoKBD --------------------------------------------------------------
const char *cRemote::GetSetup(void)
{
return Keys.GetSetup(Name());
}
void cRemote::PutSetup(const char *Setup)
{
Keys.PutSetup(Name(), Setup);
}
void cRemote::Clear(void)
{
cMutexLock MutexLock(&mutex);
in = out = 0;
if (learning) {
free(unknownCode);
unknownCode = NULL;
}
}
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;
}
return false;
}
return true; // only a real key shall report an overflow!
}
bool cRemote::Put(uint64 Code, bool Repeat, bool Release)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "%016LX", Code);
return Put(buffer, Repeat, Release);
}
bool cRemote::Put(const char *Code, bool Repeat, bool Release)
{
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);
}
if (learning) {
free(unknownCode);
unknownCode = strdup(Code);
keyPressed.Broadcast();
}
return false;
}
eKeys cRemote::Get(int WaitMs, char **UnknownCode)
{
for (;;) {
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;
}
}
}
// --- cRemotes --------------------------------------------------------------
cRemotes Remotes;
// --- cKbdRemote ------------------------------------------------------------
#if defined REMOTE_KBD
cRcIoKBD::cRcIoKBD(void)
cKbdRemote::cKbdRemote(void)
:cRemote("KBD")
{
f.Open(0); // stdin
Start();
}
cRcIoKBD::~cRcIoKBD()
{
}
void cRcIoKBD::Flush(int WaitMs)
{
int t0 = time_ms();
timeout(10);
for (;;) {
while (getch() > 0)
t0 = time_ms();
if (time_ms() - t0 >= WaitMs)
break;
}
}
bool cRcIoKBD::InputAvailable(void)
{
return f.Ready(false);
}
bool cRcIoKBD::GetCommand(unsigned int *Command, bool *Repeat, bool *Release)
{
if (Command) {
*Command = getch();
return int(*Command) > 0;
}
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;
}
}
LOG_ERROR_STR(DeviceName);
close(f);
}
else
LOG_ERROR_STR(DeviceName);
f = -1;
}
cRcIoRCU::~cRcIoRCU()
cKbdRemote::~cKbdRemote()
{
Cancel();
}
void cRcIoRCU::Action(void)
void cKbdRemote::Action(void)
{
#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;
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);
}
}
int cRcIoRCU::ReceiveByte(int TimeoutMs)
{
// 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;
}
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;
}
return false;
}
bool cRcIoRCU::SendByte(unsigned char c)
{
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);
}
}
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;
const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP ";
int n = 0;
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);
}
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
cRcIoLIRC::cRcIoLIRC(char *DeviceName)
{
*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;
}
cRcIoLIRC::~cRcIoLIRC()
{
Cancel();
}
void cRcIoLIRC::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();
}
}
}
}
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