Contiki 2.6

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 "contiki.h"
00077 #include "dev/ir.h"
00078 
00079 #include "dev/leds.h"
00080 #include "dev/beep.h"
00081 #include "isr_compat.h"
00082 
00083 PROCESS(ir_process, "IR receiver");
00084 process_event_t ir_event_received;
00085 /*---------------------------------------------------------------------------*/
00086 #define SIR1  (P1OUT |= 0x01) ///< MACRO: Puts IR sending diode high.
00087 #define SIR0  (P1OUT &= 0xFE) ///< MACRO: Puts IR sending diode low.
00088 #define BIT75 3282      ///< 3 quarters of a bit after start, 3282 cyc @ 2,4576Mhz = 1335us.
00089 #define BIT50 2188      ///< Half of bit length, 2188 cyc @ 2,4576Mhz = 890 us.
00090 
00091 /*---------------------------------------------------------------------------*/
00092 /* Sends a logical one via IR, method is timed for the 2.4576Mhz SMCLK!!!
00093  */
00094 static volatile void
00095 send1bit(void)
00096 {
00097   volatile int i;
00098   for(i = 0; i < 34; ++i) {
00099     SIR1; SIR1; SIR1; SIR1;
00100     SIR0; SIR0; SIR0; SIR0; 
00101     SIR0; SIR0; SIR0; SIR0; 
00102     SIR0; 
00103   }  
00104 }
00105 /*---------------------------------------------------------------------------*/
00106 /* Sends a logical 0 via IR, method is timed for the 2.4576Mhz SMCLK!!!
00107  */
00108 static volatile void
00109 send0bit(void)
00110 {
00111   volatile int i;
00112   for(i = 0; i < 34; ++i) {
00113     SIR0; SIR0; SIR0; SIR0; 
00114     SIR0; SIR0; SIR0; SIR0; 
00115     SIR0; SIR0; SIR0; SIR0; 
00116     SIR0; 
00117   }  
00118 }
00119 /*---------------------------------------------------------------------------*/
00120 /* Sends the lower 12 bits of data via IR, turns interrupt off while
00121    it's sending.
00122  */
00123 void
00124 ir_send(unsigned short data)
00125 {
00126   volatile unsigned short mask = 0x2000;
00127   data |= 0xF000;
00128   
00129   dint();
00130   while(mask != 0){
00131     if(!(mask & data)){
00132       send1bit();
00133       send0bit();
00134     } else {
00135       send0bit();
00136       send1bit();
00137     }
00138     mask /= 2;
00139   }
00140   eint();
00141 }
00142 /*---------------------------------------------------------------------------*/
00143 /* Testroutine which repetedly sends two commands.
00144  */
00145 /*void
00146 ir_test_send(void)
00147 {
00148   volatile unsigned int i;
00149   send12bits(0xF010);
00150   for(i=0; i<0xFFFF; i++) nop(); 
00151   send12bits(0xF011);
00152   for(i=0; i<0xFFFF; i++) nop();
00153 }*/
00154 /*---------------------------------------------------------------------------*/
00155 
00156 
00157 static void setErrorBit(void);
00158 static void clearErrorBit(void);
00159 static void setDataAvailableBit(void);
00160 static void clearDataAvailableBit(void);
00161 
00162 
00163 /// \name Internal variables.
00164 //@{
00165 static unsigned int ir_pos;             ///< current position in frame
00166 static unsigned int recvdata;            ///< here a received packet is saved
00167 static unsigned int recvdatabuffer;      ///< temporary buffer for receiving
00168 static unsigned char ir_temp;           ///< saves the first half of the manchester bit
00169 //@}
00170 
00171 /// \name Public functions. 
00172 /// If ::recir_dataAvailable()==1 use the get* functions.
00173 //@{
00174 unsigned char recir_getCode(void){ return (recvdata & 0x003F); }
00175 unsigned char recir_getAddress(void){ return ((recvdata & 0x07C0) >> 6); }
00176 unsigned char recir_getToggle(void){  return ((recvdata & 0x0800) >> 11); }
00177 unsigned char recir_getError(void){ return ((recvdata & 0x2000) >> 13); }
00178 
00179 uint16_t
00180 ir_data(void)
00181 {
00182   return recvdata;
00183 }
00184 
00185 uint8_t
00186 ir_poll(void)
00187 {
00188   if(recvdata & 0x1000) {
00189     clearDataAvailableBit();
00190     return 1;
00191   } else {
00192     return 0;
00193   }
00194 }
00195 
00196 
00197 ///\name Internal functions.
00198 //@{
00199 static void setErrorBit(void){ recvdata |= 0x2000; }
00200 static void clearErrorBit(void) { recvdata &= 0xDFFF; }
00201 static void setDataAvailableBit(void){ recvdata |= 0x1000; }
00202 static void clearDataAvailableBit(void){ recvdata &= 0xEFFF; }
00203 
00204 
00205 /// Timer B0 interrupt service routine
00206 ISR(TIMERB1, Timer_B1) {
00207 
00208   /*P2OUT = (P2OUT & 0xf7) | (8 - (P2OUT & 0x08));*/
00209   
00210   if(ir_pos <= 25) {
00211       if(ir_pos % 2) {                             // odd position
00212         if(ir_temp && !(P1IN & 0x04)) {           // 1 - 0 -->  write 1 
00213           recvdatabuffer +=1;
00214           recvdatabuffer = recvdatabuffer << 1;  
00215         } else if(!ir_temp && (P1IN & 0x04)) {      // 0 - 1 -->  write 0 
00216           recvdatabuffer = recvdatabuffer << 1;  
00217         } else { 
00218           setErrorBit();
00219           if(P1IN & 0x04) {
00220             recvdatabuffer += 1;
00221           }
00222           recvdatabuffer = recvdatabuffer << 1;
00223         }
00224       } else {                                    // even position
00225         ir_temp = P1IN & 0x04;
00226       }
00227     }
00228     
00229     if(ir_pos == 25) {                          // end reached
00230       recvdatabuffer = recvdatabuffer >> 1; 
00231 
00232       if(!recir_getError() && ( (recvdatabuffer & 0x0FFF) != (recvdata & 0x0FFF) ) ){
00233         recvdata = recvdatabuffer;
00234         setDataAvailableBit();
00235       } else {
00236         _NOP();
00237       }      
00238     }
00239     
00240     if(ir_pos==27) {
00241       TBCCTL1 &= ~CCIE;  
00242 
00243       //GREENOFF;      
00244       // temporary debug output
00245       //sendRS232Address(recvdatabuffer);
00246       //if(recir_getError()) sendRS232('E');
00247       //sendRS232String("\r\n");
00248       if(!recir_getError()) beep_beep(20);
00249       
00250       // reenable interrupt for falling edge
00251       P1IFG &= ~(0x04);
00252       P1IE  |= 0x04;                    // enable interrupt for recir RC5
00253       leds_off(LEDS_RED);
00254     }
00255     
00256   ir_pos++;
00257   TBCCR1 += BIT50;        // set new interrupt
00258  
00259   TBCCTL1 &= ~CCIFG;
00260 }
00261 
00262 
00263 /** \brief IR Interrupt routine 
00264  **
00265  ** For the falling edge (start of RC5 packet)( mid of first start bit ), IRReceiver is on P12
00266  ** real interrupt routine, which calls this, is in sensors.c */
00267 void
00268 ir_irq(void)
00269 {
00270   if(P1IN & 0x04) return; // high again, just a peak
00271 
00272   ir_pos = 0;
00273   recvdatabuffer = 0;  
00274   clearErrorBit();
00275 
00276   // the first timer interrupt will occur in the mid of the first half of the second start bit 
00277   TBCCR1 = TBR + BIT75;     // set first TBCCR1 IRQ to 75% of RC5 bitlength
00278   TBCCTL1 &= ~CCIFG;        // clear previous compare flag
00279   TBCCTL1 |= CCIE;          // CCR0 interrupt enabled, interrupt occurs when timer equals CCR0
00280   
00281   P1IE &= ~0x04;   // disable interrupt for P12 ( ReceiveIR )
00282   leds_on(LEDS_RED);
00283   //GREENON;
00284 } 
00285 
00286 //@}
00287 /*---------------------------------------------------------------------*/
00288 PROCESS_THREAD(ir_process, ev, data)
00289 {
00290   PROCESS_BEGIN();
00291 
00292   // init TIMERB ccr0 to run continouslycreate the 5 ms interval
00293   // ccr1 is used for ir receiving (RC5)
00294   TBCTL = TBSSEL1 + TBCLR;         // select SMCLK (2.4576MHz), clear TBR
00295   TBCTL |= MC1;                         // Start Timer_A in continuous mode
00296   
00297 
00298   P1IES |= 0x04;  // Important for IR-RC5 receive to detect the first FALLING edge
00299 
00300   ir_event_received = process_alloc_event();
00301 
00302   while(1) {
00303     PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_POLL);
00304     
00305     if(ir_poll() == IR_DATA) {
00306       unsigned short irdata;
00307       irdata = ir_data() & 0x7ff;    
00308       process_post(PROCESS_BROADCAST, ir_event_received, (process_data_t)irdata);
00309     }
00310     
00311   }
00312   
00313   PROCESS_END();
00314 }
00315 /*---------------------------------------------------------------------*/