Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

rcu.c

Go to the documentation of this file.
00001 /*
00002  * rcu.c: RCU remote control
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: rcu.c 1.3 2002/12/07 12:22:40 kls Exp $
00008  */
00009 
00010 #include "rcu.h"
00011 #include <netinet/in.h>
00012 #include <termios.h>
00013 #include <unistd.h>
00014 #include "tools.h"
00015 
00016 #define REPEATLIMIT  20 // ms
00017 #define REPEATDELAY 350 // ms
00018 
00019 cRcuRemote::cRcuRemote(char *DeviceName)
00020 :cRemote("RCU")
00021 {
00022   dp = 0;
00023   mode = modeB;
00024   code = 0;
00025   numberToSend = -1;
00026   lastNumber = 0;
00027   receivedCommand = false;
00028   if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) {
00029      struct termios t;
00030      if (tcgetattr(f, &t) == 0) {
00031         cfsetspeed(&t, B9600);
00032         cfmakeraw(&t);
00033         if (tcsetattr(f, TCSAFLUSH, &t) == 0) {
00034            Number(0);//XXX 8888???
00035            const char *Setup = GetSetup();
00036            if (Setup) {
00037               code = *Setup;
00038               SetCode(code);
00039               isyslog("connecting to %s remote control using code %c", Name(), code);
00040               }
00041            Start();
00042            return;
00043            }
00044         }
00045      LOG_ERROR_STR(DeviceName);
00046      close(f);
00047      }
00048   else
00049      LOG_ERROR_STR(DeviceName);
00050   f = -1;
00051 }
00052 
00053 cRcuRemote::~cRcuRemote()
00054 {
00055   Cancel();
00056 }
00057 
00058 bool cRcuRemote::Initialize(void)
00059 {
00060   if (f >= 0) {
00061      unsigned char Code = '0';
00062      isyslog("trying codes for %s remote control...", Name());
00063      for (;;) {
00064          if (DetectCode(&Code)) {
00065             code = Code;
00066             break;
00067             }
00068          }
00069      isyslog("established connection to %s remote control using code %c", Name(), code);
00070      char buffer[16];
00071      snprintf(buffer, sizeof(buffer), "%c", code);
00072      PutSetup(buffer);
00073      return true;
00074      }
00075   return false;
00076 }
00077 
00078 void cRcuRemote::Action(void)
00079 {
00080 #pragma pack(1)
00081   union {
00082     struct {
00083       unsigned short address;
00084       unsigned int command;
00085       } data;
00086     unsigned char raw[6];
00087     } buffer;
00088 #pragma pack()
00089 
00090   dsyslog("RCU remote control thread started (pid=%d)", getpid());
00091 
00092   time_t LastCodeRefresh = 0;
00093   int FirstTime = 0;
00094   uint64 LastCommand = 0;
00095   bool repeat = false;
00096 
00097   //XXX
00098   for (; f >= 0;) {
00099 
00100       LOCK_THREAD;
00101 
00102       if (ReceiveByte(REPEATLIMIT) == 'X') {
00103          for (int i = 0; i < 6; i++) {
00104              int b = ReceiveByte();
00105              if (b >= 0) {
00106                 buffer.raw[i] = b;
00107                 if (i == 5) {
00108                    unsigned short Address = ntohs(buffer.data.address); // the PIC sends bytes in "network order"
00109                    uint64         Command = ntohl(buffer.data.command);
00110                    if (code == 'B' && Address == 0x0000 && Command == 0x00004000)
00111                       // Well, well, if it isn't the "d-box"...
00112                       // This remote control sends the above command before and after
00113                       // each keypress - let's just drop this:
00114                       break;
00115                    int Now = time_ms();
00116                    Command |= uint64(Address) << 32;
00117                    if (Command != LastCommand) {
00118                       LastCommand = Command;
00119                       repeat = false;
00120                       FirstTime = Now;
00121                       }
00122                    else {
00123                       if (Now - FirstTime < REPEATDELAY)
00124                          break; // repeat function kicks in after a short delay
00125                       repeat = true;
00126                       }
00127                    Put(Command, repeat);
00128                    receivedCommand = true;
00129                    }
00130                 }
00131              else
00132                 break;
00133              }
00134          }
00135       else if (repeat) { // the last one was a repeat, so let's generate a release
00136          Put(LastCommand, false, true);
00137          repeat = false;
00138          LastCommand = 0;
00139          }
00140       else {
00141          LastCommand = 0;
00142          if (numberToSend >= 0) {
00143             Number(numberToSend);
00144             numberToSend = -1;
00145             }
00146          }
00147       if (code && time(NULL) - LastCodeRefresh > 60) {
00148          SendCommand(code); // in case the PIC listens to the wrong code
00149          LastCodeRefresh = time(NULL);
00150          }
00151       }
00152 }
00153 
00154 int cRcuRemote::ReceiveByte(int TimeoutMs)
00155 {
00156   // Returns the byte if one was received within a timeout, -1 otherwise
00157   if (cFile::FileReady(f, TimeoutMs)) {
00158      unsigned char b;
00159      if (safe_read(f, &b, 1) == 1)
00160         return b;
00161      else
00162         LOG_ERROR;
00163      }
00164   return -1;
00165 }
00166 
00167 bool cRcuRemote::SendByteHandshake(unsigned char c)
00168 {
00169   if (f >= 0) {
00170      int w = write(f, &c, 1);
00171      if (w == 1) {
00172         for (int reply = ReceiveByte(REPEATLIMIT); reply >= 0;) {
00173             if (reply == c)
00174                return true;
00175             else if (reply == 'X') {
00176                // skip any incoming RC code - it will come again
00177                for (int i = 6; i--;) {
00178                    if (ReceiveByte() < 0)
00179                       return false;
00180                    }
00181                }
00182             else
00183                return false;
00184             }
00185         }
00186      LOG_ERROR;
00187      }
00188   return false;
00189 }
00190 
00191 bool cRcuRemote::SendByte(unsigned char c)
00192 {
00193   LOCK_THREAD;
00194 
00195   for (int retry = 5; retry--;) {
00196       if (SendByteHandshake(c))
00197          return true;
00198       }
00199   return false;
00200 }
00201 
00202 bool cRcuRemote::SetCode(unsigned char Code)
00203 {
00204   code = Code;
00205   return SendCommand(code);
00206 }
00207 
00208 bool cRcuRemote::SetMode(unsigned char Mode)
00209 {
00210   mode = Mode;
00211   return SendCommand(mode);
00212 }
00213 
00214 bool cRcuRemote::SendCommand(unsigned char Cmd)
00215 { 
00216   return SendByte(Cmd | 0x80);
00217 }
00218 
00219 bool cRcuRemote::Digit(int n, int v)
00220 { 
00221   return SendByte(((n & 0x03) << 5) | (v & 0x0F) | (((dp >> n) & 0x01) << 4));
00222 }
00223 
00224 bool cRcuRemote::Number(int n, bool Hex)
00225 {
00226   LOCK_THREAD;
00227 
00228   if (!Hex) {
00229      char buf[8];
00230      sprintf(buf, "%4d", n & 0xFFFF);
00231      n = 0;
00232      for (char *d = buf; *d; d++) {
00233          if (*d == ' ')
00234             *d = 0xF;
00235          n = (n << 4) | ((*d - '0') & 0x0F);
00236          }
00237      }
00238   lastNumber = n;
00239   for (int i = 0; i < 4; i++) {
00240       if (!Digit(i, n))
00241          return false;
00242       n >>= 4;
00243       }
00244   return SendCommand(mode);
00245 }
00246 
00247 bool cRcuRemote::String(char *s)
00248 {
00249   LOCK_THREAD;
00250 
00251   const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP ";
00252   int n = 0;
00253 
00254   for (int i = 0; *s && i < 4; s++, i++) {
00255       n <<= 4;
00256       for (const char *c = chars; *c; c++) {
00257           if (*c == *s) {
00258              n |= c - chars;
00259              break;
00260              }
00261           }
00262       }
00263   return Number(n, true);
00264 }
00265 
00266 void cRcuRemote::SetPoints(unsigned char Dp, bool On)
00267 { 
00268   if (On)
00269      dp |= Dp;
00270   else
00271      dp &= ~Dp;
00272   Number(lastNumber, true);
00273 }
00274 
00275 bool cRcuRemote::DetectCode(unsigned char *Code)
00276 {
00277   // Caller should initialize 'Code' to 0 and call DetectCode()
00278   // until it returns true. Whenever DetectCode() returns false
00279   // and 'Code' is not 0, the caller can use 'Code' to display
00280   // a message like "Trying code '%c'". If false is returned and
00281   // 'Code' is 0, all possible codes have been tried and the caller
00282   // can either stop calling DetectCode() (and give some error
00283   // message), or start all over again.
00284   if (*Code < 'A' || *Code > 'D') {
00285      *Code = 'A';
00286      return false;
00287      }
00288   if (*Code <= 'D') {
00289      SetMode(modeH);
00290      char buf[5];
00291      sprintf(buf, "C0D%c", *Code);
00292      String(buf);
00293      SetCode(*Code);
00294      delay_ms(2 * REPEATDELAY);
00295      if (receivedCommand) {
00296         SetMode(modeB);
00297         String("----");
00298         return true;
00299         }
00300      if (*Code < 'D') {
00301         (*Code)++;
00302         return false;
00303         }
00304      }
00305   *Code = 0;
00306   return false;
00307 }
00308 
00309 void cRcuRemote::ChannelSwitch(const cDevice *Device, int ChannelNumber)
00310 {
00311   if (ChannelNumber && Device->IsPrimaryDevice()) {
00312      LOCK_THREAD;
00313      numberToSend = ChannelNumber;
00314      }
00315 }
00316 
00317 void cRcuRemote::Recording(const cDevice *Device, const char *Name)
00318 {
00319   SetPoints(1 << Device->DeviceNumber(), Device->Receiving());
00320 }

Generated on Wed Feb 5 23:30:11 2003 for VDR by doxygen1.3-rc2