├── LICENSE ├── RC5.cpp ├── RC5.h ├── README.md └── examples └── RC5Decode └── RC5Decode.ino /LICENSE: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2013, Clearwater Software 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /RC5.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * RC5 Arduino Library 3 | * Guy Carpenter, Clearwater Software - 2013 4 | * 5 | * Licensed under the BSD2 license, see LICENSE for details. 6 | * 7 | * All text above must be included in any redistribution. 8 | */ 9 | 10 | #include "RC5.h" 11 | 12 | #define MIN_SHORT 444 13 | #define MAX_SHORT 1333 14 | #define MIN_LONG 1334 15 | #define MAX_LONG 2222 16 | 17 | /* 18 | * These step by two because it makes it 19 | * possible to use the values as bit-shift counters 20 | * when making state-machine transitions. States 21 | * are encoded as 2 bits, so we step by 2. 22 | */ 23 | #define EVENT_SHORTSPACE 0 24 | #define EVENT_SHORTPULSE 2 25 | #define EVENT_LONGSPACE 4 26 | #define EVENT_LONGPULSE 6 27 | 28 | #define STATE_START1 0 29 | #define STATE_MID1 1 30 | #define STATE_MID0 2 31 | #define STATE_START0 3 32 | 33 | /* 34 | * definitions for parsing the bitstream into 35 | * discrete parts. 14 bits are parsed as: 36 | * [S1][S2][T][A A A A A][C C C C C C] 37 | * Bits are transmitted MSbit first. 38 | */ 39 | #define S2_MASK 0x1000 // 1 bit 40 | #define S2_SHIFT 12 41 | #define TOGGLE_MASK 0x0800 // 1 bit 42 | #define TOGGLE_SHIFT 11 43 | #define ADDRESS_MASK 0x7C0 // 5 bits 44 | #define ADDRESS_SHIFT 6 45 | #define COMMAND_MASK 0x003F // low 6 bits 46 | #define COMMAND_SHIFT 0 47 | 48 | 49 | /* trans[] is a table of transitions, indexed by 50 | * the current state. Each byte in the table 51 | * represents a set of 4 possible next states, 52 | * packed as 4 x 2-bit values: 8 bits DDCCBBAA, 53 | * where AA are the low two bits, and 54 | * AA = short space transition 55 | * BB = short pulse transition 56 | * CC = long space transition 57 | * DD = long pulse transition 58 | * 59 | * If a transition does not change the state, 60 | * an error has occured and the state machine should 61 | * reset. 62 | * 63 | * The transition table is: 64 | * 00 00 00 01 from state 0: short space->1 65 | * 10 01 00 01 from state 1: short pulse->0, long pulse->2 66 | * 10 01 10 11 from state 2: short space->3, long space->1 67 | * 11 11 10 11 from state 3: short pulse->2 68 | */ 69 | const unsigned char trans[] = {0x01, 70 | 0x91, 71 | 0x9B, 72 | 0xFB}; 73 | 74 | RC5::RC5(unsigned char pin) 75 | { 76 | this->pin = pin; 77 | pinMode(pin, INPUT_PULLUP); 78 | this->reset(); 79 | } 80 | 81 | void RC5::reset() 82 | { 83 | this->state = STATE_MID1; 84 | this->bits = 1; // emit a 1 at start - see state machine graph 85 | this->command = 1; 86 | this->time0 = micros(); 87 | } 88 | 89 | void RC5::decodePulse(unsigned char signal, unsigned long period) 90 | { 91 | if (period >= MIN_SHORT && period <= MAX_SHORT) { 92 | this->decodeEvent(signal ? EVENT_SHORTPULSE : EVENT_SHORTSPACE); 93 | } else if (period >= MIN_LONG && period <= MAX_LONG) { 94 | this->decodeEvent(signal ? EVENT_LONGPULSE : EVENT_LONGSPACE); 95 | } else { 96 | // time period out of range, reset 97 | this->reset(); 98 | } 99 | } 100 | 101 | void RC5::decodeEvent(unsigned char event) 102 | { 103 | // find next state, 2 bits 104 | unsigned char newState = (trans[this->state]>>event) & 0x3; 105 | if (newState==this->state) { 106 | // no state change indicates error, reset 107 | this->reset(); 108 | } else { 109 | this->state = newState; 110 | if (newState == STATE_MID0) { 111 | // always emit 0 when entering mid0 state 112 | this->command = (this->command<<1)+0; 113 | this->bits++; 114 | } else if (newState == STATE_MID1) { 115 | // always emit 1 when entering mid1 state 116 | this->command = (this->command<<1)+1; 117 | this->bits++; 118 | } 119 | } 120 | } 121 | 122 | bool RC5::read(unsigned int *message) 123 | { 124 | /* Note that the input value read is inverted from the theoretical signal, 125 | ie we get 1 while no signal present, pulled to 0 when a signal is detected. 126 | So when the value changes, the inverted value that we get from reading the pin 127 | is equal to the theoretical (uninverted) signal value of the time period that 128 | has just ended. 129 | */ 130 | int value = digitalRead(this->pin); 131 | 132 | if (value != this->lastValue) { 133 | unsigned long time1 = micros(); 134 | unsigned long elapsed = time1-this->time0; 135 | this->time0 = time1; 136 | this->lastValue = value; 137 | this->decodePulse(value, elapsed); 138 | } 139 | 140 | if (this->bits == 14) { 141 | *message = this->command; 142 | this->command = 0; 143 | this->bits = 0; 144 | return true; 145 | } else { 146 | return false; 147 | } 148 | } 149 | 150 | bool RC5::read(unsigned char *toggle, unsigned char *address, unsigned char *command) 151 | { 152 | unsigned int message; 153 | if (this->read(&message)) { 154 | *toggle = (message & TOGGLE_MASK ) >> TOGGLE_SHIFT; 155 | *address = (message & ADDRESS_MASK) >> ADDRESS_SHIFT; 156 | 157 | // Support for extended RC5: 158 | // to get extended command, invert S2 and shift into command's 7th bit 159 | unsigned char extended; 160 | extended = (~message & S2_MASK) >> (S2_SHIFT - 6); 161 | *command = ((message & COMMAND_MASK) >> COMMAND_SHIFT) | extended; 162 | 163 | return true; 164 | } else { 165 | return false; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /RC5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * RC5 Arduino Library 3 | * Guy Carpenter, Clearwater Software - 2013 4 | * 5 | * Licensed under the BSD2 license, see LICENSE for details. 6 | * 7 | * All text above must be included in any redistribution. 8 | */ 9 | 10 | #ifndef RC5_h 11 | #define RC5_h 12 | 13 | #include 14 | 15 | class RC5 16 | { 17 | public: 18 | unsigned char pin; 19 | unsigned char state; 20 | unsigned long time0; 21 | unsigned long lastValue; 22 | unsigned int bits; 23 | unsigned int command; 24 | 25 | RC5(unsigned char pin); 26 | void reset(); 27 | bool read(unsigned int *message); 28 | bool read(unsigned char *toggle, unsigned char *address, unsigned char *command); 29 | void decodeEvent(unsigned char event); 30 | void decodePulse(unsigned char signal, unsigned long period); 31 | }; 32 | 33 | #endif // RC5_h 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Arduino RC5 remote control decoder library 2 | ========================================== 3 | 4 | This is an Arduino library for decoding infrared remote control commands encoded 5 | with the Philips RC5 protocol. It is based on the article 6 | "An Efficient Algorithm for Decoding RC5 Remote Control Signals" 7 | by Guy Carpenter, Oct 2001. 8 | 9 | For more information see http://clearwater.com.au/code/rc5. 10 | 11 | This library supports the extended RC5 protocol which uses the second 12 | stop bit S2 as an extension to the command value. 13 | 14 | See also http://www.sbprojects.com/knowledge/ir/rc5.php 15 | 16 | Using the Library 17 | ----------------- 18 | 19 | ```C++ 20 | 21 | #include 22 | #define IR_PIN 7 23 | RC5 rc5(IR_PIN); 24 | 25 | void loop() { 26 | if (rc5.read(&toggle, &address, &command)) 27 | { 28 | Serial.print(address); 29 | Serial.print(","); 30 | Serial.print(command); 31 | Serial.println(toggle ? " (t) " : ""); 32 | } 33 | } 34 | 35 | ``` 36 | 37 | Pressing the power button on the remote control twice produces this output: 38 | ``` 39 | 0,12 (t) 40 | 0,12 (t) 41 | 0,12 42 | 0,12 43 | ``` 44 | which is address 0 (TV1), command 12 (Standby) 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /examples/RC5Decode/RC5Decode.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Wiring notes: 3 | * 4 | * Using IR sensor like this: 5 | * http://www.adafruit.com/products/157 6 | * wired as follows: 7 | * pin1 - arduino pin 7 8 | * pin2 - ground 9 | * pin3 - 5V 10 | * 11 | * This code will display address, command and toggle for decoded sequences. 12 | * Pressing the power button twice gives this result: 13 | * a:0 c:12 t:0 <- first press, a:0 => TV1, c:12 => Standby command. 14 | * a:0 c:12 t:0 15 | * a:0 c:12 t:0 16 | * a:0 c:12 t:1 <- second press, toggle changes 17 | * a:0 c:12 t:1 18 | * 19 | */ 20 | 21 | #include 22 | 23 | int IR_PIN = 7; 24 | unsigned long t0; 25 | RC5 rc5(IR_PIN); 26 | 27 | void setup() { 28 | Serial.begin(9600); 29 | Serial.println("Starting"); 30 | } 31 | 32 | void loop() { 33 | unsigned char toggle; 34 | unsigned char address; 35 | unsigned char command; 36 | if (rc5.read(&toggle, &address, &command)) 37 | { 38 | Serial.print("a:"); 39 | Serial.print(address); 40 | Serial.print(" c:"); 41 | Serial.print(command); 42 | Serial.print(" t:"); 43 | Serial.println(toggle); 44 | } 45 | } 46 | --------------------------------------------------------------------------------