ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
IRreceiver.cpp
1 /*
2  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "IRreceiver.h"
24 #if defined(ARDUINO) && ARDUINO >= 100
25 #include <Arduino.h>
26 #else
27 #include <WProgram.h>
28 #endif
29 
159 static IRreceiver *receiver = 0;
160 
161 void _IR_receive_interrupt(void)
162 {
163  receiver->handleInterrupt();
164 }
165 
176 IRreceiver::IRreceiver(int interruptNumber)
177  : _system(0)
178  , _systemFilter(-1)
179  , started(false)
180  , halfChange(false)
181  , lastChange(0)
182  , bits(0)
183  , bitCount(0)
184  , buffer(0)
185  , lastBuffer(0)
186 {
187  switch (interruptNumber) {
188  case 0: default: pin = 2; break;
189  case 1: pin = 3; break;
190  case 2: pin = 21; break; // Arduino Mega only
191  case 3: pin = 20; break; // Arduino Mega only
192  case 4: pin = 19; break; // Arduino Mega only
193  case 5: pin = 18; break; // Arduino Mega only
194  }
195  receiver = this;
196  attachInterrupt(interruptNumber, _IR_receive_interrupt, CHANGE);
197 }
198 
221 {
222  unsigned buf;
223 
224  // Read the last-delivered sequence from the buffer and clear it.
225  cli();
226  buf = buffer;
227  buffer = 0;
228  sei();
229 
230  // Bail out if no sequence or it is not for us.
231  if (!buf) {
232  _system = -1;
233  return -1;
234  }
235  if (_systemFilter != -1) {
236  if (((buf >> 6) & 0x1F) != _systemFilter) {
237  _system = -1;
238  return -1;
239  }
240  }
241 
242  // Extract the command.
243  int cmd = buf & 0x3F;
244  if ((buf & 0x1000) == 0)
245  cmd += 64;
246 
247  // Is this a new command or an auto-repeat of the previous command?
248  // Bit 11 will toggle whenever a new button press is started.
249  if (lastBuffer == buf)
250  cmd += AUTO_REPEAT;
251  else
252  lastBuffer = buf;
253  _system = (buf >> 6) & 0x1F;
254  return cmd;
255 }
256 
304 // Number of microseconds that the signal is HIGH or LOW for
305 // indicating a bit. A 1 bit is transmitted as LOW for 889us
306 // followed by HIGH for 889us. A 0 bit is HIGH, then LOW.
307 #define IR_BIT_TIME 889
308 
309 // Number of microseconds to detect a long gap in the coding
310 // corresponding to 2 time units HIGH or LOW. We actually check
311 // for at least 1.5 time units to allow for slight variations
312 // in timing on different remote controls.
313 #define IR_LONG_BIT_TIME (889 * 6 / 4)
314 
315 // Maximum timeout for a single bit. If we don't see a rising edge
316 // within this time, then we have lost sync and need to restart.
317 #define IR_MAX_TIME (IR_BIT_TIME * 4)
318 
319 // Protocol details from http://en.wikipedia.org/wiki/RC-5
320 void IRreceiver::handleInterrupt()
321 {
322  bool value = digitalRead(pin);
323  unsigned long currentTime = micros();
324  if (!value) {
325  // Rising edge (input is active-LOW)
326  if (started && (currentTime - lastChange) > IR_MAX_TIME) {
327  // Too long since the last received bit, so restart the process.
328  started = false;
329  }
330  if (started) {
331  // We recognize bits on the falling edges, so merely
332  // adjust the "changed at last half-cycle" flag.
333  if ((currentTime - lastChange) > IR_LONG_BIT_TIME) {
334  // Long time since last falling edge indicates that the
335  // next bit will definitely be a 1.
336  halfChange = true;
337  } else {
338  halfChange = !halfChange;
339  }
340  lastChange = currentTime;
341  } else {
342  // Encountered the start bit - start receiving up to 14 bits.
343  lastChange = currentTime;
344  started = true;
345  halfChange = true;
346  bits = 0;
347  bitCount = 14;
348  }
349  } else if (started) {
350  // Falling edge
351  if ((currentTime - lastChange) > IR_LONG_BIT_TIME) {
352  // Long time since last rise indicates 1 followed by 0.
353  bits = (bits << 2) | 0x02;
354  --bitCount;
355  halfChange = true;
356  } else if (halfChange) {
357  // Rise was halfway through, so falling edge indicates a 1.
358  bits = (bits << 1) | 0x01;
359  halfChange = false;
360  } else {
361  // Rise was at the start, so falling edge indicates a 0.
362  bits <<= 1;
363  halfChange = true;
364  }
365  lastChange = currentTime;
366  --bitCount;
367  if (bitCount <= 0) {
368  // All 14 bits have been received, so deliver the value.
369  started = false;
370  buffer = bits;
371  }
372  }
373 }
IRreceiver(int interruptNumber=0)
Constructs a new infrared remote control receiver that is attached to interruptNumber.
Definition: IRreceiver.cpp:176
Manages the reception of RC-5 commands from an infrared remote control.
Definition: IRreceiver.h:29
int command()
Returns the next command from the remote control.
Definition: IRreceiver.cpp:220
static const int AUTO_REPEAT
Flag that is added to the output of command() when the command is an auto-repeated button press rathe...
Definition: IRreceiver.h:34