Main Page Data Structures File List Data Fields Globals Related Pages

# remote.cpp

Go to the documentation of this file.

    00001 /*  Remote Control driver
    00002
    00003     25.10.2001: tk, i should really implement a better buffer technique,
    00004                 to avoid the lengthy decoding during the timer interrupt.
    00005                 Debugging of IR decoder functions is a pain in the ass,
    00006                 and we might even loose some timer samples, if the deocding
    00007                 takes too long. (a real nice idea would be a generic decoder
    00008                 that can parse LIRC config files..) [see www.lirc.org]
    00009     24.06.2001: tk, initial implementation.
    00010
    00011     Copyright (c)2000 by Thomas Kindler, thomas.kindler@gmx.de
    00012
    00013     This program is free software; you can redistribute it and/or
    00014     modify it under the terms of the GNU General Public License as
    00015     published by the Free Software Foundation; either version 2 of
    00016     the License, or (at your option) any later version. Read the
    00017     full License at http://www.gnu.org/copyleft for more details.
    00018
    00019 */
    00020
    00021 // include files -----
    00022 //
    00023 #include <conio.h>
    00024 #include <stdio.h>
    00025 #include <string.h>
    00026 #include <dos.h>
    00027 #include <stdlib.h>
    00028 #include <stdarg.h>
    00029 #include <assert.h>
    00030 #include "amd186.h"
    00031 #include "remote.h"
    00032 #include "clib/rtos.h"
    00033 #include "clib/hwapi.h"
    00034 #include "clib/rtos.h"
    00035
    00036 #define  RC_DMA_LEN    1024
    00037
    00038
    00040 static volatile unsigned  dmabuf[RC_DMA_LEN];
    00041
    00043 static void interrupt     (*oldTimerHandler)(...);
    00044
    00046 static unsigned long      queue[RC_QUEUE_SIZE];
    00047 static volatile int       qHead, qCount;
    00048
    00049
    00050 //#define  RC_DEBUG
    00051
    00052 #ifdef RC_DEBUG
    00053   static char  dstring[8000];
    00054   static char *dstringptr = dstring;
    00055
    00062   static int dprintf(const char *format, ...)
    00063   {
    00064     if (dstringptr-dstring>sizeof(dstring)-256)
    00065       return 0;
    00066     va_list arglist;
    00067     va_start(arglist, format);
    00068     int ret = vsprintf(dstringptr, format, arglist);
    00069
    00070     dstringptr += ret;
    00071     assert(dstringptr < dstring+sizeof(dstring));
    00072
    00073     va_end(arglist);
    00074     return ret;
    00075   }
    00076
    00082   static void ddump()
    00083   {
    00084     printf("%s", dstring);
    00085     dstring[0] = '\0';
    00086     dstringptr = dstring;
    00087   }
    00088 #endif
    00089
    00090
    00091
    00111 static unsigned long DecodeRC5(unsigned const *samples)
    00112 {
    00113   int state = 3;   // START0      MID0     START1     MID1
    00114   int next[4][2] = {{  1, -1},{  0,  3},{  3, -1},{  2,  1}};
    00115   int emit[4][2] = {{  0, -1},{ -1,  1},{  1, -1},{ -1,  0}};
    00116
    00117   unsigned long  code = 0;
    00118   for (int i=0, b=12; b>=0; i++) {
    00119     unsigned t = samples[i];
    00120     if (abs(t-RC5_SHORT) < RC5_MARGIN) {
    00121       if (emit[state][0] == 0)
    00122         b--;
    00123       else if (emit[state][0] == 1)
    00124         code |= 1L<<b--;
    00125       state = next[state][0];
    00126     } else if (abs(t-RC5_LONG) < RC5_MARGIN) {
    00127       if (emit[state][1] == 0)
    00128         b--;
    00129       else if (emit[state][1] == 1)
    00130         code |= 1L<<b--;
    00131       state = next[state][1];
    00132     } else {
    00133       // timing error
    00134       return 0;
    00135     }
    00136     // check for biphase error
    00137     if (state == -1)
    00138       return 0;
    00139   }
    00140
    00141   // assemble keycode, and check for repeat
    00142   //
    00143   unsigned long keycode;
    00144   static unsigned long lastcode = 0;
    00145
    00146   keycode = RCKEY_RC5 | (code & 0x7ff);
    00147
    00148   if (~(code^lastcode) & 0x800)
    00149     keycode |= RCKEY_REPEAT;
    00150   lastcode = code;
    00151
    00152   return keycode;
    00153 }
    00154
    00155
    00163 static unsigned long DecodeNEC(unsigned const *samples)
    00164 {
    00165   unsigned long keycode = RCKEY_NEC;
    00166   unsigned long code = 0;
    00167   static unsigned long lastcode = 0;
    00168
    00169   if (abs(samples[0]-NEC_START1) > NEC_MARGIN)
    00170     return 0;
    00171
    00172   if (abs(samples[1]-NEC_START2) < NEC_MARGIN) {
    00173     lastcode = 0;
    00174     for (int i=0; i<32; i++) {
    00175       int t1 = samples[i*2+2];
    00176       int t2 = samples[i*2+3];
    00177
    00178       if (abs(t1-NEC_PULSE)>NEC_MARGIN)
    00179         return 0;
    00180
    00181       if (abs(t2-NEC_PAUSE0)<NEC_MARGIN) {
    00182         // 0
    00183       } else if (abs(t2-NEC_PAUSE1)<NEC_MARGIN) {
    00184         // 1
    00185         code |= 1L << i;
    00186       } else {
    00187         return 0;
    00188       }
    00189     }
    00190   } else if (abs(samples[1]-NEC_REPEAT) < NEC_MARGIN) {
    00191     code = lastcode;
    00192     keycode |= RCKEY_REPEAT;
    00193   } else {
    00194     return 0;
    00195   }
    00196
    00197   if (((code>>16) ^ ~(code>>24)) & 0xff)
    00198     return 0;
    00199
    00200   lastcode = code;
    00201   keycode |= (((code>>16)&0xff) | ((code & 0xffff)<<8)) & RCKEY_CODE;
    00202
    00203   return keycode;
    00204 }
    00205
    00206
    00213 static unsigned long DecodeSAMSUNG(unsigned const *samples)
    00214 {
    00215   // check start bits
    00216   //
    00217   if ((abs(samples[0]-SAM_START1) > SAM_MARGIN) ||
    00218       (abs(samples[1]-SAM_START2) > SAM_MARGIN))
    00219     return 0;
    00220
    00221   unsigned long code = 0;
    00222   for (int i=0; i<32; i++) {
    00223     int t1 = samples[i*2+2];
    00224     int t2 = samples[i*2+3];
    00225
    00226     if (abs(t1-SAM_PULSE)>SAM_MARGIN)
    00227       return 0;
    00228
    00229     if (abs(t2-SAM_PAUSE0)<SAM_MARGIN) {
    00230       // 0
    00231     } else if (abs(t2-SAM_PAUSE1)<SAM_MARGIN) {
    00232       // 1
    00233       code |= 1L << i;
    00234     } else {
    00235       return 0;
    00236     }
    00237   }
    00238
    00239   // assemble keycode, and check for repeat
    00240   //
    00241   static unsigned long lastcode = 0;
    00242   static unsigned long lasttime = 0;
    00243
    00244   unsigned long time;
    00245   unsigned long keycode;
    00246
    00247   keycode = RCKEY_SAMSUNG | (code >> 16);
    00248
    00249   RTX_Get_System_Ticks(&time);
    00250   if ((code == lastcode) && (time-lasttime < SAM_REPEATMS))
    00251     keycode |= RCKEY_REPEAT;
    00252
    00253   lastcode = code;
    00254   lasttime = time;
    00255
    00256   return keycode;
    00257 }
    00258
    00259
    00273 static void DecodeSamples(unsigned *samples, unsigned length)
    00274 {
    00275   int cooked = 0;
    00276   for (int i=0; i<length-1; i++) {
    00277     unsigned t = (samples[i+1] - samples[i]) / TICKS_PER_uS;
    00278     if (t > RC_TRESHOLD)
    00279       samples[cooked++] = t;
    00280   }
    00281   samples[cooked++] = 0;
    00282
    00283   #ifdef RC_DEBUG
    00284     dprintf("cooklen %d\n", cooked);
    00285     dprintf("index   pulse   pause\n");
    00286     for (int i=0; i<cooked; i+=2)
    00287       dprintf(" %-4d   %5u   %5u\n", i, samples[i], samples[i+1]);
    00288   #endif
    00289
    00290   unsigned long key = 0;
    00291   if (!key) key = DecodeRC5(samples);
    00292   if (!key) key = DecodeNEC(samples);
    00293   if (!key) key = DecodeSAMSUNG(samples);
    00294
    00295   if (key && qCount < RC_QUEUE_SIZE) {
    00296     queue[(qHead+qCount) % RC_QUEUE_SIZE] = key;
    00297     qCount++;
    00298   }
    00299 }
    00300
    00301
    00309 static void interrupt timerHandler(...)
    00310 {
    00311   static unsigned lastpos;
    00312   unsigned        position;
    00313
    00314   // get transfer count without disturbing the channel.
    00315   // (don't use GetDMAInfo()!!)
    00316   //
    00317   position = RC_DMA_LEN - inpw(RC_DMACHANNEL ? PCB_D1TC:PCB_D0TC);
    00318
    00319   if (position == lastpos && position != 0)
    00320   {
    00321     // try to decode the timing samples
    00322     //
    00323     DecodeSamples((unsigned*)dmabuf, position);
    00324
    00325     // Restart DMA channel
    00326     //
    00327     DmaInfo  dma;
    00328     AMD_GetDmaInfo(RC_DMACHANNEL, &dma);
    00329     dma.length  = RC_DMA_LEN;
    00330     dma.dstMem  = (void*)dmabuf;
    00331     AMD_StartDma(RC_DMACHANNEL, &dma);
    00332   }
    00333   lastpos = position;
    00334   oldTimerHandler();
    00335 }
    00336
    00337
    00344 int RC_KeyAvail()
    00345 {
    00346   #ifdef RC_DEBUG
    00347     ddump();
    00348   #endif
    00349
    00350   return (int)qCount;
    00351 }
    00352
    00353
    00361 unsigned long RC_GetKey()
    00362 {
    00363   while (!RC_KeyAvail()) {
    00364     RTX_Sleep_Time(10);
    00365   }
    00366
    00367   unsigned long key;
    00368   key    = queue[qHead++];
    00369   qHead %= RC_QUEUE_SIZE;
    00370   qCount--;
    00371
    00372   return key;
    00373 }
    00374
    00375
    00380 void RC_Init()
    00381 {
    00382   // Enable chip select
    00383   //
    00384   pfe_enable_bus(0xff, true);
    00385   pfe_enable_pcs(1);
    00386
    00387   // Set up the timer --
    00388   // We do this by hand, because the BIOS doesn't support
    00389   // timers with only one terminal count. (Go figure. It
    00390   // always writes to both CMPA and CMPB!)
    00391   //
    00392   oldTimerHandler = getvect(0x12);
    00393   setvect(0x12, timerHandler);
    00394
    00395   outpw(PCB_T1CON, TCON_STOP);
    00396   outpw(PCB_T1CMPA, 0 );
    00397   outpw(PCB_T1CNT, 0 );
    00398   outpw(PCB_T1CON, TCON_CONT | TCON_INT | TCON_START);
    00399
    00400   // Enable DMA channel and DMA Request pin
    00401   //
    00402   DmaInfo  dma;
    00403   dma.control = DCON_BW | DCON_TC | DCON_DMIO | DCON_DINC | DCON_SSYNC | DCON_P;
    00404   dma.length  = RC_DMA_LEN;
    00405   dma.srcPort = PCB_T1CNT;
    00406   dma.dstMem  = (void*)dmabuf;
    00407   AMD_StartDma(RC_DMACHANNEL, &dma);
    00408   AMD_EnableDrq(RC_DMACHANNEL, true);
    00409 }
    00410
    00411
    00416 void RC_Done()
    00417 {
    00418   // Restore timer interrupt
    00419   //
    00420   outpw(PCB_T1CON, TCON_STOP);
    00421   if (oldTimerHandler)
    00422     setvect(0x12, oldTimerHandler);
    00423
    00424   // Disable the DMA channel
    00425   //
    00426   AMD_StopDma(RC_DMACHANNEL);
    00427 }