ir.c

00001 
00002 
00003 
00004 /* The software in this file is based on code from FU Berlin. */
00005 
00006 /*
00007 Copyright 2003/2004, Freie Universitaet Berlin. All rights reserved.
00008 
00009 These sources were developed at the Freie Universität Berlin, Computer
00010 Systems and Telematics group.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are
00014 met:
00015 
00016 - Redistributions of source code must retain the above copyright
00017 notice, this list of conditions and the following disclaimer.
00018 
00019 - Redistributions in binary form must reproduce the above copyright
00020 notice, this list of conditions and the following disclaimer in the
00021 documentation and/or other materials provided with the distribution.
00022  
00023 - Neither the name of Freie Universitaet Berlin (FUB) nor the names of its
00024 contributors may be used to endorse or promote products derived from
00025 this software without specific prior written permission.
00026 
00027 This software is provided by FUB and the contributors on an "as is"
00028 basis, without any representations or warranties of any kind, express
00029 or implied including, but not limited to, representations or
00030 warranties of non-infringement, merchantability or fitness for a
00031 particular purpose. In no event shall FUB or contributors be liable
00032 for any direct, indirect, incidental, special, exemplary, or
00033 consequential damages (including, but not limited to, procurement of
00034 substitute goods or services; loss of use, data, or profits; or
00035 business interruption) however caused and on any theory of liability,
00036 whether in contract, strict liability, or tort (including negligence
00037 or otherwise) arising in any way out of the use of this software, even
00038 if advised of the possibility of such damage.
00039 
00040 This implementation was developed by the CST group at the FUB.
00041 Contributors: Thomas Pietsch, Bjoern Lichtblau
00042 
00043 */
00044 
00045 /*  \file recir.c
00046  ** \ingroup Firmware
00047  ** \brief Receiving RC5 via IR Receiving Diode.
00048  **
00049  ** \code
00050  ** RC5: 1780 us bitlength (manchester encoded, so half bitlength of 890 us is important)
00051  ** Transferred packet (2 start + toggle bit + 5 address bits + 6 comand bits)): 
00052  **                                   | S | S | T | A4 | A3 | A2 | A1 | A0 | C5 | C4 | C3 | C2 | C1 | C0 |
00053  ** irdata format: | ? | ? | error  | newData | T | A4 | A3 | A2 | A1 | A0 | C5 | C4 | C3 | C2 | C1 | C0 |
00054  ** \endcode
00055  **
00056  ** <img src="../pics/rc5.jpg">
00057  ** See detailed description at <a href="http://users.pandora.be/davshomepage/rc5.htm">http://users.pandora.be/davshomepage/rc5.htm</a>
00058  **
00059  ** Some common addresses and commands:
00060  ** \code
00061  ** Address:          Device:          Command:
00062  **   0               TV1              0...9    Numbers 0...9 (channel select)
00063  **   1               TV2              12       Standby
00064  **   5               VCR1             16       Master Volume +
00065  **   6               VCR2             17       Master Volume -
00066  **  17               Tuner            18       Brightness +
00067  **  18               Audio Tape       19       Brightness -
00068  **  20               CD Player        50       Fast rewind
00069  **                                    52       Fast run forward
00070  **                                    53       Play
00071  **                                    54       Stop
00072  **                                    55       Recording
00073  ** \endcode
00074  **/
00075 
00076 #include <io.h>
00077 #include <signal.h>
00078 
00079 #include "dev/ir.h"
00080 
00081 #include "dev/leds.h"
00082 #include "dev/beep.h"
00083 
00084 PROCESS(ir_process, "IR receiver");
00085 process_event_t ir_event_received;
00086 /*---------------------------------------------------------------------------*/
00087 #define SIR1  (P1OUT |= 0x01) ///< MACRO: Puts IR sending diode high.
00088 #define SIR0  (P1OUT &= 0xFE) ///< MACRO: Puts IR sending diode low.
00089 #define BIT75 3282      ///< 3 quarters of a bit after start, 3282 cyc @ 2,4576Mhz = 1335us.
00090 #define BIT50 2188      ///< Half of bit length, 2188 cyc @ 2,4576Mhz = 890 us.
00091 
00092 /*---------------------------------------------------------------------------*/
00093 /* Sends a logical one via IR, method is timed for the 2.4576Mhz SMCLK!!!
00094  */
00095 static volatile void
00096 send1bit(void)
00097 {
00098   volatile int i;
00099   for(i = 0; i < 34; ++i) {
00100     SIR1; SIR1; SIR1; SIR1;
00101     SIR0; SIR0; SIR0; SIR0; 
00102     SIR0; SIR0; SIR0; SIR0; 
00103     SIR0; 
00104   }  
00105 }
00106 /*---------------------------------------------------------------------------*/
00107 /* Sends a logical 0 via IR, method is timed for the 2.4576Mhz SMCLK!!!
00108  */
00109 static volatile void
00110 send0bit(void)
00111 {
00112   volatile int i;
00113   for(i = 0; i < 34; ++i) {
00114     SIR0; SIR0; SIR0; SIR0; 
00115     SIR0; SIR0; SIR0; SIR0; 
00116     SIR0; SIR0; SIR0; SIR0; 
00117     SIR0; 
00118   }  
00119 }
00120 /*---------------------------------------------------------------------------*/
00121 /* Sends the lower 12 bits of data via IR, turns interrupt off while
00122    it's sending.
00123  */
00124 void
00125 ir_send(unsigned short data)
00126 {
00127   volatile unsigned short mask = 0x2000;
00128   data |= 0xF000;
00129   
00130   dint();
00131   while(mask != 0){
00132     if(!(mask & data)){
00133       send1bit();
00134       send0bit();
00135     } else {
00136       send0bit();
00137       send1bit();
00138     }
00139     mask /= 2;
00140   }
00141   eint();
00142 }
00143 /*---------------------------------------------------------------------------*/
00144 /* Testroutine which repetedly sends two commands.
00145  */
00146 /*void
00147 ir_test_send(void)
00148 {
00149   volatile unsigned int i;
00150   send12bits(0xF010);
00151   for(i=0; i<0xFFFF; i++) nop(); 
00152   send12bits(0xF011);
00153   for(i=0; i<0xFFFF; i++) nop();
00154 }*/
00155 /*---------------------------------------------------------------------------*/
00156 
00157 
00158 static void setErrorBit(void);
00159 static void clearErrorBit(void);
00160 static void setDataAvailableBit(void);
00161 static void clearDataAvailableBit(void);
00162 
00163 
00164 /// \name Internal variables.
00165 //@{
00166 static unsigned int ir_pos;             ///< current position in frame
00167 static unsigned int recvdata;            ///< here a received packet is saved
00168 static unsigned int recvdatabuffer;      ///< temporary buffer for receiving
00169 static unsigned char ir_temp;           ///< saves the first half of the manchester bit
00170 //@}
00171 
00172 /// \name Public functions. 
00173 /// If ::recir_dataAvailable()==1 use the get* functions.
00174 //@{
00175 unsigned char recir_getCode(void){ return (recvdata & 0x003F); }
00176 unsigned char recir_getAddress(void){ return ((recvdata & 0x07C0) >> 6); }
00177 unsigned char recir_getToggle(void){  return ((recvdata & 0x0800) >> 11); }
00178 unsigned char recir_getError(void){ return ((recvdata & 0x2000) >> 13); }
00179 
00180 u16_t
00181 ir_data(void)
00182 {
00183   return recvdata;
00184 }
00185 
00186 u8_t
00187 ir_poll(void)
00188 {
00189   if(recvdata & 0x1000) {
00190     clearDataAvailableBit();
00191     return 1;
00192   } else {
00193     return 0;
00194   }
00195 }
00196 
00197 
00198 ///\name Internal functions.
00199 //@{
00200 static void setErrorBit(void){ recvdata |= 0x2000; }
00201 static void clearErrorBit(void) { recvdata &= 0xDFFF; }
00202 static void setDataAvailableBit(void){ recvdata |= 0x1000; }
00203 static void clearDataAvailableBit(void){ recvdata &= 0xEFFF; }
00204 
00205 
00206 /// Timer B0 interrupt service routine
00207 interrupt(TIMERB1_VECTOR) Timer_B1 (void) {
00208 
00209   /*P2OUT = (P2OUT & 0xf7) | (8 - (P2OUT & 0x08));*/
00210   
00211   if(ir_pos <= 25) {
00212       if(ir_pos % 2) {                             // odd position
00213         if(ir_temp && !(P1IN & 0x04)) {           // 1 - 0 -->  write 1 
00214           recvdatabuffer +=1;
00215           recvdatabuffer = recvdatabuffer << 1;  
00216         } else if(!ir_temp && (P1IN & 0x04)) {      // 0 - 1 -->  write 0 
00217           recvdatabuffer = recvdatabuffer << 1;  
00218         } else { 
00219           setErrorBit();
00220           if(P1IN & 0x04) {
00221             recvdatabuffer += 1;
00222           }
00223           recvdatabuffer = recvdatabuffer << 1;
00224         }
00225       } else {                                    // even position
00226         ir_temp = P1IN & 0x04;
00227       }
00228     }
00229     
00230     if(ir_pos == 25) {                          // end reached
00231       recvdatabuffer = recvdatabuffer >> 1; 
00232 
00233       if(!recir_getError() && ( (recvdatabuffer & 0x0FFF) != (recvdata & 0x0FFF) ) ){
00234         recvdata = recvdatabuffer;
00235         setDataAvailableBit();
00236       } else {
00237         _NOP();
00238       }      
00239     }
00240     
00241     if(ir_pos==27) {
00242       TBCCTL1 &= ~CCIE;  
00243 
00244       //GREENOFF;      
00245       // temporary debug output
00246       //sendRS232Address(recvdatabuffer);
00247       //if(recir_getError()) sendRS232('E');
00248       //sendRS232String("\r\n");
00249       if(!recir_getError()) beep_beep(20);
00250       
00251       // reenable interrupt for falling edge
00252       P1IFG &= ~(0x04);
00253       P1IE  |= 0x04;                    // enable interrupt for recir RC5
00254       leds_off(LEDS_RED);
00255     }
00256     
00257   ir_pos++;
00258   TBCCR1 += BIT50;        // set new interrupt
00259  
00260   TBCCTL1 &= ~CCIFG;
00261 }
00262 
00263 
00264 /** \brief IR Interrupt routine 
00265  **
00266  ** For the falling edge (start of RC5 packet)( mid of first start bit ), IRReceiver is on P12
00267  ** real interrupt routine, which calls this, is in sensors.c */
00268 void
00269 ir_irq(void)
00270 {
00271   if(P1IN & 0x04) return; // high again, just a peak
00272 
00273   ir_pos = 0;
00274   recvdatabuffer = 0;  
00275   clearErrorBit();
00276 
00277   // the first timer interrupt will occur in the mid of the first half of the second start bit 
00278   TBCCR1 = TBR + BIT75;     // set first TBCCR1 IRQ to 75% of RC5 bitlength
00279   TBCCTL1 &= ~CCIFG;        // clear previous compare flag
00280   TBCCTL1 |= CCIE;          // CCR0 interrupt enabled, interrupt occurs when timer equals CCR0
00281   
00282   P1IE &= ~0x04;   // disable interrupt for P12 ( ReceiveIR )
00283   leds_on(LEDS_RED);
00284   //GREENON;
00285 } 
00286 
00287 //@}
00288 /*---------------------------------------------------------------------*/
00289 PROCESS_THREAD(ir_process, ev, data)
00290 {
00291   PROCESS_BEGIN();
00292 
00293   // init TIMERB ccr0 to run continouslycreate the 5 ms interval
00294   // ccr1 is used for ir receiving (RC5)
00295   TBCTL = TBSSEL1 + TBCLR;         // select SMCLK (2.4576MHz), clear TBR
00296   TBCTL |= MC1;                         // Start Timer_A in continuous mode
00297   
00298 
00299   P1IES |= 0x04;  // Important for IR-RC5 receive to detect the first FALLING edge
00300 
00301   ir_event_received = process_alloc_event();
00302 
00303   while(1) {
00304     PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_POLL);
00305     
00306     if(ir_poll() == IR_DATA) {
00307       unsigned short irdata;
00308       irdata = ir_data() & 0x7ff;    
00309       process_post(PROCESS_BROADCAST, ir_event_received, (process_data_t)irdata);
00310     }
00311     
00312   }
00313   
00314   PROCESS_END();
00315 }
00316 /*---------------------------------------------------------------------*/

Generated on Mon Apr 11 14:23:43 2011 for Contiki 2.5 by  doxygen 1.6.1