diff options
author | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2002-09-29 18:00:00 +0200 |
---|---|---|
committer | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2002-09-29 18:00:00 +0200 |
commit | d08073815d6d9132f7fb5cd9f82877967dc6b0e4 (patch) | |
tree | f93fbe9f18ed2893d88dc4ce6d01d80804d664da /rcu.c | |
parent | 346f4cd1420bb02bd9cec4059385c9922d64fc3f (diff) | |
download | vdr-patch-lnbsharing-d08073815d6d9132f7fb5cd9f82877967dc6b0e4.tar.gz vdr-patch-lnbsharing-d08073815d6d9132f7fb5cd9f82877967dc6b0e4.tar.bz2 |
Version 1.1.11vdr-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.
Diffstat (limited to 'rcu.c')
-rw-r--r-- | rcu.c | 312 |
1 files changed, 312 insertions, 0 deletions
@@ -0,0 +1,312 @@ +/* + * rcu.c: RCU remote control + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: rcu.c 1.1 2002/09/29 13:16:44 kls Exp $ + */ + +#include "rcu.h" +#include <netinet/in.h> +#include <termios.h> +#include <unistd.h> +#include "tools.h" + +#define REPEATLIMIT 20 // ms +#define REPEATDELAY 350 // ms + +cRcuRemote::cRcuRemote(char *DeviceName) +:cRemote("RCU") +{ + dp = 0; + mode = modeB; + code = 0; + lastNumber = 0; + receivedCommand = false; + 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) { + Number(0);//XXX 8888??? + const char *Setup = GetSetup(); + if (Setup) { + code = *Setup; + SetCode(code); + isyslog("connecting to %s remote control using code %c", Name(), code); + } + Start(); + return; + } + } + LOG_ERROR_STR(DeviceName); + close(f); + } + else + LOG_ERROR_STR(DeviceName); + f = -1; +} + +cRcuRemote::~cRcuRemote() +{ + Cancel(); +} + +bool cRcuRemote::Initialize(void) +{ + if (f >= 0) { + unsigned char Code = '0'; + isyslog("trying codes for %s remote control...", Name()); + for (;;) { + if (DetectCode(&Code)) { + code = Code; + break; + } + } + isyslog("established connection to %s remote control using code %c", Name(), code); + char buffer[16]; + snprintf(buffer, sizeof(buffer), "%c", code); + PutSetup(buffer); + return true; + } + return false; +} + +void cRcuRemote::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()); + + time_t LastCodeRefresh = 0; + int FirstTime = 0; + uint64 LastCommand = 0; + bool repeat = false; + + //XXX + 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" + uint64 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(); + Command |= uint64(Address) << 32; + if (Command != LastCommand) { + LastCommand = Command; + repeat = false; + FirstTime = Now; + } + else { + if (Now - FirstTime < REPEATDELAY) + break; // repeat function kicks in after a short delay + repeat = true; + } + Put(Command, repeat); + receivedCommand = true; + } + } + else + break; + } + } + else if (repeat) { // the last one was a repeat, so let's generate a release + Put(LastCommand, false, true); + repeat = false; + LastCommand = 0; + } + else + LastCommand = 0; + if (code && time(NULL) - LastCodeRefresh > 60) { + SendCommand(code); // in case the PIC listens to the wrong code + LastCodeRefresh = time(NULL); + } + } +} + +int cRcuRemote::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 cRcuRemote::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 cRcuRemote::SendByte(unsigned char c) +{ + LOCK_THREAD; + + for (int retry = 5; retry--;) { + if (SendByteHandshake(c)) + return true; + } + return false; +} + +bool cRcuRemote::SetCode(unsigned char Code) +{ + code = Code; + return SendCommand(code); +} + +bool cRcuRemote::SetMode(unsigned char Mode) +{ + mode = Mode; + return SendCommand(mode); +} + +bool cRcuRemote::SendCommand(unsigned char Cmd) +{ + return SendByte(Cmd | 0x80); +} + +bool cRcuRemote::Digit(int n, int v) +{ + return SendByte(((n & 0x03) << 5) | (v & 0x0F) | (((dp >> n) & 0x01) << 4)); +} + +bool cRcuRemote::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 cRcuRemote::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 cRcuRemote::SetPoints(unsigned char Dp, bool On) +{ + if (On) + dp |= Dp; + else + dp &= ~Dp; + Number(lastNumber, true); +} + +bool cRcuRemote::DetectCode(unsigned char *Code) +{ + // 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); + delay_ms(2 * REPEATDELAY); + if (receivedCommand) { + SetMode(modeB); + String("----"); + return true; + } + if (*Code < 'D') { + (*Code)++; + return false; + } + } + *Code = 0; + return false; +} + +void cRcuRemote::ChannelSwitch(const cDevice *Device, int ChannelNumber) +{ + if (ChannelNumber && Device->IsPrimaryDevice()) + Number(ChannelNumber); +} + +void cRcuRemote::Recording(const cDevice *Device, const char *Name) +{ + SetPoints(1 << Device->CardIndex(), Device->Receiving()); //XXX CardNumber()!!! +} |