Contiki 2.5
ir.c
1 
2 
3 
4 /* The software in this file is based on code from FU Berlin. */
5 
6 /*
7 Copyright 2003/2004, Freie Universitaet Berlin. All rights reserved.
8 
9 These sources were developed at the Freie Universität Berlin, Computer
10 Systems and Telematics group.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are
14 met:
15 
16 - Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18 
19 - Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in the
21 documentation and/or other materials provided with the distribution.
22 
23 - Neither the name of Freie Universitaet Berlin (FUB) nor the names of its
24 contributors may be used to endorse or promote products derived from
25 this software without specific prior written permission.
26 
27 This software is provided by FUB and the contributors on an "as is"
28 basis, without any representations or warranties of any kind, express
29 or implied including, but not limited to, representations or
30 warranties of non-infringement, merchantability or fitness for a
31 particular purpose. In no event shall FUB or contributors be liable
32 for any direct, indirect, incidental, special, exemplary, or
33 consequential damages (including, but not limited to, procurement of
34 substitute goods or services; loss of use, data, or profits; or
35 business interruption) however caused and on any theory of liability,
36 whether in contract, strict liability, or tort (including negligence
37 or otherwise) arising in any way out of the use of this software, even
38 if advised of the possibility of such damage.
39 
40 This implementation was developed by the CST group at the FUB.
41 Contributors: Thomas Pietsch, Bjoern Lichtblau
42 
43 */
44 
45 /* \file recir.c
46  ** \ingroup Firmware
47  ** \brief Receiving RC5 via IR Receiving Diode.
48  **
49  ** \code
50  ** RC5: 1780 us bitlength (manchester encoded, so half bitlength of 890 us is important)
51  ** Transferred packet (2 start + toggle bit + 5 address bits + 6 comand bits)):
52  ** | S | S | T | A4 | A3 | A2 | A1 | A0 | C5 | C4 | C3 | C2 | C1 | C0 |
53  ** irdata format: | ? | ? | error | newData | T | A4 | A3 | A2 | A1 | A0 | C5 | C4 | C3 | C2 | C1 | C0 |
54  ** \endcode
55  **
56  ** <img src="../pics/rc5.jpg">
57  ** See detailed description at <a href="http://users.pandora.be/davshomepage/rc5.htm">http://users.pandora.be/davshomepage/rc5.htm</a>
58  **
59  ** Some common addresses and commands:
60  ** \code
61  ** Address: Device: Command:
62  ** 0 TV1 0...9 Numbers 0...9 (channel select)
63  ** 1 TV2 12 Standby
64  ** 5 VCR1 16 Master Volume +
65  ** 6 VCR2 17 Master Volume -
66  ** 17 Tuner 18 Brightness +
67  ** 18 Audio Tape 19 Brightness -
68  ** 20 CD Player 50 Fast rewind
69  ** 52 Fast run forward
70  ** 53 Play
71  ** 54 Stop
72  ** 55 Recording
73  ** \endcode
74  **/
75 
76 #include "contiki.h"
77 #include "dev/ir.h"
78 
79 #include "dev/leds.h"
80 #include "dev/beep.h"
81 
82 PROCESS(ir_process, "IR receiver");
83 process_event_t ir_event_received;
84 /*---------------------------------------------------------------------------*/
85 #define SIR1 (P1OUT |= 0x01) ///< MACRO: Puts IR sending diode high.
86 #define SIR0 (P1OUT &= 0xFE) ///< MACRO: Puts IR sending diode low.
87 #define BIT75 3282 ///< 3 quarters of a bit after start, 3282 cyc @ 2,4576Mhz = 1335us.
88 #define BIT50 2188 ///< Half of bit length, 2188 cyc @ 2,4576Mhz = 890 us.
89 
90 /*---------------------------------------------------------------------------*/
91 /* Sends a logical one via IR, method is timed for the 2.4576Mhz SMCLK!!!
92  */
93 static volatile void
94 send1bit(void)
95 {
96  volatile int i;
97  for(i = 0; i < 34; ++i) {
98  SIR1; SIR1; SIR1; SIR1;
99  SIR0; SIR0; SIR0; SIR0;
100  SIR0; SIR0; SIR0; SIR0;
101  SIR0;
102  }
103 }
104 /*---------------------------------------------------------------------------*/
105 /* Sends a logical 0 via IR, method is timed for the 2.4576Mhz SMCLK!!!
106  */
107 static volatile void
108 send0bit(void)
109 {
110  volatile int i;
111  for(i = 0; i < 34; ++i) {
112  SIR0; SIR0; SIR0; SIR0;
113  SIR0; SIR0; SIR0; SIR0;
114  SIR0; SIR0; SIR0; SIR0;
115  SIR0;
116  }
117 }
118 /*---------------------------------------------------------------------------*/
119 /* Sends the lower 12 bits of data via IR, turns interrupt off while
120  it's sending.
121  */
122 void
123 ir_send(unsigned short data)
124 {
125  volatile unsigned short mask = 0x2000;
126  data |= 0xF000;
127 
128  dint();
129  while(mask != 0){
130  if(!(mask & data)){
131  send1bit();
132  send0bit();
133  } else {
134  send0bit();
135  send1bit();
136  }
137  mask /= 2;
138  }
139  eint();
140 }
141 /*---------------------------------------------------------------------------*/
142 /* Testroutine which repetedly sends two commands.
143  */
144 /*void
145 ir_test_send(void)
146 {
147  volatile unsigned int i;
148  send12bits(0xF010);
149  for(i=0; i<0xFFFF; i++) nop();
150  send12bits(0xF011);
151  for(i=0; i<0xFFFF; i++) nop();
152 }*/
153 /*---------------------------------------------------------------------------*/
154 
155 
156 static void setErrorBit(void);
157 static void clearErrorBit(void);
158 static void setDataAvailableBit(void);
159 static void clearDataAvailableBit(void);
160 
161 
162 /// \name Internal variables.
163 //@{
164 static unsigned int ir_pos; ///< current position in frame
165 static unsigned int recvdata; ///< here a received packet is saved
166 static unsigned int recvdatabuffer; ///< temporary buffer for receiving
167 static unsigned char ir_temp; ///< saves the first half of the manchester bit
168 //@}
169 
170 /// \name Public functions.
171 /// If ::recir_dataAvailable()==1 use the get* functions.
172 //@{
173 unsigned char recir_getCode(void){ return (recvdata & 0x003F); }
174 unsigned char recir_getAddress(void){ return ((recvdata & 0x07C0) >> 6); }
175 unsigned char recir_getToggle(void){ return ((recvdata & 0x0800) >> 11); }
176 unsigned char recir_getError(void){ return ((recvdata & 0x2000) >> 13); }
177 
178 u16_t
179 ir_data(void)
180 {
181  return recvdata;
182 }
183 
184 u8_t
185 ir_poll(void)
186 {
187  if(recvdata & 0x1000) {
188  clearDataAvailableBit();
189  return 1;
190  } else {
191  return 0;
192  }
193 }
194 
195 
196 ///\name Internal functions.
197 //@{
198 static void setErrorBit(void){ recvdata |= 0x2000; }
199 static void clearErrorBit(void) { recvdata &= 0xDFFF; }
200 static void setDataAvailableBit(void){ recvdata |= 0x1000; }
201 static void clearDataAvailableBit(void){ recvdata &= 0xEFFF; }
202 
203 
204 /// Timer B0 interrupt service routine
205 interrupt(TIMERB1_VECTOR) Timer_B1 (void) {
206 
207  /*P2OUT = (P2OUT & 0xf7) | (8 - (P2OUT & 0x08));*/
208 
209  if(ir_pos <= 25) {
210  if(ir_pos % 2) { // odd position
211  if(ir_temp && !(P1IN & 0x04)) { // 1 - 0 --> write 1
212  recvdatabuffer +=1;
213  recvdatabuffer = recvdatabuffer << 1;
214  } else if(!ir_temp && (P1IN & 0x04)) { // 0 - 1 --> write 0
215  recvdatabuffer = recvdatabuffer << 1;
216  } else {
217  setErrorBit();
218  if(P1IN & 0x04) {
219  recvdatabuffer += 1;
220  }
221  recvdatabuffer = recvdatabuffer << 1;
222  }
223  } else { // even position
224  ir_temp = P1IN & 0x04;
225  }
226  }
227 
228  if(ir_pos == 25) { // end reached
229  recvdatabuffer = recvdatabuffer >> 1;
230 
231  if(!recir_getError() && ( (recvdatabuffer & 0x0FFF) != (recvdata & 0x0FFF) ) ){
232  recvdata = recvdatabuffer;
233  setDataAvailableBit();
234  } else {
235  _NOP();
236  }
237  }
238 
239  if(ir_pos==27) {
240  TBCCTL1 &= ~CCIE;
241 
242  //GREENOFF;
243  // temporary debug output
244  //sendRS232Address(recvdatabuffer);
245  //if(recir_getError()) sendRS232('E');
246  //sendRS232String("\r\n");
247  if(!recir_getError()) beep_beep(20);
248 
249  // reenable interrupt for falling edge
250  P1IFG &= ~(0x04);
251  P1IE |= 0x04; // enable interrupt for recir RC5
252  leds_off(LEDS_RED);
253  }
254 
255  ir_pos++;
256  TBCCR1 += BIT50; // set new interrupt
257 
258  TBCCTL1 &= ~CCIFG;
259 }
260 
261 
262 /** \brief IR Interrupt routine
263  **
264  ** For the falling edge (start of RC5 packet)( mid of first start bit ), IRReceiver is on P12
265  ** real interrupt routine, which calls this, is in sensors.c */
266 void
267 ir_irq(void)
268 {
269  if(P1IN & 0x04) return; // high again, just a peak
270 
271  ir_pos = 0;
272  recvdatabuffer = 0;
273  clearErrorBit();
274 
275  // the first timer interrupt will occur in the mid of the first half of the second start bit
276  TBCCR1 = TBR + BIT75; // set first TBCCR1 IRQ to 75% of RC5 bitlength
277  TBCCTL1 &= ~CCIFG; // clear previous compare flag
278  TBCCTL1 |= CCIE; // CCR0 interrupt enabled, interrupt occurs when timer equals CCR0
279 
280  P1IE &= ~0x04; // disable interrupt for P12 ( ReceiveIR )
281  leds_on(LEDS_RED);
282  //GREENON;
283 }
284 
285 //@}
286 /*---------------------------------------------------------------------*/
287 PROCESS_THREAD(ir_process, ev, data)
288 {
289  PROCESS_BEGIN();
290 
291  // init TIMERB ccr0 to run continouslycreate the 5 ms interval
292  // ccr1 is used for ir receiving (RC5)
293  TBCTL = TBSSEL1 + TBCLR; // select SMCLK (2.4576MHz), clear TBR
294  TBCTL |= MC1; // Start Timer_A in continuous mode
295 
296 
297  P1IES |= 0x04; // Important for IR-RC5 receive to detect the first FALLING edge
298 
299  ir_event_received = process_alloc_event();
300 
301  while(1) {
302  PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_POLL);
303 
304  if(ir_poll() == IR_DATA) {
305  unsigned short irdata;
306  irdata = ir_data() & 0x7ff;
307  process_post(PROCESS_BROADCAST, ir_event_received, (process_data_t)irdata);
308  }
309 
310  }
311 
312  PROCESS_END();
313 }
314 /*---------------------------------------------------------------------*/