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 }

Generated on Sun Aug 4 21:47:28 2002 for k/os mp3v2 by doxygen1.2.16