├── CPPLINT.cfg ├── examples ├── IRsendDemo │ ├── .gitignore │ ├── platformio.ini │ ├── lib │ │ └── readme.txt │ ├── .travis.yml │ └── IRsendDemo.ino ├── platformio.ini ├── IRGCSendDemo │ ├── platformio.ini │ └── IRGCSendDemo.ino ├── IRServer │ ├── platformio.ini │ └── IRServer.ino ├── IRrecvDemo │ ├── platformio.ini │ └── IRrecvDemo.ino ├── IRrecvDump │ ├── platformio.ini │ └── IRrecvDump.ino ├── IRrecvDumpV2 │ ├── platformio.ini │ └── IRrecvDumpV2.ino ├── IRGCTCPServer │ ├── platformio.ini │ └── IRGCTCPServer.ino ├── TurnOnDaikinAC │ ├── platformio.ini │ └── TurnOnDaikinAC.ino ├── JVCPanasonicSendDemo │ ├── platformio.ini │ └── JVCPanasonicSendDemo.ino ├── TurnOnKelvinatorAC │ ├── platformio.ini │ └── TurnOnKelvinatorAC.ino └── TurnOnMitsubishiAC │ ├── platformio.ini │ └── TurnOnMitsubishiAC.ino ├── src ├── CPPLINT.cfg ├── IRutils.h ├── IRtimer.h ├── ir_LG.h ├── IRtimer.cpp ├── IRutils.cpp ├── esp_interface.h ├── ir_Sherwood.cpp ├── ir_Mitsubishi.h ├── ir_GlobalCache.cpp ├── ir_Daikin.h ├── ir_Gree.cpp ├── ir_Whynter.cpp ├── ir_Aiwa.cpp ├── ir_Dish.cpp ├── ir_Kelvinator.h ├── ir_JVC.cpp ├── ir_Denon.cpp ├── ir_Coolix.cpp ├── ir_RCMM.cpp ├── ir_Samsung.cpp ├── ir_Panasonic.cpp ├── IRrecv.h ├── ir_Sony.cpp ├── ir_NEC.cpp ├── IRsend.h ├── ir_LG.cpp ├── IRremoteESP8266.h ├── ir_Daikin.cpp └── ir_Sanyo.cpp ├── README.md ├── library.properties ├── platformio.ini ├── library.json ├── test ├── IRutils_test.cpp ├── ir_Sherwood_test.cpp ├── IRsend_test.h ├── ir_GlobalCache_test.cpp ├── IRsend_test.cpp ├── ir_RCMM_test.cpp ├── ir_Gree_test.cpp └── ir_Sanyo_test.cpp └── keywords.txt /CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | set noparent 2 | root=src 3 | linelength=80 4 | -------------------------------------------------------------------------------- /examples/IRsendDemo/.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .piolibdeps 3 | .clang_complete 4 | .gcc-flags.json 5 | -------------------------------------------------------------------------------- /src/CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | filter=-build/include,+build/include_alpha,+build/include_order,+build/include_what_you_use 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IRremoteESP32 2 | Infrared remote library for ESP32: send and receive infrared signals with multiple protocols. Based on: https://github.com/markszabo/IRremoteESP8266 3 | 4 | Still in development 5 | -------------------------------------------------------------------------------- /src/IRutils.h: -------------------------------------------------------------------------------- 1 | #ifndef IRUTILS_H_ 2 | #define IRUTILS_H_ 3 | 4 | // Copyright 2017 David Conran 5 | 6 | #define __STDC_LIMIT_MACROS 7 | #include 8 | 9 | uint64_t reverseBits(uint64_t input, uint16_t nbits); 10 | 11 | #endif // IRUTILS_H_ 12 | -------------------------------------------------------------------------------- /src/IRtimer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #ifndef IRTIMER_H_ 4 | #define IRTIMER_H_ 5 | 6 | #define __STDC_LIMIT_MACROS 7 | #include 8 | 9 | // Classes 10 | class IRtimer { 11 | public: 12 | IRtimer(); 13 | void reset(); 14 | uint32_t elapsed(); 15 | 16 | private: 17 | uint32_t start; 18 | }; 19 | 20 | #endif // IRTIMER_H_ 21 | -------------------------------------------------------------------------------- /examples/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif32 12 | framework = arduino 13 | board = 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/IRGCSendDemo/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/IRServer/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/IRrecvDemo/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/IRrecvDump/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/IRrecvDumpV2/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/IRGCTCPServer/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/TurnOnDaikinAC/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/JVCPanasonicSendDemo/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/TurnOnKelvinatorAC/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /examples/TurnOnMitsubishiAC/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = ../../ 3 | src_dir=. 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | -------------------------------------------------------------------------------- /src/ir_LG.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #ifndef IR_LG_H_ 4 | #define IR_LG_H_ 5 | 6 | // L GGGG 7 | // L G 8 | // L G GG 9 | // L G G 10 | // LLLLL GGG 11 | 12 | #define __STDC_LIMIT_MACROS 13 | #include 14 | 15 | uint8_t calcLGChecksum(uint16_t data); 16 | 17 | #endif // IR_LG_H_ 18 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=IRremoteESP8266 2 | version=2.0.1 3 | author=Sebastien Warin, Mark Szabo, Ken Shirriff, David Conran 4 | maintainer=Mark Szabo, David Conran, Sebastien Warin, Roi Dayan, Massimiliano Pinto 5 | sentence=Send and receive infrared signals with multiple protocols (ESP8266) 6 | paragraph=This library enables you to send and receive infra-red signals on an ESP8266. 7 | category=Device Control 8 | url=https://github.com/markszabo/IRremoteESP8266 9 | architectures=esp8266 10 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | lib_extra_dirs = . 3 | src_dir = examples/IRrecvDumpV2 4 | 5 | [common] 6 | build_flags = 7 | lib_deps_builtin = 8 | lib_deps_external = 9 | 10 | [env:nodemcuv2] 11 | platform = espressif8266 12 | framework = arduino 13 | board = nodemcuv2 14 | build_flags = ${common.build_flags} 15 | lib_deps = 16 | ${common.lib_deps_builtin} 17 | ${common.lib_deps_external} 18 | 19 | [env:d1_mini] 20 | platform = espressif8266 21 | framework = arduino 22 | board = d1_mini 23 | build_flags = ${common.build_flags} 24 | lib_deps = 25 | ${common.lib_deps_builtin} 26 | ${common.lib_deps_external} 27 | -------------------------------------------------------------------------------- /examples/TurnOnDaikinAC/TurnOnDaikinAC.ino: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 sillyfrog */ 2 | #include 3 | #include 4 | 5 | IRDaikinESP dakinir(D1); 6 | 7 | void setup() { 8 | dakinir.begin(); 9 | Serial.begin(115200); 10 | } 11 | 12 | 13 | void loop() { 14 | Serial.println("Sending..."); 15 | 16 | // Set up what we want to send. See ir_Daikin.cpp for all the options. 17 | dakinir.on(); 18 | dakinir.setFan(1); 19 | dakinir.setMode(DAIKIN_COOL); 20 | dakinir.setTemp(25); 21 | dakinir.setSwingVertical(0); 22 | dakinir.setSwingHorizontal(0); 23 | 24 | // Now send the IR signal. 25 | dakinir.send(); 26 | 27 | delay(5000); 28 | } 29 | -------------------------------------------------------------------------------- /examples/IRsendDemo/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; http://docs.platformio.org/page/projectconf.html 10 | [platformio] 11 | lib_extra_dirs = ../../ 12 | src_dir=. 13 | 14 | [common] 15 | build_flags = 16 | lib_deps_builtin = 17 | lib_deps_external = 18 | 19 | 20 | [env:esp32dev] 21 | platform = espressif32 22 | board = esp32dev 23 | framework = arduino 24 | -------------------------------------------------------------------------------- /src/IRtimer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRtimer.h" 4 | #ifndef UNIT_TEST 5 | #include 6 | #endif 7 | 8 | // This class performs a simple time in useconds since instantiated. 9 | // Handles when the system timer wraps around (once). 10 | 11 | IRtimer::IRtimer() { 12 | reset(); 13 | } 14 | 15 | void IRtimer::reset() { 16 | #ifndef UNIT_TEST 17 | start = micros(); 18 | #else 19 | start = 0; 20 | #endif 21 | } 22 | 23 | uint32_t IRtimer::elapsed() { 24 | #ifndef UNIT_TEST 25 | uint32_t now = micros(); 26 | #else 27 | uint32_t now = 0; 28 | #endif 29 | if (start <= now) // Check if the system timer has wrapped. 30 | return now - start; // No wrap. 31 | else 32 | return UINT32_MAX - start + now; // Has wrapped. 33 | } 34 | -------------------------------------------------------------------------------- /src/IRutils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRutils.h" 4 | #ifndef UNIT_TEST 5 | #include 6 | #endif 7 | #define __STDC_LIMIT_MACROS 8 | #include 9 | #include 10 | 11 | // Reverse the order of the requested least significant nr. of bits. 12 | // Args: 13 | // input: Bit pattern/integer to reverse. 14 | // nbits: Nr. of bits to reverse. 15 | // Returns: 16 | // The reversed bit pattern. 17 | uint64_t reverseBits(uint64_t input, uint16_t nbits) { 18 | if (nbits <= 1) 19 | return input; // Reversing <= 1 bits makes no change at all. 20 | // Cap the nr. of bits to rotate to the max nr. of bits in the input. 21 | nbits = std::min(nbits, (uint16_t) (sizeof(input) * 8)); 22 | uint64_t output = 0; 23 | for (uint16_t i = 0; i < nbits; i++) { 24 | output <<= 1; 25 | output |= (input & 1); 26 | input >>= 1; 27 | } 28 | // Merge any remaining unreversed bits back to the top of the reversed bits. 29 | return (input << nbits) | output; 30 | } 31 | -------------------------------------------------------------------------------- /examples/IRsendDemo/lib/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for the project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link to executable file. 4 | 5 | The source code of each library should be placed in separate directory, like 6 | "lib/private_lib/[here are source files]". 7 | 8 | For example, see how can be organized `Foo` and `Bar` libraries: 9 | 10 | |--lib 11 | | |--Bar 12 | | | |--docs 13 | | | |--examples 14 | | | |--src 15 | | | |- Bar.c 16 | | | |- Bar.h 17 | | |--Foo 18 | | | |- Foo.c 19 | | | |- Foo.h 20 | | |- readme.txt --> THIS FILE 21 | |- platformio.ini 22 | |--src 23 | |- main.c 24 | 25 | Then in `src/main.c` you should use: 26 | 27 | #include 28 | #include 29 | 30 | // rest H/C/CPP code 31 | 32 | PlatformIO will find your libraries automatically, configure preprocessor's 33 | include paths and build them. 34 | 35 | More information about PlatformIO Library Dependency Finder 36 | - http://docs.platformio.org/page/librarymanager/ldf.html 37 | -------------------------------------------------------------------------------- /examples/IRrecvDemo/IRrecvDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRrecvDemo - demonstrates receiving IR codes with IRrecv 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * Version 0.1 Sept, 2015 5 | * Based on Ken Shirriff's IrsendDemo 6 | * Version 0.1 July, 2009 7 | * Copyright 2009 Ken Shirriff, http://arcfn.com 8 | */ 9 | 10 | #include 11 | 12 | // an IR detector/demodulator is connected to GPIO pin 2 13 | uint16_t RECV_PIN = 2; 14 | 15 | IRrecv irrecv(RECV_PIN); 16 | 17 | decode_results results; 18 | 19 | void setup() { 20 | Serial.begin(9600); 21 | irrecv.enableIRIn(); // Start the receiver 22 | } 23 | 24 | void loop() { 25 | if (irrecv.decode(&results)) { 26 | // print() & println() can't handle printing long longs. (uint64_t) 27 | // So we have to print the top and bottom halves separately. 28 | if (results.value >> 32) 29 | Serial.print((uint32_t) (results.value >> 32), HEX); 30 | Serial.println((uint32_t) (results.value & 0xFFFFFFFF), HEX); 31 | irrecv.resume(); // Receive the next value 32 | } 33 | delay(100); 34 | } 35 | -------------------------------------------------------------------------------- /src/esp_interface.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | #ifndef __ESP_INTERFACE_H__ 17 | #define __ESP_INTERFACE_H__ 18 | 19 | #include 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | typedef enum { 26 | ESP_IF_WIFI_STA = 0, /**< ESP32 station interface */ 27 | ESP_IF_WIFI_AP, /**< ESP32 soft-AP interface */ 28 | ESP_IF_ETH, /**< ESP32 ethernet interface */ 29 | ESP_IF_MAX 30 | } esp_interface_t; 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | 37 | #endif /* __ESP_INTERFACE_TYPES_H__ */ 38 | -------------------------------------------------------------------------------- /examples/IRGCSendDemo/IRGCSendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRsendGCDemo 3 | * demonstrates sending Global Cache-formatted IR codes with IRsend 4 | * 5 | * An IR LED must be connected to ESP8266 pin 0. 6 | * Version 0.1 30 March, 2016 7 | * Based on Ken Shirriff's IrsendDemo 8 | * Version 0.1 July, 2009 9 | * Copyright 2009 Ken Shirriff 10 | * http://arcfn.com 11 | */ 12 | 13 | #include 14 | 15 | // Codes are in Global Cache format less the emitter ID and request ID. 16 | // These codes can be found in GC's Control Tower database. 17 | 18 | uint16_t Samsung_power_toggle[71] = { 19 | 38000, 1, 1, 170, 170, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20, 20, 20, 20, 20 | 20, 20, 20, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21 | 20, 20, 20, 63, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 63, 20, 22 | 20, 20, 63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 1798}; 23 | 24 | IRsend irsend(4); // an IR emitter led is connected to GPIO pin 4 25 | 26 | void setup() { 27 | irsend.begin(); 28 | Serial.begin(115200); 29 | } 30 | 31 | void loop() { 32 | Serial.println("Toggling power"); 33 | irsend.sendGC(Samsung_power_toggle, 71); 34 | delay(10000); 35 | } 36 | -------------------------------------------------------------------------------- /examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend 3 | * An IR LED must be connected to ESP8266 pin 0. 4 | * Version 0.1 June, 2015 5 | * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com 6 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 7 | */ 8 | #include 9 | 10 | #define PanasonicAddress 0x4004 // Panasonic address (Pre data) 11 | #define PanasonicPower 0x100BCBD // Panasonic Power button 12 | 13 | #define JVCPower 0xC5E8 14 | 15 | IRsend irsend(0); // an IR led is connected to GPIO pin 0 16 | 17 | void setup() { 18 | irsend.begin(); 19 | } 20 | 21 | void loop() { 22 | // This should turn your TV on and off 23 | irsend.sendPanasonic(PanasonicAddress, PanasonicPower); 24 | 25 | irsend.sendJVC(JVCPower, 16, 0); // hex value, 16 bits, no repeat 26 | // see http://www.sbprojects.com/knowledge/ir/jvc.php for information 27 | delayMicroseconds(50); 28 | irsend.sendJVC(JVCPower, 16, 1); // hex value, 16 bits, repeat 29 | delayMicroseconds(50); 30 | } 31 | -------------------------------------------------------------------------------- /src/ir_Sherwood.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include 4 | #include "IRsend.h" 5 | 6 | // SSSSS HH HH EEEEEEE RRRRRR WW WW OOOOO OOOOO DDDDD 7 | // SS HH HH EE RR RR WW WW OO OO OO OO DD DD 8 | // SSSSS HHHHHHH EEEEE RRRRRR WW W WW OO OO OO OO DD DD 9 | // SS HH HH EE RR RR WW WWW WW OO OO OO OO DD DD 10 | // SSSSS HH HH EEEEEEE RR RR WW WW OOOO0 OOOO0 DDDDDD 11 | 12 | #if SEND_SHERWOOD 13 | // Send an IR command to a Sherwood device. 14 | // 15 | // Args: 16 | // data: The contents of the command you want to send. 17 | // nbits: The bit size of the command being sent. (SHERWOOD_BITS) 18 | // repeat: The nr. of times you want the command to be repeated. (Default: 1) 19 | // 20 | // Status: STABLE / Known working. 21 | // 22 | // Note: 23 | // Sherwood remote codes appear to be NEC codes with a manditory repeat code. 24 | // i.e. repeat should be >= SHERWOOD_MIN_REPEAT (1). 25 | void IRsend::sendSherwood(uint64_t data, uint16_t nbits, 26 | uint16_t repeat) { 27 | sendNEC(data, nbits, std::max((uint16_t) SHERWOOD_MIN_REPEAT, repeat)); 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "IRremoteESP8266", 3 | "version": "2.0.1", 4 | "keywords": "infrared, ir, remote, esp8266", 5 | "description": "Send and receive infrared signals with multiple protocols (ESP8266)", 6 | "repository": 7 | { 8 | "type": "git", 9 | "url": "https://github.com/markszabo/IRremoteESP8266.git" 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Ken Shirriff", 14 | "email": "zetoslab@gmail.com" 15 | }, 16 | { 17 | "name": "Mark Szabo", 18 | "url": "http://nomartini-noparty.blogspot.com/", 19 | "maintainer": true 20 | }, 21 | { 22 | "name": "Sebastien Warin", 23 | "url": "http://sebastien.warin.fr", 24 | "maintainer": true 25 | }, 26 | { 27 | "name": "David Conran", 28 | "url": "https://plus.google.com/+davidconran", 29 | "maintainer": true 30 | }, 31 | { 32 | "name": "Roi Dayan", 33 | "url": "https://github.com/roidayan/", 34 | "maintainer": true 35 | }, 36 | { 37 | "name": "Massimiliano Pinto", 38 | "url": "https://github.com/pintomax/", 39 | "maintainer": true 40 | } 41 | ], 42 | "frameworks": "arduino", 43 | "platforms": "espressif8266" 44 | } 45 | -------------------------------------------------------------------------------- /test/IRutils_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRutils.h" 4 | #include "gtest/gtest.h" 5 | 6 | // Tests reverseBits(). 7 | 8 | // Tests reverseBits for typical use. 9 | TEST(ReverseBitsTest, TypicalUse) { 10 | EXPECT_EQ(0xF, reverseBits(0xF0, 8)); 11 | EXPECT_EQ(0xFFFF, reverseBits(0xFFFF0000, 32)); 12 | EXPECT_EQ(0x555500005555FFFF, reverseBits(0xFFFFAAAA0000AAAA, 64)); 13 | EXPECT_EQ(0, reverseBits(0, 64)); 14 | EXPECT_EQ(0xFFFFFFFFFFFFFFFF, reverseBits(0xFFFFFFFFFFFFFFFF, 64)); 15 | } 16 | 17 | // Tests reverseBits for bit size values <= 1 18 | TEST(ReverseBitsTest, LessThanTwoBitsReversed) { 19 | EXPECT_EQ(0x12345678, reverseBits(0x12345678, 1)); 20 | EXPECT_EQ(1234, reverseBits(1234, 0)); 21 | } 22 | 23 | // Tests reverseBits for bit size larger than a uint64_t. 24 | TEST(ReverseBitsTest, LargerThan64BitsReversed) { 25 | EXPECT_EQ(0, reverseBits(0, 65)); 26 | EXPECT_EQ(0xFFFFFFFFFFFFFFFF, reverseBits(0xFFFFFFFFFFFFFFFF, 100)); 27 | EXPECT_EQ(0x555500005555FFFF, reverseBits(0xFFFFAAAA0000AAAA, 3000)); 28 | } 29 | 30 | // Tests reverseBits for bit sizes less than all the data stored. 31 | TEST(ReverseBitsTest, LessBitsReversedThanInputHasSet) { 32 | EXPECT_EQ(0xF8, reverseBits(0xF1, 4)); 33 | EXPECT_EQ(0xF5, reverseBits(0xFA, 4)); 34 | EXPECT_EQ(0x12345678FFFF0000, reverseBits(0x123456780000FFFF, 32)); 35 | } 36 | -------------------------------------------------------------------------------- /examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 David Conran */ 2 | #include 3 | #include 4 | 5 | IRMitsubishiAC mitsubir(D1); // IR led controlled by Pin D1. 6 | 7 | void printState() { 8 | // Display the settings. 9 | Serial.println("Mitsubishi A/C remote is in the following state:"); 10 | Serial.printf(" Power: %d, Mode: %d, Temp: %dC, Fan Speed: %d," \ 11 | " Vane Mode: %d\n", 12 | mitsubir.getPower(), mitsubir.getMode(), mitsubir.getTemp(), 13 | mitsubir.getFan(), mitsubir.getVane()); 14 | // Display the encoded IR sequence. 15 | unsigned char* ir_code = mitsubir.getRaw(); 16 | Serial.print("IR Code: 0x"); 17 | for (uint8_t i = 0; i < MITSUBISHI_AC_STATE_LENGTH; i++) 18 | Serial.printf("%02X", ir_code[i]); 19 | Serial.println(); 20 | } 21 | 22 | void setup() { 23 | mitsubir.begin(); 24 | Serial.begin(115200); 25 | delay(200); 26 | 27 | // Set up what we want to send. See ir_Mitsubishi.cpp for all the options. 28 | Serial.println("Default state of the remote."); 29 | printState(); 30 | Serial.println("Setting desired state for A/C."); 31 | mitsubir.on(); 32 | mitsubir.setFan(1); 33 | mitsubir.setMode(MITSUBISHI_AC_COOL); 34 | mitsubir.setTemp(26); 35 | mitsubir.setVane(MITSUBISHI_AC_VANE_AUTO); 36 | } 37 | 38 | void loop() { 39 | // Now send the IR signal. 40 | Serial.println("Sending IR command to A/C ..."); 41 | mitsubir.send(); 42 | printState(); 43 | delay(5000); 44 | } 45 | -------------------------------------------------------------------------------- /examples/IRsendDemo/.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < http://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < http://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < http://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choice one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # 39 | # script: 40 | # - platformio run 41 | 42 | 43 | # 44 | # Template #2: The project is intended to by used as a library with examples 45 | # 46 | 47 | # language: python 48 | # python: 49 | # - "2.7" 50 | # 51 | # sudo: false 52 | # cache: 53 | # directories: 54 | # - "~/.platformio" 55 | # 56 | # env: 57 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 58 | # - PLATFORMIO_CI_SRC=examples/file.ino 59 | # - PLATFORMIO_CI_SRC=path/to/test/directory 60 | # 61 | # install: 62 | # - pip install -U platformio 63 | # 64 | # script: 65 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 66 | -------------------------------------------------------------------------------- /examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 David Conran */ 2 | #include 3 | #include 4 | 5 | IRKelvinatorAC kelvir(D1); // IR led controlled by Pin D1. 6 | 7 | void printState() { 8 | // Display the settings. 9 | Serial.println("Kelvinator A/C remote is in the following state:"); 10 | Serial.printf(" Basic\n Power: %d, Mode: %d, Temp: %dC, Fan Speed: %d\n", 11 | kelvir.getPower(), kelvir.getMode(), kelvir.getTemp(), 12 | kelvir.getFan()); 13 | Serial.printf(" Options\n X-Fan: %d, Light: %d, Ion Filter: %d\n", 14 | kelvir.getXFan(), kelvir.getLight(), kelvir.getIonFilter()); 15 | Serial.printf(" Swing (V): %d, Swing (H): %d, Turbo: %d, Quiet: %d\n", 16 | kelvir.getSwingVertical(), kelvir.getSwingHorizontal(), 17 | kelvir.getTurbo(), kelvir.getQuiet()); 18 | // Display the encoded IR sequence. 19 | unsigned char* ir_code = kelvir.getRaw(); 20 | Serial.print("IR Code: 0x"); 21 | for (uint8_t i = 0; i < KELVINATOR_STATE_LENGTH; i++) 22 | Serial.printf("%02X", ir_code[i]); 23 | Serial.println(); 24 | } 25 | 26 | void setup() { 27 | kelvir.begin(); 28 | Serial.begin(115200); 29 | delay(200); 30 | 31 | // Set up what we want to send. See ir_Kelvinator.cpp for all the options. 32 | // Most things default to off. 33 | Serial.println("Default state of the remote."); 34 | printState(); 35 | Serial.println("Setting desired state for A/C."); 36 | kelvir.on(); 37 | kelvir.setFan(1); 38 | kelvir.setMode(KELVINATOR_COOL); 39 | kelvir.setTemp(26); 40 | kelvir.setSwingVertical(false); 41 | kelvir.setSwingHorizontal(true); 42 | kelvir.setXFan(true); 43 | kelvir.setIonFilter(false); 44 | kelvir.setLight(true); 45 | } 46 | 47 | void loop() { 48 | // Now send the IR signal. 49 | Serial.println("Sending IR command to A/C ..."); 50 | kelvir.send(); 51 | printState(); 52 | delay(5000); 53 | } 54 | -------------------------------------------------------------------------------- /src/ir_Mitsubishi.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009 Ken Shirriff 2 | // Copyright 2017 David Conran 3 | #ifndef IR_MITSUBISHI_H_ 4 | #define IR_MITSUBISHI_H_ 5 | 6 | #define __STDC_LIMIT_MACROS 7 | #include 8 | #include "IRremoteESP8266.h" 9 | #include "IRsend.h" 10 | 11 | // MMMMM IIIII TTTTT SSSS U U BBBB IIIII SSSS H H IIIII 12 | // M M M I T S U U B B I S H H I 13 | // M M M I T SSS U U BBBB I SSS HHHHH I 14 | // M M I T S U U B B I S H H I 15 | // M M IIIII T SSSS UUU BBBBB IIIII SSSS H H IIIII 16 | 17 | // Mitsubishi (TV) decoding added from https://github.com/z3t0/Arduino-IRremote 18 | // Mitsubishi (TV) sending & Mitsubishi A/C support added by David Conran 19 | 20 | // Constants 21 | #define MITSUBISHI_AC_AUTO 0x20U 22 | #define MITSUBISHI_AC_COOL 0x18U 23 | #define MITSUBISHI_AC_DRY 0x10U 24 | #define MITSUBISHI_AC_HEAT 0x08U 25 | #define MITSUBISHI_AC_POWER 0x20U 26 | #define MITSUBISHI_AC_FAN_AUTO 0U 27 | #define MITSUBISHI_AC_FAN_MAX 5U 28 | #define MITSUBISHI_AC_FAN_REAL_MAX 4U 29 | #define MITSUBISHI_AC_FAN_SILENT 6U 30 | #define MITSUBISHI_AC_MIN_TEMP 16U // 16C 31 | #define MITSUBISHI_AC_MAX_TEMP 31U // 31C 32 | #define MITSUBISHI_AC_VANE_AUTO 0U 33 | #define MITSUBISHI_AC_VANE_AUTO_MOVE 7U 34 | 35 | #if SEND_MITSUBISHI_AC 36 | class IRMitsubishiAC { 37 | public: 38 | explicit IRMitsubishiAC(uint16_t pin); 39 | 40 | void stateReset(); 41 | void send(); 42 | void begin(); 43 | void on(); 44 | void off(); 45 | void setPower(bool state); 46 | bool getPower(); 47 | void setTemp(uint8_t temp); 48 | uint8_t getTemp(); 49 | void setFan(uint8_t fan); 50 | uint8_t getFan(); 51 | void setMode(uint8_t mode); 52 | uint8_t getMode(); 53 | void setVane(uint8_t mode); 54 | uint8_t getVane(); 55 | uint8_t* getRaw(); 56 | 57 | private: 58 | uint8_t remote_state[MITSUBISHI_AC_STATE_LENGTH]; 59 | void checksum(); 60 | IRsend _irsend; 61 | }; 62 | 63 | #endif 64 | 65 | #endif // IR_MITSUBISHI_H_ 66 | -------------------------------------------------------------------------------- /examples/IRsendDemo/IRsendDemo.ino: -------------------------------------------------------------------------------- 1 | /* IRremoteESP32: IRsendDemo - demonstrates sending IR codes with IRsend. 2 | * 3 | * Version 1.0 June 2017 4 | * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, 5 | * Copyright 2009 Ken Shirriff, http://arcfn.com 6 | * 7 | * An IR LED with resistor and NPN transistor must be connected 8 | * 9 | * Suggested circuit: 10 | * https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending 11 | * 12 | * Common mistakes & tips: 13 | * * Don't just connect the IR LED directly to the pin, it won't 14 | * have enough current to drive the IR LED effectively. 15 | * * Make sure you have the IR LED polarity correct. 16 | * See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity 17 | * * Typical digital camera/phones can be used to see if the IR LED is flashed. 18 | * Replace the IR LED with a normal LED if you don't have a digital camera 19 | * when debugging. 20 | * * Avoid using the following pins unless you really know what you are doing: 21 | * * Pin 0/D3: Can interfere with the boot/program mode & support circuits. 22 | * * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere. 23 | * * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere. 24 | * 25 | */ 26 | 27 | #include "IRsend.h" 28 | 29 | 30 | #define ONEMARK 400 //Nr. of usecs for the led to be pulsed for a '1' bit. 31 | #define ONESPACE 400 //Nr. of usecs for the led to be fully off for a '1' bit. 32 | #define ZEROMARK 400 //Nr. of usecs for the led to be pulsed for a '0' bit. 33 | #define ZEROSPACE 1200 //Nr. of usecs for the led to be fully off for a '0' bit. 34 | #define IRLED 26 35 | 36 | IRsend irsend(IRLED); // an IR led is connected to the IRLED gpio 37 | 38 | void setup() { 39 | irsend.begin(); 40 | Serial.begin(115200); 41 | } 42 | 43 | void loop() { 44 | irsend.enableIROut(38000, 45); 45 | //send header 46 | irsend.mark(3200); 47 | irsend.space(1600); 48 | //send command 49 | irsend.sendData(ONEMARK, ONESPACE, ZEROMARK, ZEROSPACE, 0xCF, 8, 1); 50 | irsend.sendData(ONEMARK, ONESPACE, ZEROMARK, ZEROSPACE, 0x00, 8, 1); 51 | irsend.sendData(ONEMARK, ONESPACE, ZEROMARK, ZEROSPACE, 0xA0, 8, 1); 52 | irsend.sendData(ONEMARK, ONESPACE, ZEROMARK, ZEROSPACE, 0xC0, 8, 1); 53 | irsend.sendData(ONEMARK, ONESPACE, ZEROMARK, ZEROSPACE, 0xE0, 8, 1); 54 | irsend.sendData(ONEMARK, ONESPACE, ZEROMARK, ZEROSPACE, 0xC5, 8, 1); 55 | irsend.sendData(ONEMARK, ONESPACE, ZEROMARK, ZEROSPACE, 0xE6, 8, 1); 56 | irsend.sendData(ONEMARK, ONESPACE, ZEROMARK, ZEROSPACE, 0xDF, 8, 1); 57 | irsend.sendData(ONEMARK, ONESPACE, ZEROMARK, ZEROSPACE, 0x7F, 8, 1); 58 | 59 | delay(2000); 60 | } 61 | -------------------------------------------------------------------------------- /examples/IRServer/IRServer.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRServer - demonstrates sending IR codes controlled from a webserver 3 | * An IR LED must be connected to ESP8266 pin 0. 4 | * Version 0.1 June, 2015 5 | * Copyright 2015 Mark Szabo 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | const char* ssid = "....."; 15 | const char* password = "....."; 16 | MDNSResponder mdns; 17 | 18 | ESP8266WebServer server(80); 19 | 20 | IRsend irsend(0); 21 | 22 | void handleRoot() { 23 | server.send(200, "text/html", 24 | "" \ 25 | "ESP8266 Demo" \ 26 | "" \ 27 | "

Hello from ESP8266, you can send NEC encoded IR" \ 28 | "signals from here!

" \ 29 | "

Send 0xFFE01F

" \ 30 | "

Send 0xFAB123

" \ 31 | "

Send 0xFFE896

" \ 32 | "" \ 33 | ""); 34 | } 35 | 36 | void handleIr() { 37 | for (uint8_t i = 0; i < server.args(); i++) { 38 | if (server.argName(i) == "code") { 39 | uint32_t code = strtoul(server.arg(i).c_str(), NULL, 10); 40 | irsend.sendNEC(code, 32); 41 | } 42 | } 43 | handleRoot(); 44 | } 45 | 46 | void handleNotFound() { 47 | String message = "File Not Found\n\n"; 48 | message += "URI: "; 49 | message += server.uri(); 50 | message += "\nMethod: "; 51 | message += (server.method() == HTTP_GET)?"GET":"POST"; 52 | message += "\nArguments: "; 53 | message += server.args(); 54 | message += "\n"; 55 | for (uint8_t i = 0; i < server.args(); i++) 56 | message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; 57 | server.send(404, "text/plain", message); 58 | } 59 | 60 | void setup(void) { 61 | irsend.begin(); 62 | 63 | Serial.begin(115200); 64 | WiFi.begin(ssid, password); 65 | Serial.println(""); 66 | 67 | // Wait for connection 68 | while (WiFi.status() != WL_CONNECTED) { 69 | delay(500); 70 | Serial.print("."); 71 | } 72 | Serial.println(""); 73 | Serial.print("Connected to "); 74 | Serial.println(ssid); 75 | Serial.print("IP address: "); 76 | Serial.println(WiFi.localIP()); 77 | 78 | if (mdns.begin("esp8266", WiFi.localIP())) { 79 | Serial.println("MDNS responder started"); 80 | } 81 | 82 | server.on("/", handleRoot); 83 | server.on("/ir", handleIr); 84 | 85 | server.on("/inline", [](){ 86 | server.send(200, "text/plain", "this works as well"); 87 | }); 88 | 89 | server.onNotFound(handleNotFound); 90 | 91 | server.begin(); 92 | Serial.println("HTTP server started"); 93 | } 94 | 95 | void loop(void) { 96 | server.handleClient(); 97 | } 98 | -------------------------------------------------------------------------------- /test/ir_Sherwood_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRsend.h" 4 | #include "IRsend_test.h" 5 | #include "gtest/gtest.h" 6 | 7 | // Tests for sendSherwood(). 8 | 9 | // Test sending typical data only. 10 | TEST(TestSendSherwood, SendDataOnly) { 11 | IRsendTest irsend(4); 12 | irsend.begin(); 13 | 14 | irsend.reset(); 15 | irsend.sendSherwood(0xC1A28877); 16 | EXPECT_EQ("m9000s4500m560s1690m560s1690m560s560m560s560m560s560m560s560" 17 | "m560s560m560s1690m560s1690m560s560m560s1690m560s560m560s560" 18 | "m560s560m560s1690m560s560m560s1690m560s560m560s560m560s560" 19 | "m560s1690m560s560m560s560m560s560m560s560m560s1690m560s1690" 20 | "m560s1690m560s560m560s1690m560s1690m560s1690m560s108000" 21 | "m9000s2250m560s108000", irsend.outputStr()); 22 | } 23 | 24 | // Test sending typical data with extra repeats. 25 | TEST(TestSendSherwood, SendDataWithRepeats) { 26 | IRsendTest irsend(4); 27 | irsend.begin(); 28 | 29 | irsend.reset(); 30 | irsend.sendSherwood(0xC1A28877, 32, 2); 31 | EXPECT_EQ("m9000s4500m560s1690m560s1690m560s560m560s560m560s560m560s560" 32 | "m560s560m560s1690m560s1690m560s560m560s1690m560s560m560s560" 33 | "m560s560m560s1690m560s560m560s1690m560s560m560s560m560s560" 34 | "m560s1690m560s560m560s560m560s560m560s560m560s1690m560s1690" 35 | "m560s1690m560s560m560s1690m560s1690m560s1690m560s108000" 36 | "m9000s2250m560s108000" 37 | "m9000s2250m560s108000", irsend.outputStr()); 38 | } 39 | 40 | // Test sending typical data with explicit no repeats. 41 | TEST(TestSendSherwood, SendDataWithZeroRepeats) { 42 | IRsendTest irsend(4); 43 | irsend.begin(); 44 | 45 | irsend.reset(); 46 | irsend.sendSherwood(0xC1A28877, 32, 0); 47 | // Should have a single NEC repeat, as we always send one. 48 | EXPECT_EQ("m9000s4500m560s1690m560s1690m560s560m560s560m560s560m560s560" 49 | "m560s560m560s1690m560s1690m560s560m560s1690m560s560m560s560" 50 | "m560s560m560s1690m560s560m560s1690m560s560m560s560m560s560" 51 | "m560s1690m560s560m560s560m560s560m560s560m560s1690m560s1690" 52 | "m560s1690m560s560m560s1690m560s1690m560s1690m560s108000" 53 | "m9000s2250m560s108000", irsend.outputStr()); 54 | } 55 | 56 | // Test that a typical Sherwood send decodes as the appropriate NEC value. 57 | TEST(TestSendSherwood, DecodesAsNEC) { 58 | IRsendTest irsend(4); 59 | IRrecv irrecv(0); 60 | irsend.begin(); 61 | 62 | irsend.reset(); 63 | irsend.sendSherwood(0xC1A28877); 64 | irsend.makeDecodeResult(); 65 | 66 | EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); 67 | EXPECT_EQ(NEC, irsend.capture.decode_type); 68 | EXPECT_EQ(NEC_BITS, irsend.capture.bits); 69 | EXPECT_EQ(0xC1A28877, irsend.capture.value); 70 | EXPECT_EQ(0x4583, irsend.capture.address); 71 | EXPECT_EQ(0x11, irsend.capture.command); 72 | } 73 | -------------------------------------------------------------------------------- /test/IRsend_test.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #ifndef TEST_IRSEND_TEST_H_ 4 | #define TEST_IRSEND_TEST_H_ 5 | 6 | #define __STDC_LIMIT_MACROS 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "IRrecv.h" 12 | #include "IRsend.h" 13 | 14 | #define OUTPUT_BUF 1000U 15 | #define RAW_BUF 1000U 16 | class IRsendTest: public IRsend { 17 | public: 18 | uint32_t output[OUTPUT_BUF]; 19 | uint16_t last; 20 | uint16_t rawbuf[RAW_BUF]; 21 | decode_results capture; 22 | 23 | explicit IRsendTest(uint16_t x, bool i = false) : IRsend(x, i) { 24 | reset(); 25 | } 26 | 27 | void reset() { 28 | last = 0; 29 | output[last] = 0; 30 | } 31 | 32 | std::string outputStr() { 33 | std::stringstream result; 34 | if (last == 0 && output[0] == 0) 35 | return ""; 36 | for (uint16_t i = 0; i <= last; i++) { 37 | if ((i & 1) != outputOff ) // Odd XOR outputOff 38 | result << "s"; 39 | else 40 | result << "m"; 41 | result << output[i]; 42 | } 43 | reset(); 44 | return result.str(); 45 | } 46 | 47 | void makeDecodeResult(uint16_t offset = 0) { 48 | capture.decode_type = UNKNOWN; 49 | capture.bits = 0; 50 | capture.rawlen = last + 1 - offset; 51 | capture.overflow = (last - offset >= (int16_t) RAW_BUF); 52 | capture.repeat = false; 53 | capture.address = 0; 54 | capture.command = 0; 55 | capture.value = 0; 56 | capture.rawbuf = rawbuf; 57 | for (uint16_t i = 0; 58 | (i < RAW_BUF - 1) && (offset < OUTPUT_BUF); 59 | i++, offset++) 60 | if (output[offset] > UINT16_MAX) 61 | rawbuf[i + 1] = UINT16_MAX / USECPERTICK; 62 | else 63 | rawbuf[i + 1] = output[offset] / USECPERTICK; 64 | } 65 | 66 | void dumpRawResult() { 67 | std::cout << "uint16_t rawbuf["<< capture.rawlen << "] =\n"; 68 | for (uint16_t i = 0; i < capture.rawlen; i++) { 69 | std::cout << capture.rawbuf[i]; 70 | std::cout << "("; 71 | std::cout << capture.rawbuf[i] * USECPERTICK; 72 | std::cout << "), "; 73 | if (i % 8 == 7) 74 | std::cout << "\n"; 75 | } 76 | std::cout << "\n"; 77 | } 78 | 79 | void addGap(uint32_t usecs) { 80 | space(usecs); 81 | } 82 | 83 | protected: 84 | uint16_t mark(uint16_t usec) { 85 | if (last >= OUTPUT_BUF) 86 | return 0; 87 | if (last & 1) // Is odd? (i.e. last call was a space()) 88 | output[++last] = usec; 89 | else 90 | output[last] += usec; 91 | return 0; 92 | } 93 | 94 | void space(uint32_t time) { 95 | if (last >= OUTPUT_BUF) 96 | return; 97 | if (last & 1) { // Is odd? (i.e. last call was a space()) 98 | output[last] += time; 99 | } else { 100 | output[++last] = time; 101 | } 102 | } 103 | }; 104 | #endif // TEST_IRSEND_TEST_H_ 105 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ######################################### 2 | # Syntax Coloring Map For IRremoteESP8266 3 | ######################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | decode_results KEYWORD1 10 | IRrecv KEYWORD1 11 | IRsend KEYWORD1 12 | IRtimer KEYWORD1 13 | 14 | ####################################### 15 | # Methods and Functions (KEYWORD2) 16 | ####################################### 17 | 18 | decode KEYWORD2 19 | enableIRIn KEYWORD2 20 | disableIRIn KEYWORD2 21 | resume KEYWORD2 22 | begin KEYWORD2 23 | send KEYWORD2 24 | enableIROut KEYWORD2 25 | sendNEC KEYWORD2 26 | encodeNEC KEYWORD2 27 | sendLG KEYWORD2 28 | encodeLG KEYWORD2 29 | sendSony KEYWORD2 30 | encodeSony KEYWORD2 31 | sendSanyo KEYWORD2 32 | sendSanyoLC7461 KEYWORD2 33 | encodeSanyoLC7461 KEYWORD2 34 | sendMitsubishi KEYWORD2 35 | sendRaw KEYWORD2 36 | sendGC KEYWORD2 37 | sendRC5 KEYWORD2 38 | sendRC6 KEYWORD2 39 | sendRCMM KEYWORD2 40 | sendDISH KEYWORD2 41 | sendSharp KEYWORD2 42 | sendSharpRaw KEYWORD2 43 | encodeSharp KEYWORD2 44 | sendPanasonic KEYWORD2 45 | sendPanasonic64 KEYWORD2 46 | encodePanasonic KEYWORD2 47 | sendJVC KEYWORD2 48 | encodeJVC KEYWORD2 49 | sendWhynter KEYWORD2 50 | sendSAMSUNG KEYWORD2 51 | encodeSAMSUNG KEYWORD2 52 | sendDaikin KEYWORD2 53 | sendCOOLIX KEYWORD2 54 | sendDenon KEYWORD2 55 | sendKelvinator KEYWORD2 56 | sendSherwood KEYWORD2 57 | sendMitsubishiAC KEYWORD2 58 | mark KEYWORD2 59 | space KEYWORD2 60 | reset KEYWORD2 61 | elapsed KEYWORD2 62 | calcLGChecksum KEYWORD2 63 | reverseBits KEYWORD2 64 | 65 | ####################################### 66 | # Constants (LITERAL1) 67 | ####################################### 68 | 69 | NEC LITERAL1 70 | SONY LITERAL1 71 | SANYO LITERAL1 72 | MITSUBISHI LITERAL1 73 | RC5 LITERAL1 74 | RC5X LITERAL1 75 | RC6 LITERAL1 76 | DISH LITERAL1 77 | SHARP LITERAL1 78 | PANASONIC LITERAL1 79 | JVC LITERAL1 80 | LG LITERAL1 81 | SAMSUNG LITERAL1 82 | WHYNTER LITERAL1 83 | AIWA_RC_T501 LITERAL1 84 | COOLIX LITERAL1 85 | UNKNOWN LITERAL1 86 | REPEAT LITERAL1 87 | DENON LITERAL1 88 | DAIKIN LITERAL1 89 | KELVINATOR LITERAL1 90 | SHERWOOD LITERAL1 91 | MITSUBISHIAC LITERAL1 92 | RCMM LITERAL1 93 | SANYO_LC7461 LITERAL1 94 | NEC_BITS LITERAL1 95 | SHERWOOD_BITS LITERAL1 96 | SONY_MIN_BITS LITERAL1 97 | SONY_12_BITS LITERAL1 98 | SONY_15_BITS LITERAL1 99 | SONY_20_BITS LITERAL1 100 | SANYO_SA8650B_BITS LITERAL1 101 | MITSUBISHI_BITS LITERAL1 102 | PANASONIC_BITS LITERAL1 103 | JVC_BITS LITERAL1 104 | LG_BITS LITERAL1 105 | SAMSUNG_BITS LITERAL1 106 | COOLIX_BITS LITERAL1 107 | DAIKIN_BITS LITERAL1 108 | RC5X_BITS LITERAL1 109 | RC6_36_BITS LITERAL1 110 | RC6_MODE0_BITS LITERAL1 111 | RCMM_BITS LITERAL1 112 | WHYNTER_BITS LITERAL1 113 | SANYO_LC7461_BITS LITERAL1 114 | SHARP_BITS LITERAL1 115 | DISH_BITS LITERAL1 116 | DENON_BITS LITERAL1 117 | SONY_MIN_REPEAT LITERAL1 118 | MITSUBISHI_MIN_REPEAT LITERAL1 119 | DISH_MIN_REPEAT LITERAL1 120 | SHERWOOD_MIN_REPEAT LITERAL1 121 | -------------------------------------------------------------------------------- /src/ir_GlobalCache.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Hisham Khalifa 2 | // Copyright 2017 David Conran 3 | 4 | #include 5 | #include "IRsend.h" 6 | #include "IRtimer.h" 7 | 8 | // GGG L OOOO BBBB AA L CCCC AA CCCC H H EEEEEE 9 | // G G L O O B B AAAA L C C AAAA C C H H E 10 | // G L O O BBBBB A A L C A A C HHHHHH EEEE 11 | // G GG L O O B BB AAAAAA L C C AAAAAA C C H H E 12 | // GGGGG LLLLLL OOOO BBBBB A A LLLLLL CCCC A A CCCC H H EEEEEE 13 | 14 | // Global Cache IR format sender originally added by Hisham Khalifa 15 | // (http://www.hishamkhalifa.com) 16 | 17 | // Constants 18 | #define GLOBALCACHE_MAX_REPEAT 50U 19 | #define GLOBALCACHE_MIN_USEC 80U 20 | #define GLOBALCACHE_FREQ_INDEX 0U 21 | #define GLOBALCACHE_RPT_INDEX GLOBALCACHE_FREQ_INDEX + 1U 22 | #define GLOBALCACHE_RPT_START_INDEX GLOBALCACHE_RPT_INDEX + 1U 23 | #define GLOBALCACHE_START_INDEX GLOBALCACHE_RPT_START_INDEX + 1U 24 | 25 | #if SEND_GLOBALCACHE 26 | // Send a shortened GlobalCache (GC) IRdb/control tower formatted message. 27 | // 28 | // Args: 29 | // buf: An array of uint16_t containing the shortened GlobalCache data. 30 | // len: Nr. of entries in the buf[] array. 31 | // 32 | // Status: STABLE / Known working. 33 | // 34 | // Note: 35 | // Global Cache format without the emitter ID or request ID. 36 | // Starts at the frequency (Hertz), followed by nr. of times to emit (count), 37 | // then the offset for repeats (where a repeat will start from), 38 | // then the rest of entries are the actual IR message as units of periodic 39 | // time. 40 | // e.g. sendir,1:1,1,38000,1,1,9,70,9,30,9,... -> 38000,1,1,9,70,9,30,9,... 41 | // Ref: 42 | // https://irdb.globalcache.com/Home/Database 43 | void IRsend::sendGC(uint16_t buf[], uint16_t len) { 44 | uint16_t hz = buf[GLOBALCACHE_FREQ_INDEX]; // GC frequency is in Hz. 45 | enableIROut(hz); 46 | uint32_t periodic_time = calcUSecPeriod(hz); 47 | uint8_t emits = std::min(buf[GLOBALCACHE_RPT_INDEX], 48 | (uint16_t) GLOBALCACHE_MAX_REPEAT); 49 | // Repeat 50 | for (uint8_t repeat = 0; repeat < emits; repeat++) { 51 | // First time through, start at the beginning (GLOBALCACHE_START_INDEX), 52 | // otherwise for repeats, we start a specified offset from that. 53 | uint16_t offset = GLOBALCACHE_START_INDEX; 54 | if (repeat) 55 | offset += buf[GLOBALCACHE_RPT_START_INDEX] - 1; 56 | // Data 57 | for (; offset < len; offset++) { 58 | // Convert periodic units to microseconds. 59 | // Minimum is GLOBALCACHE_MIN_USEC for actual GC units. 60 | uint32_t microseconds = std::max(buf[offset] * periodic_time, 61 | GLOBALCACHE_MIN_USEC); 62 | // These codes start at an odd index (not even as with sendRaw). 63 | if (offset & 1) // Odd bit. 64 | mark(microseconds); 65 | else // Even bit. 66 | space(microseconds); 67 | } 68 | } 69 | // It's possible that we've ended on a mark(), thus ensure the LED is off. 70 | ledOff(); 71 | } 72 | #endif 73 | -------------------------------------------------------------------------------- /examples/IRrecvDump/IRrecvDump.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRrecvDump - dump details of IR codes with IRrecv 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * Version 0.1 Sept, 2015 5 | * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, 6 | * Copyright 2009 Ken Shirriff, http://arcfn.com 7 | * JVC and Panasonic protocol added by Kristian Lauszus 8 | * (Thanks to zenwheel and other people at the original blog post) 9 | * LG added by Darryl Smith (based on the JVC protocol) 10 | */ 11 | 12 | #include 13 | 14 | // an IR detector/demodulator is connected to GPIO pin 2 15 | uint16_t RECV_PIN = 2; 16 | 17 | IRrecv irrecv(RECV_PIN); 18 | 19 | decode_results results; 20 | 21 | void setup() { 22 | Serial.begin(115200); 23 | irrecv.enableIRIn(); // Start the receiver 24 | } 25 | 26 | void serialPrintUint64Hex(uint64_t value) { 27 | // Serial.print() can't handle printing long longs. (uint64_t) 28 | // So we have to print the top and bottom halves separately. 29 | if (value >> 32) 30 | Serial.print((uint32_t) (value >> 32), HEX); 31 | Serial.print((uint32_t) (value & 0xFFFFFFFF), HEX); 32 | } 33 | 34 | void dump(decode_results *results) { 35 | // Dumps out the decode_results structure. 36 | // Call this after IRrecv::decode() 37 | uint16_t count = results->rawlen; 38 | if (results->decode_type == UNKNOWN) { 39 | Serial.print("Unknown encoding: "); 40 | } else if (results->decode_type == NEC) { 41 | Serial.print("Decoded NEC: "); 42 | } else if (results->decode_type == SONY) { 43 | Serial.print("Decoded SONY: "); 44 | } else if (results->decode_type == RC5) { 45 | Serial.print("Decoded RC5: "); 46 | } else if (results->decode_type == RC5X) { 47 | Serial.print("Decoded RC5X: "); 48 | } else if (results->decode_type == RC6) { 49 | Serial.print("Decoded RC6: "); 50 | } else if (results->decode_type == PANASONIC) { 51 | Serial.print("Decoded PANASONIC - Address: "); 52 | Serial.print(results->address, HEX); 53 | Serial.print(" Value: "); 54 | } else if (results->decode_type == LG) { 55 | Serial.print("Decoded LG: "); 56 | } else if (results->decode_type == JVC) { 57 | Serial.print("Decoded JVC: "); 58 | } else if (results->decode_type == AIWA_RC_T501) { 59 | Serial.print("Decoded AIWA RC T501: "); 60 | } else if (results->decode_type == WHYNTER) { 61 | Serial.print("Decoded Whynter: "); 62 | } 63 | serialPrintUint64Hex(results->value); 64 | Serial.print(" ("); 65 | Serial.print(results->bits, DEC); 66 | Serial.println(" bits)"); 67 | Serial.print("Raw ("); 68 | Serial.print(count, DEC); 69 | Serial.print("): "); 70 | 71 | for (uint16_t i = 1; i < count; i++) { 72 | if (i % 100 == 0) 73 | yield(); // Preemptive yield every 100th entry to feed the WDT. 74 | if (i & 1) { 75 | Serial.print(results->rawbuf[i] * USECPERTICK, DEC); 76 | } else { 77 | Serial.write('-'); 78 | Serial.print((uint32_t) results->rawbuf[i] * USECPERTICK, DEC); 79 | } 80 | Serial.print(" "); 81 | } 82 | Serial.println(); 83 | } 84 | 85 | void loop() { 86 | if (irrecv.decode(&results)) { 87 | serialPrintUint64Hex(results.value); 88 | dump(&results); 89 | irrecv.resume(); // Receive the next value 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/ir_Daikin.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 sillyfrog */ 2 | #ifndef IR_DAIKIN_H_ 3 | #define IR_DAIKIN_H_ 4 | 5 | #include "IRremoteESP8266.h" 6 | #include "IRsend.h" 7 | 8 | // DDDDD AAA IIIII KK KK IIIII NN NN 9 | // DD DD AAAAA III KK KK III NNN NN 10 | // DD DD AA AA III KKKK III NN N NN 11 | // DD DD AAAAAAA III KK KK III NN NNN 12 | // DDDDDD AA AA IIIII KK KK IIIII NN NN 13 | 14 | /* 15 | Daikin AC map 16 | byte 7= checksum of the first part (and last byte before a 29ms pause) 17 | byte 13=mode 18 | b7 = 0 19 | b6+b5+b4 = Mode 20 | Modes: b6+b5+b4 21 | 011 = Cool 22 | 100 = Heat (temp 23) 23 | 110 = FAN (temp not shown, but 25) 24 | 000 = Fully Automatic (temp 25) 25 | 010 = DRY (temp 0xc0 = 96 degrees c) 26 | b3 = 0 27 | b2 = OFF timer set 28 | b1 = ON timer set 29 | b0 = Air Conditioner ON 30 | byte 14=temp*2 (Temp should be between 18 - 32) 31 | byte 16=Fan 32 | FAN control 33 | b7+b6+b5+b4 = Fan speed 34 | Fan: b7+b6+b5+b4 35 | 0×30 = 1 bar 36 | 0×40 = 2 bar 37 | 0×50 = 3 bar 38 | 0×60 = 4 bar 39 | 0×70 = 5 bar 40 | 0xa0 = Auto 41 | 0xb0 = Not auto, moon + tree 42 | b3+b2+b1+b0 = Swing control up/down 43 | Swing control up/down: 44 | 0000 = Swing up/down off 45 | 1111 = Swing up/down on 46 | byte 17 47 | Swing control left/right: 48 | 0000 = Swing left/right off 49 | 1111 = Swing left/right on 50 | byte 21=Aux -> Powerful (bit 1), Silent (bit 5) 51 | byte 24=Aux2 -> Intelligent eye on (bit 7) 52 | byte 26= checksum of the second part 53 | */ 54 | 55 | // Constants 56 | #define DAIKIN_COOL 0b011 57 | #define DAIKIN_HEAT 0b100 58 | #define DAIKIN_FAN 0b110 59 | #define DAIKIN_AUTO 0b000 60 | #define DAIKIN_DRY 0b010 61 | #define DAIKIN_POWERFUL 0b00000010 62 | #define DAIKIN_SILENT 0b00100000 63 | #define DAIKIN_MIN_TEMP 18U // Celsius 64 | #define DAIKIN_MAX_TEMP 32U // Celsius 65 | #define DAIKIN_FAN_AUTO (uint8_t) 0U 66 | #define DAIKIN_FAN_MIN (uint8_t) 1U 67 | #define DAIKIN_FAN_MAX (uint8_t) 5U 68 | 69 | #if SEND_DAIKIN 70 | class IRDaikinESP { 71 | public: 72 | explicit IRDaikinESP(uint16_t pin); 73 | 74 | void send(); 75 | void begin(); 76 | void on(); 77 | void off(); 78 | void setPower(bool state); 79 | uint8_t getPower(); 80 | void setAux(uint8_t aux); 81 | uint8_t getAux(); 82 | void setTemp(uint8_t temp); 83 | uint8_t getTemp(); 84 | void setFan(uint8_t fan); 85 | uint8_t getFan(); 86 | uint8_t getMode(); 87 | void setMode(uint8_t mode); 88 | void setSwingVertical(bool state); 89 | bool getSwingVertical(); 90 | void setSwingHorizontal(bool state); 91 | bool getSwingHorizontal(); 92 | bool getQuiet(); 93 | void setQuiet(bool state); 94 | bool getPowerful(); 95 | void setPowerful(bool state); 96 | uint8_t* getRaw(); 97 | 98 | private: 99 | // # of bytes per command 100 | uint8_t daikin[DAIKIN_COMMAND_LENGTH]; 101 | void stateReset(); 102 | void checksum(); 103 | IRsend _irsend; 104 | }; 105 | #endif 106 | 107 | #endif // IR_DAIKIN_H_ 108 | -------------------------------------------------------------------------------- /test/ir_GlobalCache_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRsend.h" 4 | #include "IRsend_test.h" 5 | #include "gtest/gtest.h" 6 | 7 | // Tests for sendGlobalCache(). 8 | 9 | // Test sending a typical command wihtout a repeat. 10 | TEST(TestSendGlobalCache, NonRepeatingCode) { 11 | IRsendTest irsend(4); 12 | IRrecv irrecv(4); 13 | irsend.begin(); 14 | irsend.reset(); 15 | 16 | // Modified NEC TV "Power On" from Global Cache with no repeats 17 | uint16_t gc_test[71] = {38000, 1, 1, 342, 172, 21, 22, 21, 21, 21, 65, 21, 21, 18 | 21, 22, 21, 22, 21, 21, 21, 22, 21, 65, 21, 65, 21, 19 | 22, 21, 65, 21, 65, 21, 65, 21, 65, 21, 65, 21, 65, 20 | 21, 22, 21, 22, 21, 21, 21, 22, 21, 22, 21, 65, 21, 21 | 22, 21, 21, 21, 65, 21, 65, 21, 65, 21, 64, 22, 65, 22 | 21, 22, 21, 65, 21, 1519}; 23 | irsend.sendGC(gc_test, 71); 24 | irsend.makeDecodeResult(); 25 | EXPECT_EQ("m7866s3956m483s506m483s483m483s1495m483s483m483s506m483s506" 26 | "m483s483m483s506m483s1495m483s1495m483s506m483s1495m483s1495" 27 | "m483s1495m483s1495m483s1495m483s1495m483s506m483s506m483s483" 28 | "m483s506m483s506m483s1495m483s506m483s483m483s1495m483s1495" 29 | "m483s1495m483s1472m506s1495m483s506m483s1495m483s34937", 30 | irsend.outputStr()); 31 | EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); 32 | EXPECT_EQ(NEC, irsend.capture.decode_type); 33 | EXPECT_EQ(NEC_BITS, irsend.capture.bits); 34 | EXPECT_EQ(0x20DF827D, irsend.capture.value); 35 | EXPECT_EQ(0x4, irsend.capture.address); 36 | EXPECT_EQ(0x41, irsend.capture.command); 37 | } 38 | 39 | // Test sending typical command with repeats. 40 | TEST(TestSendGlobalCache, RepeatCode) { 41 | IRsendTest irsend(4); 42 | IRrecv irrecv(4); 43 | irsend.begin(); 44 | irsend.reset(); 45 | 46 | // Sherwood (NEC-like) "Power On" from Global Cache with 2 repeats 47 | uint16_t gc_test[75] = {38000, 2, 69, 341, 171, 21, 64, 21, 64, 21, 21, 21, 48 | 21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 64, 21, 21, 49 | 21, 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, 21, 50 | 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, 21, 21, 51 | 21, 21, 21, 21, 21, 64, 21, 64, 21, 64, 21, 21, 21, 52 | 64, 21, 64, 21, 64, 21, 1600, 341, 85, 21, 3647}; 53 | irsend.sendGC(gc_test, 75); 54 | irsend.makeDecodeResult(); 55 | EXPECT_EQ("m7843s3933m483s1472m483s1472m483s483m483s483m483s483m483s483" 56 | "m483s483m483s1472m483s1472m483s483m483s1472m483s483m483s483" 57 | "m483s483m483s1472m483s483m483s1472m483s483m483s483m483s483" 58 | "m483s1472m483s483m483s483m483s483m483s483m483s1472m483s1472" 59 | "m483s1472m483s483m483s1472m483s1472m483s1472m483s36800" 60 | "m7843s1955m483s83881" 61 | "m7843s1955m483s83881", irsend.outputStr()); 62 | EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); 63 | EXPECT_EQ(NEC, irsend.capture.decode_type); 64 | EXPECT_EQ(NEC_BITS, irsend.capture.bits); 65 | EXPECT_EQ(0xC1A28877, irsend.capture.value); 66 | EXPECT_EQ(0x4583, irsend.capture.address); 67 | EXPECT_EQ(0x11, irsend.capture.command); 68 | } 69 | -------------------------------------------------------------------------------- /src/ir_Gree.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Ville Skyttä (scop) 2 | // Copyright 2017 David Conran 3 | // 4 | // Gree protocol compatible heat pump carrying the "Ultimate" brand name. 5 | // 6 | 7 | #include "IRremoteESP8266.h" 8 | #include "IRsend.h" 9 | 10 | // GGGG RRRRRR EEEEEEE EEEEEEE 11 | // GG GG RR RR EE EE 12 | // GG RRRRRR EEEEE EEEEE 13 | // GG GG RR RR EE EE 14 | // GGGGGG RR RR EEEEEEE EEEEEEE 15 | 16 | // Constants 17 | // Ref: https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.h 18 | #define GREE_HDR_MARK 9000U 19 | #define GREE_HDR_SPACE 4000U 20 | #define GREE_BIT_MARK 620U 21 | #define GREE_ONE_SPACE 1600U 22 | #define GREE_ZERO_SPACE 540U 23 | #define GREE_MSG_SPACE 19000U 24 | 25 | #if SEND_GREE 26 | // Send a Gree Heat Pump message. 27 | // 28 | // Args: 29 | // data: An array of bytes containing the IR command. 30 | // nbytes: Nr. of bytes of data in the array. (>=GREE_STATE_LENGTH) 31 | // repeat: Nr. of times the message is to be repeated. (Default = 0). 32 | // 33 | // Status: ALPHA / Untested. 34 | // 35 | // Ref: 36 | // https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp 37 | void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) { 38 | if (nbytes < GREE_STATE_LENGTH) 39 | return; // Not enough bytes to send a proper message. 40 | 41 | // Set IR carrier frequency 42 | enableIROut(38); 43 | 44 | for (uint16_t r = 0; r <= repeat; r++) { 45 | // Header #1 46 | mark(GREE_HDR_MARK); 47 | space(GREE_HDR_SPACE); 48 | 49 | // Data #1 50 | uint16_t i; 51 | for (i = 0; i < 4 && i < nbytes; i++) 52 | sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE, 53 | data[i], 8, false); 54 | 55 | // Footer #1 (010) 56 | sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE, 57 | 0b010, 3); 58 | 59 | // Header #2 60 | mark(GREE_BIT_MARK); 61 | space(GREE_MSG_SPACE); 62 | 63 | // Data #2 64 | for (; i < nbytes; i++) 65 | sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE, 66 | data[i], 8, false); 67 | 68 | // Footer #2 69 | mark(GREE_BIT_MARK); 70 | space(GREE_MSG_SPACE); 71 | } 72 | } 73 | 74 | // Send a Gree Heat Pump message. 75 | // 76 | // Args: 77 | // data: The raw message to be sent. 78 | // nbits: Nr. of bits of data in the message. (Default is GREE_BITS) 79 | // repeat: Nr. of times the message is to be repeated. (Default = 0). 80 | // 81 | // Status: ALPHA / Untested. 82 | // 83 | // Ref: 84 | // https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp 85 | void IRsend::sendGree(uint64_t data, uint16_t nbits, uint16_t repeat) { 86 | if (nbits != GREE_BITS) 87 | return; // Wrong nr. of bits to send a proper message. 88 | // Set IR carrier frequency 89 | enableIROut(38); 90 | 91 | for (uint16_t r = 0; r <= repeat; r++) { 92 | // Header 93 | mark(GREE_HDR_MARK); 94 | space(GREE_HDR_SPACE); 95 | 96 | // Data 97 | for (int16_t i = 8; i <= nbits; i += 8) { 98 | sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE, 99 | (data >> (nbits - i)) & 0xFF, 8, false); 100 | if (i == nbits / 2) { 101 | // Send the mid-message Footer. 102 | sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE, 103 | 0b010, 3); 104 | mark(GREE_BIT_MARK); 105 | space(GREE_MSG_SPACE); 106 | } 107 | } 108 | // Footer 109 | mark(GREE_BIT_MARK); 110 | space(GREE_MSG_SPACE); 111 | } 112 | } 113 | #endif // SEND_GREE 114 | -------------------------------------------------------------------------------- /src/ir_Whynter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2009 Ken Shirriff 2 | // Copyright 2017 David Conran 3 | 4 | #include 5 | #include "IRrecv.h" 6 | #include "IRsend.h" 7 | #include "IRtimer.h" 8 | 9 | // W W H H Y Y N N TTTTT EEEEE RRRRR 10 | // W W H H Y Y NN N T E R R 11 | // W W W HHHHH Y N N N T EEE RRRR 12 | // W W W H H Y N NN T E R R 13 | // WWW H H Y N N T EEEEE R R 14 | 15 | // Whynter A/C ARC-110WD added by Francesco Meschia 16 | // Whynter originally added from https://github.com/shirriff/Arduino-IRremote/ 17 | 18 | // Constants 19 | #define WHYNTER_HDR_MARK 2850U 20 | #define WHYNTER_HDR_SPACE 2850U 21 | #define WHYNTER_BIT_MARK 750U 22 | #define WHYNTER_ONE_SPACE 2150U 23 | #define WHYNTER_ZERO_SPACE 750U 24 | #define WHYNTER_MIN_COMMAND_LENGTH 108000UL // Completely made up value. 25 | #define WHYNTER_MIN_GAP WHYNTER_MIN_COMMAND_LENGTH - \ 26 | (2 * (WHYNTER_BIT_MARK + WHYNTER_ZERO_SPACE) + \ 27 | WHYNTER_BITS * (WHYNTER_BIT_MARK + WHYNTER_ONE_SPACE)) 28 | 29 | #if SEND_WHYNTER 30 | // Send a Whynter message. 31 | // 32 | // Args: 33 | // data: message to be sent. 34 | // nbits: Nr. of bits of the message to be sent. 35 | // repeat: Nr. of additional times the message is to be sent. 36 | // 37 | // Status: STABLE 38 | // 39 | // Ref: 40 | // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Whynter.cpp 41 | void IRsend::sendWhynter(uint64_t data, uint16_t nbits, uint16_t repeat) { 42 | // Set IR carrier frequency 43 | enableIROut(38); 44 | IRtimer usecTimer = IRtimer(); 45 | 46 | for (uint16_t i = 0; i <= repeat; i++) { 47 | usecTimer.reset(); 48 | // Header 49 | mark(WHYNTER_BIT_MARK); 50 | space(WHYNTER_ZERO_SPACE); 51 | mark(WHYNTER_HDR_MARK); 52 | space(WHYNTER_HDR_SPACE); 53 | // Data 54 | sendData(WHYNTER_BIT_MARK, WHYNTER_ONE_SPACE, WHYNTER_BIT_MARK, 55 | WHYNTER_ZERO_SPACE, data, nbits, true); 56 | // Footer 57 | mark(WHYNTER_BIT_MARK); 58 | space(std::max(WHYNTER_MIN_COMMAND_LENGTH - usecTimer.elapsed(), 59 | WHYNTER_MIN_GAP)); 60 | } 61 | } 62 | #endif 63 | 64 | #if DECODE_WHYNTER 65 | // Decode the supplied Whynter message. 66 | // 67 | // Args: 68 | // results: Ptr to the data to decode and where to store the decode result. 69 | // nbits: Nr. of data bits to expect. 70 | // strict: Flag indicating if we should perform strict matching. 71 | // Returns: 72 | // boolean: True if it can decode it, false if it can't. 73 | // 74 | // Status: BETA Strict mode is ALPHA. 75 | // 76 | // Ref: 77 | // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Whynter.cpp 78 | bool IRrecv::decodeWhynter(decode_results *results, uint16_t nbits, 79 | bool strict) { 80 | if (results->rawlen < 2 * nbits + 2 * HEADER + FOOTER - 1) 81 | return false; // We don't have enough entries to possibly match. 82 | 83 | // Compliance 84 | if (strict && nbits != WHYNTER_BITS) 85 | return false; // Incorrect nr. of bits per spec. 86 | 87 | uint16_t offset = OFFSET_START; 88 | 89 | // Header 90 | // Sequence begins with a bit mark and a zero space 91 | if (!matchMark(results->rawbuf[offset++], WHYNTER_BIT_MARK)) 92 | return false; 93 | if (!matchSpace(results->rawbuf[offset++], WHYNTER_ZERO_SPACE)) 94 | return false; 95 | // header mark and space 96 | if (!matchMark(results->rawbuf[offset++], WHYNTER_HDR_MARK)) 97 | return false; 98 | if (!matchSpace(results->rawbuf[offset++], WHYNTER_HDR_SPACE)) 99 | return false; 100 | 101 | // Data 102 | uint64_t data = 0; 103 | for (uint16_t i = 0; i < nbits; i++, offset++) { 104 | if (!matchMark(results->rawbuf[offset++], WHYNTER_BIT_MARK)) 105 | return false; 106 | if (matchSpace(results->rawbuf[offset], WHYNTER_ONE_SPACE)) 107 | data = (data << 1) | 1; // 1 108 | else if (matchSpace(results->rawbuf[offset], WHYNTER_ZERO_SPACE)) 109 | data <<= 1; // 0 110 | else 111 | return false; 112 | } 113 | 114 | // Footer 115 | if (!matchMark(results->rawbuf[offset++], WHYNTER_BIT_MARK)) 116 | return false; 117 | if (offset <= results->rawlen && 118 | !matchAtLeast(results->rawbuf[offset], WHYNTER_MIN_GAP)) 119 | return false; 120 | 121 | // Success 122 | results->decode_type = WHYNTER; 123 | results->bits = nbits; 124 | results->value = data; 125 | results->address = 0; 126 | results->command = 0; 127 | return true; 128 | } 129 | #endif 130 | -------------------------------------------------------------------------------- /examples/IRGCTCPServer/IRGCTCPServer.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRGCTCPServer - send Global Cache-formatted codes via TCP. 3 | * An IR emitter must be connected to GPIO pin 4. 4 | * Version 0.2 May, 2017 5 | * Copyright 2016 Hisham Khalifa, http://www.hishamkhalifa.com 6 | * Copyright 2017 David Conran 7 | * 8 | * Example command - Samsung TV power toggle: 38000,1,1,170,170,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,20,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,63,20,63,20,63,20,63,20,63,20,63,20,1798\r\n 9 | * For more codes, visit: https://irdb.globalcache.com/ 10 | * 11 | * How to use this program: 12 | * 1) Update "ssid" and "password" below for your WIFI network. 13 | * 2) Compile and upload the sketch to your ESP8266 module. 14 | * 3) (Optional) Use the serial connection to confirm it started and get the 15 | * IP address. 16 | * 4) From a client machine, connect to port 4998 on the ESP8266, using 17 | * 'telnet', 'nc' (netcat), 'putty' or similar command, etc. 18 | * You may need to install one. 19 | * Unix/OSX: 20 | * Start a shell. Then type: 21 | * telnet 4998 22 | * Windows: 23 | * Start a new CMD window, then type: 24 | * telnet 4998 25 | * 26 | * 5) Enter a Global Cache-formatted code, starting at the frequency, 27 | * and then a return/enter at the end. No spaces. e.g.: 28 | * 29 | * 38000,1,1,170,170,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,20,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,63,20,63,20,63,20,63,20,63,20,63,20,1798 30 | * 31 | * To exit the 'telnet' command: 32 | * press + <]> at the same time, then press 'q', and then . 33 | * or: 34 | * + might work. 35 | * 36 | * This program will display the ESP's IP address on the serial console, or you 37 | * can check your wifi router for it's address. 38 | */ 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | const char* ssid = "..."; // Put your WIFI SSID here. 46 | const char* password = "..."; // Put your WIFI password here. 47 | 48 | WiFiServer server(4998); // Uses port 4998. 49 | WiFiClient client; 50 | 51 | uint16_t *code_array; 52 | IRsend irsend(4); // an IR emitter led is connected to GPIO pin 4 53 | 54 | void sendGCString(String str) { 55 | int16_t index; 56 | uint16_t count; 57 | 58 | // Find out how many items there are in the string. 59 | index = -1; 60 | count = 1; 61 | do { 62 | index = str.indexOf(',', index + 1); 63 | count++; 64 | } while (index != -1); 65 | 66 | // Now we know how many there are, allocate the memory to store them all. 67 | code_array = reinterpret_cast(malloc(count * sizeof(uint16_t))); 68 | // Check we malloc'ed successfully. 69 | if (code_array == NULL) { // malloc failed, so give up. 70 | Serial.printf("\nCan't allocate %d bytes. (%d bytes free)\n", 71 | count * sizeof(uint16_t), ESP.getFreeHeap()); 72 | Serial.println("Giving up & forcing a reboot."); 73 | ESP.restart(); // Reboot. 74 | delay(500); // Wait for the restart to happen. 75 | return; // Should never get here, but just in case. 76 | } 77 | 78 | // Now convert the strings to integers and place them in code_array. 79 | count = 0; 80 | uint16_t start_from = 0; 81 | do { 82 | index = str.indexOf(',', start_from); 83 | code_array[count] = str.substring(start_from, index).toInt(); 84 | start_from = index + 1; 85 | count++; 86 | } while (index != -1); 87 | 88 | irsend.sendGC(code_array, count); // All done. Send it. 89 | free(code_array); // Free up the memory allocated. 90 | } 91 | 92 | void setup() { 93 | // initialize serial: 94 | Serial.begin(115200); 95 | delay(100); 96 | Serial.println(" "); 97 | Serial.println("IR TCP Server"); 98 | 99 | while (WiFi.status() != WL_CONNECTED) { 100 | delay(900); 101 | Serial.print("."); 102 | } 103 | 104 | server.begin(); 105 | IPAddress myAddress = WiFi.localIP(); 106 | Serial.println(myAddress); 107 | irsend.begin(); 108 | } 109 | 110 | void loop() { 111 | while (!client) 112 | client = server.available(); 113 | 114 | while (!client.connected()) { 115 | delay(900); 116 | client = server.available(); 117 | } 118 | 119 | if (client.available()) { 120 | String ir_code_str = client.readStringUntil('\r'); // Exclusive of \r 121 | client.readStringUntil('\n'); // Skip new line as well 122 | client.flush(); 123 | sendGCString(ir_code_str); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/ir_Aiwa.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRrecv.h" 4 | #include "IRsend.h" 5 | #include "IRtimer.h" 6 | 7 | // AAA IIIII W W AAA 8 | // A A I W W A A 9 | // AAAAA I W W W AAAAA 10 | // A A I W W W A A 11 | // A A IIIII WWW A A 12 | 13 | // Based off the RC-T501 RCU 14 | // Added by David Conran. (Inspired by IRremoteESP8266's implementation: 15 | // https://github.com/z3t0/Arduino-IRremote) 16 | 17 | #define AIWA_RC_T501_PRE_BITS 26U 18 | #define AIWA_RC_T501_POST_BITS 1U 19 | // NOTE: These are the compliment (inverted) of lirc values as 20 | // lirc uses a '0' for a mark, and a '1' for a space. 21 | #define AIWA_RC_T501_PRE_DATA 0x1D8113FULL // 26-bits 22 | #define AIWA_RC_T501_POST_DATA 1ULL 23 | 24 | #if SEND_AIWA_RC_T501 25 | // Send a Aiwa RC T501 formatted message. 26 | // 27 | // Args: 28 | // data: The message to be sent. 29 | // nbits: The number of bits of the message to be sent. 30 | // Typically AIWA_RC_T501_BITS. Max is 37 = (64 - 27) 31 | // repeat: The number of times the command is to be repeated. 32 | // 33 | // Status: BETA / Should work. 34 | // 35 | // Ref: 36 | // http://lirc.sourceforge.net/remotes/aiwa/RC-T501 37 | void IRsend::sendAiwaRCT501(uint64_t data, uint16_t nbits, uint16_t repeat) { 38 | // Appears to be an extended NEC1 protocol. i.e. 42 bits instead of 32 bits. 39 | // So use sendNEC instead, however the twist is it has a fixed 26 bit 40 | // prefix, and a fixed postfix bit. 41 | uint64_t new_data = ( 42 | (AIWA_RC_T501_PRE_DATA << (nbits + AIWA_RC_T501_POST_BITS)) | 43 | (data << AIWA_RC_T501_POST_BITS) | AIWA_RC_T501_POST_DATA); 44 | nbits += AIWA_RC_T501_PRE_BITS + AIWA_RC_T501_POST_BITS; 45 | if (nbits > sizeof(new_data) * 8) 46 | return; // We are overflowing. Abort, and don't send. 47 | sendNEC(new_data, nbits, repeat); 48 | } 49 | #endif 50 | 51 | #if DECODE_AIWA_RC_T501 52 | // Decode the supplied Aiwa RC T501 message. 53 | // 54 | // Args: 55 | // results: Ptr to the data to decode and where to store the decode result. 56 | // nbits: The number of data bits to expect. Typically AIWA_RC_T501_BITS. 57 | // strict: Flag indicating if we should perform strict matching. 58 | // Returns: 59 | // boolean: True if it can decode it, false if it can't. 60 | // 61 | // Status: BETA / Should work. 62 | // 63 | // Notes: 64 | // Aiwa RC T501 appears to be a 42 bit variant of the NEC1 protocol. 65 | // However, we historically (original Arduino IRremote project) treats it as 66 | // a 15 bit (data) protocol. So, we expect nbits to typically be 15, and we 67 | // will remove the prefix and postfix from the raw data, and use that as 68 | // the result. 69 | // 70 | // Ref: 71 | // http://www.sbprojects.com/knowledge/ir/nec.php 72 | bool IRrecv::decodeAiwaRCT501(decode_results *results, uint16_t nbits, 73 | bool strict) { 74 | // Compliance 75 | if (strict && nbits != AIWA_RC_T501_BITS) 76 | return false; // Doesn't match our protocol defn. 77 | 78 | // Add on the pre & post bits to our requested bit length. 79 | uint16_t expected_nbits = nbits + AIWA_RC_T501_PRE_BITS + 80 | AIWA_RC_T501_POST_BITS; 81 | uint64_t new_data; 82 | if (expected_nbits > sizeof(new_data) * 8) 83 | return false; // We can't possibly match something that big. 84 | // Decode it as a much bigger (non-standard) NEC message, so we have to turn 85 | // off strict mode checking for NEC. 86 | if (!decodeNEC(results, expected_nbits, false)) 87 | return false; // The NEC decode had a problem, so we should too. 88 | uint16_t actual_bits = results->bits; 89 | new_data = results->value; 90 | if (actual_bits < expected_nbits) 91 | return false; // The data we caught was undersized. Throw it back. 92 | if ((new_data & 0x1ULL) != AIWA_RC_T501_POST_DATA) 93 | return false; // The post data doesn't match, so it can't be this protocol. 94 | // Trim off the post data bit. 95 | new_data >>= AIWA_RC_T501_POST_BITS; 96 | actual_bits -= AIWA_RC_T501_POST_BITS; 97 | 98 | // Extract out our likely new value and put it back in the results. 99 | actual_bits -= AIWA_RC_T501_PRE_BITS; 100 | results->value = new_data & ((1ULL << actual_bits) - 1); 101 | 102 | // Check the prefix data matches. 103 | new_data >>= actual_bits; // Trim off the new data to expose the prefix. 104 | if (new_data != AIWA_RC_T501_PRE_DATA) // Check the prefix. 105 | return false; 106 | 107 | // Compliance 108 | if (strict && results->bits != expected_nbits) 109 | return false; 110 | 111 | // Success 112 | results->decode_type = AIWA_RC_T501; 113 | results->bits = actual_bits; 114 | results->address = 0; 115 | results->command = 0; 116 | return true; 117 | } 118 | #endif 119 | -------------------------------------------------------------------------------- /src/ir_Dish.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Todd Treece 2 | // Copyright 2017 David Conran 3 | 4 | #include "IRrecv.h" 5 | #include "IRsend.h" 6 | #include "IRtimer.h" 7 | 8 | // DDDD IIIII SSSS H H 9 | // D D I S H H 10 | // D D I SSS HHHHH 11 | // D D I S H H 12 | // DDDD IIIII SSSS H H 13 | 14 | // DISH support orginally by Todd Treece 15 | // http://unionbridge.org/design/ircommand 16 | 17 | // Constants 18 | // Ref: 19 | // https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Dish.cpp 20 | // http://www.hifi-remote.com/wiki/index.php?title=Dish 21 | #define DISH_HDR_MARK 400U 22 | #define DISH_HDR_SPACE 6100U 23 | #define DISH_BIT_MARK 400U 24 | #define DISH_ONE_SPACE 1700U 25 | #define DISH_ZERO_SPACE 2800U 26 | #define DISH_RPT_SPACE DISH_HDR_SPACE 27 | 28 | #if SEND_DISH 29 | // Send an IR command to a DISH NETWORK device. 30 | // 31 | // Args: 32 | // data: The contents of the command you want to send. 33 | // nbits: The bit size of the command being sent. 34 | // repeat: The number of times you want the command to be repeated. 35 | // 36 | // Status: BETA / Previously working. 37 | // 38 | // Note: 39 | // Dishplayer is a different protocol. 40 | // Typically a DISH device needs to get a command a total of at least 4 41 | // times to accept it. e.g. repeat=3 42 | // 43 | // Here is the LIRC file I found that seems to match the remote codes from the 44 | // oscilloscope: 45 | // DISH NETWORK (echostar 301): 46 | // http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx 47 | // 48 | // Ref: 49 | // http://www.hifi-remote.com/wiki/index.php?title=Dish 50 | void IRsend::sendDISH(uint64_t data, uint16_t nbits, uint16_t repeat) { 51 | // Set 57.6kHz IR carrier frequency, duty cycle is unknown. 52 | enableIROut(57600); 53 | // Header 54 | mark(DISH_HDR_MARK); 55 | space(DISH_HDR_SPACE); 56 | // We always send a command, even for repeat=0, hence '<= repeat'. 57 | for (uint16_t i = 0; i <= repeat; i++) { 58 | // Data 59 | sendData(DISH_BIT_MARK, DISH_ONE_SPACE, DISH_BIT_MARK, DISH_ZERO_SPACE, 60 | data, nbits, true); 61 | // Footer 62 | mark(DISH_BIT_MARK); 63 | space(DISH_RPT_SPACE); 64 | } 65 | } 66 | #endif 67 | 68 | #if DECODE_DISH 69 | // Decode the supplied DISH NETWORK message. 70 | // 71 | // Args: 72 | // results: Ptr to the data to decode and where to store the decode result. 73 | // nbits: Nr. of bits to expect in the data portion. Typically DISH_BITS. 74 | // strict: Flag to indicate if we strictly adhere to the specification. 75 | // Returns: 76 | // boolean: True if it can decode it, false if it can't. 77 | // 78 | // Status: ALPHA (untested and unconfirmed.) 79 | // 80 | // Note: 81 | // Dishplayer is a different protocol. 82 | // Typically a DISH device needs to get a command a total of at least 4 83 | // times to accept it. 84 | // Ref: 85 | // http://www.hifi-remote.com/wiki/index.php?title=Dish 86 | // http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx 87 | // https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Dish.cpp 88 | bool IRrecv::decodeDISH(decode_results *results, uint16_t nbits, bool strict) { 89 | if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) 90 | return false; // Not enough entries to be valid. 91 | if (strict && nbits != DISH_BITS) 92 | return false; // Not strictly compliant. 93 | 94 | uint64_t data = 0; 95 | uint16_t offset = OFFSET_START; 96 | 97 | // Header 98 | if (!match(results->rawbuf[offset++], DISH_HDR_MARK)) 99 | return false; 100 | if (!matchSpace(results->rawbuf[offset++], DISH_HDR_SPACE)) 101 | return false; 102 | 103 | // Data 104 | uint16_t actual_bits; 105 | for (actual_bits = 0; offset < results->rawlen; actual_bits++, offset++) { 106 | if (!match(results->rawbuf[offset++], DISH_BIT_MARK)) 107 | return false; 108 | if (matchSpace(results->rawbuf[offset], DISH_ONE_SPACE)) 109 | data = (data << 1) | 1; // 1 110 | else if (matchSpace(results->rawbuf[offset], DISH_ZERO_SPACE)) 111 | data = data << 1; // 0 112 | else 113 | break; 114 | } 115 | 116 | // Footer 117 | if (!match(results->rawbuf[offset - 1], DISH_BIT_MARK)) 118 | return false; 119 | 120 | // Compliance 121 | if (strict) { 122 | // The DISH protocol calls for a repeated message, so strictly speaking 123 | // there should be a code following this. Only require it if we are set to 124 | // strict matching. 125 | if (!matchSpace(results->rawbuf[offset], DISH_RPT_SPACE)) 126 | return false; 127 | if (actual_bits != nbits) 128 | return false; // We didn't get the same number of bits we asked for. 129 | } 130 | 131 | // Success 132 | results->decode_type = DISH; 133 | results->bits = actual_bits; 134 | results->value = data; 135 | results->address = 0; 136 | results->command = 0; 137 | return true; 138 | } 139 | #endif 140 | -------------------------------------------------------------------------------- /src/ir_Kelvinator.h: -------------------------------------------------------------------------------- 1 | // Kelvinator A/C 2 | // 3 | // Copyright 2016 David Conran 4 | 5 | #ifndef IR_KELVINATOR_H_ 6 | #define IR_KELVINATOR_H_ 7 | 8 | #define __STDC_LIMIT_MACROS 9 | #include 10 | #include "IRremoteESP8266.h" 11 | #include "IRsend.h" 12 | 13 | // KK KK EEEEEEE LL VV VV IIIII NN NN AAA TTTTTTT OOOOO RRRRRR 14 | // KK KK EE LL VV VV III NNN NN AAAAA TTT OO OO RR RR 15 | // KKKK EEEEE LL VV VV III NN N NN AA AA TTT OO OO RRRRRR 16 | // KK KK EE LL VV VV III NN NNN AAAAAAA TTT OO OO RR RR 17 | // KK KK EEEEEEE LLLLLLL VVV IIIII NN NN AA AA TTT OOOO0 RR RR 18 | 19 | // Constants 20 | #define KELVINATOR_AUTO 0U 21 | #define KELVINATOR_COOL 1U 22 | #define KELVINATOR_DRY 2U 23 | #define KELVINATOR_FAN 3U 24 | #define KELVINATOR_HEAT 4U 25 | #define KELVINATOR_BASIC_FAN_MAX 3U 26 | #define KELVINATOR_FAN_MAX 5U 27 | #define KELVINATOR_MIN_TEMP 16U // 16C 28 | #define KELVINATOR_MAX_TEMP 30U // 30C 29 | #define KELVINATOR_AUTO_TEMP 25U // 25C 30 | 31 | /* 32 | Kelvinator AC map 33 | 34 | (header mark and space) 35 | byte 0 = Basic Modes 36 | b2-0 = Modes 37 | Modes: 38 | 000 = Auto (temp = 25C) 39 | 001 = Cool 40 | 010 = Dry (temp = 25C, but not shown) 41 | 011 = Fan 42 | 100 = Heat 43 | b3 = Power Status (1 = On, 0 = Off) 44 | b5-4 = Fan (Basic modes) 45 | Fan: 46 | 00 = Auto 47 | 01 = Fan 1 48 | 10 = Fan 2 49 | 11 = Fan 3 or higher (See byte 14) 50 | b6 = Vent swing (1 = On, 0 = Off) (See byte 4) 51 | b7 = Sleep Modes 1 & 3 (1 = On, 0 = Off) 52 | byte 1 = Temperature 53 | b3-0: Degrees C. 54 | 0000 (0) = 16C 55 | 0001 (1) = 17C 56 | 0010 (2) = 18C 57 | ... 58 | 1101 (13) = 29C 59 | 1110 (14) = 30C 60 | byte 2 = Extras 61 | b3-0 = UNKNOWN, typically 0. 62 | b4 = Turbo Fan (1 = On, 0 = Off) 63 | b5 = Light (Display) (1 = On, 0 = Off) 64 | b6 = Ion Filter (1 = On, 0 = Off) 65 | b7 = X-Fan (Fan runs for a while after power off) (1 = On, 0 = Off) 66 | byte 3 = Section Indicator 67 | b3-0 = Unused (Typically 0) 68 | b5-4 = Unknown (possibly timer related) (Typically 0b01) 69 | b7-6 = End of command block (B01) 70 | (B010 marker and a gap of 20ms) 71 | byte 4 = Extended options 72 | b0 = Swing Vent Vertical (1 = On, 0 = Off) 73 | b4 = Swing Vent Horizontal (1 = On, 0 = Off) 74 | byte 5-6 = Timer related. Typically 0 except when timer in use. 75 | byte 7 = checksum 76 | b3-0 = Unknown (Used in Timer mode) 77 | b7-4 = checksum of the previous bytes (0-6) 78 | (gap of 40ms) 79 | (header mark and space) 80 | byte 8 = Repeat of byte 0 81 | byte 9 = Repeat of byte 1 82 | byte 10 = Repeat of byte 2 83 | byte 11 = Section Indicator 84 | b3-0 = Unused (Typically 0) 85 | b5-4 = Unknown (possibly timer related) (Typically 0b11) 86 | b7-6 = End of command block (B01) 87 | (B010 marker and a gap of 20ms) 88 | byte 12 = Extended options 89 | b0 = Sleep mode 2 (1 = On, 0=Off) 90 | b6-1 = Unknown (Used in Sleep Mode 3, Typically 0b000000) 91 | b7 = Quiet Mode (1 = On, 0=Off) 92 | byte 13 = Unknown (Sleep Mode 3 related, Typically 0x00) 93 | byte 14 = Fan control 94 | b3-0 = Unknown (Sleep Mode 3 related, Typically 0b0000) 95 | b6-4 = Fan speed 96 | 0b000 (0) = Automatic 97 | 0b001 (1) = Fan 1 98 | 0b010 (2) = Fan 2 99 | 0b011 (3) = Fan 3 100 | 0b100 (4) = Fan 4 101 | 0b101 (5) = Fan 5 102 | byte 15 = checksum 103 | b3-0 = Unknown (Typically 0b0000) 104 | b7-4 = checksum of the previous bytes (8-14) 105 | */ 106 | 107 | #if SEND_KELVINATOR 108 | 109 | // Classes 110 | class IRKelvinatorAC { 111 | public: 112 | explicit IRKelvinatorAC(uint16_t pin); 113 | 114 | void stateReset(); 115 | void send(); 116 | void begin(); 117 | void on(); 118 | void off(); 119 | void setPower(bool state); 120 | bool getPower(); 121 | void setTemp(uint8_t temp); 122 | uint8_t getTemp(); 123 | void setFan(uint8_t fan); 124 | uint8_t getFan(); 125 | void setMode(uint8_t mode); 126 | uint8_t getMode(); 127 | void setSwingVertical(bool state); 128 | bool getSwingVertical(); 129 | void setSwingHorizontal(bool state); 130 | bool getSwingHorizontal(); 131 | void setQuiet(bool state); 132 | bool getQuiet(); 133 | void setIonFilter(bool state); 134 | bool getIonFilter(); 135 | void setLight(bool state); 136 | bool getLight(); 137 | void setXFan(bool state); 138 | bool getXFan(); 139 | void setTurbo(bool state); 140 | bool getTurbo(); 141 | uint8_t* getRaw(); 142 | 143 | private: 144 | // The state of the IR remote in IR code form. 145 | uint8_t remote_state[KELVINATOR_STATE_LENGTH]; 146 | void checksum(); 147 | void fixup(); 148 | IRsend _irsend; 149 | }; 150 | #endif 151 | 152 | #endif // IR_KELVINATOR_H_ 153 | -------------------------------------------------------------------------------- /src/ir_JVC.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Kristian Lauszus 2 | // Copyright 2017 David Conran 3 | 4 | #include 5 | #include "IRrecv.h" 6 | #include "IRsend.h" 7 | #include "IRtimer.h" 8 | #include "IRutils.h" 9 | 10 | // JJJJJ V V CCCC 11 | // J V V C 12 | // J V V C 13 | // J J V V C 14 | // J V CCCC 15 | 16 | // JVC originally added by Kristian Lauszus 17 | // (Thanks to zenwheel and other people at the original blog post) 18 | 19 | // Constants 20 | // Ref: 21 | // http://www.sbprojects.com/knowledge/ir/jvc.php 22 | #define JVC_HDR_MARK 8400U 23 | #define JVC_HDR_SPACE 4200U 24 | #define JVC_BIT_MARK 525U 25 | #define JVC_ONE_SPACE 1725U 26 | #define JVC_ZERO_SPACE 525U 27 | #define JVC_RPT_LENGTH 60000U 28 | #define JVC_MIN_GAP 11400U // 60000 - 16 * (1725 + 525) - 8400 - 4200 29 | 30 | #if SEND_JVC 31 | // Send a JVC message. 32 | // 33 | // Args: 34 | // data: The contents of the command you want to send. 35 | // nbits: The bit size of the command being sent. (JVC_BITS) 36 | // repeat: The number of times you want the command to be repeated. 37 | // 38 | // Status: STABLE. 39 | // 40 | // Ref: 41 | // http://www.sbprojects.com/knowledge/ir/jvc.php 42 | void IRsend::sendJVC(uint64_t data, uint16_t nbits, uint16_t repeat) { 43 | // Set 38kHz IR carrier frequency & a 1/3 (33%) duty cycle. 44 | enableIROut(38, 33); 45 | 46 | IRtimer usecs = IRtimer(); 47 | // Header 48 | // Only sent for the first message. 49 | mark(JVC_HDR_MARK); 50 | space(JVC_HDR_SPACE); 51 | 52 | // We always send the data & footer at least once, hence '<= repeat'. 53 | for (uint16_t i = 0; i <= repeat; i++) { 54 | // Data 55 | sendData(JVC_BIT_MARK, JVC_ONE_SPACE, JVC_BIT_MARK, JVC_ZERO_SPACE, 56 | data, nbits, true); 57 | // Footer 58 | mark(JVC_BIT_MARK); 59 | // Wait till the end of the repeat time window before we send another code. 60 | space(std::max(JVC_MIN_GAP, JVC_RPT_LENGTH - usecs.elapsed())); 61 | usecs.reset(); 62 | } 63 | } 64 | 65 | // Calculate the raw JVC data based on address and command. 66 | // 67 | // Args: 68 | // address: An 8-bit address value. 69 | // command: An 8-bit command value. 70 | // Returns: 71 | // A raw JVC message. 72 | // 73 | // Status: BETA / Should work fine. 74 | // 75 | // Ref: 76 | // http://www.sbprojects.com/knowledge/ir/jvc.php 77 | uint16_t IRsend::encodeJVC(uint8_t address, uint8_t command) { 78 | return reverseBits((command << 8) | address, 16); 79 | } 80 | #endif 81 | 82 | #if DECODE_JVC 83 | // Decode the supplied JVC message. 84 | // 85 | // Args: 86 | // results: Ptr to the data to decode and where to store the decode result. 87 | // nbits: Nr. of bits of data to expect. Typically JVC_BITS. 88 | // strict: Flag indicating if we should perform strict matching. 89 | // Returns: 90 | // boolean: True if it can decode it, false if it can't. 91 | // 92 | // Status: STABLE 93 | // 94 | // Note: 95 | // JVC repeat codes don't have a header. 96 | // Ref: 97 | // http://www.sbprojects.com/knowledge/ir/jvc.php 98 | bool IRrecv::decodeJVC(decode_results *results, uint16_t nbits, bool strict) { 99 | if (strict && nbits != JVC_BITS) 100 | return false; // Must be called with the correct nr. of bits. 101 | if (results->rawlen < 2 * nbits + FOOTER - 1) 102 | return false; // Can't possibly be a valid JVC message. 103 | 104 | uint64_t data = 0; 105 | uint16_t offset = OFFSET_START; 106 | bool isRepeat = true; 107 | 108 | // Header 109 | // (Optional as repeat codes don't have the header) 110 | if (matchMark(results->rawbuf[offset], JVC_HDR_MARK)) { 111 | isRepeat = false; 112 | offset++; 113 | if (results->rawlen < 2 * nbits + 4) 114 | return false; // Can't possibly be a valid JVC message with a header. 115 | if (!matchSpace(results->rawbuf[offset++], JVC_HDR_SPACE)) 116 | return false; 117 | } 118 | 119 | // Data 120 | for (uint16_t i = 0; i < nbits; i++) { 121 | if (!matchMark(results->rawbuf[offset++], JVC_BIT_MARK)) 122 | return false; 123 | if (matchSpace(results->rawbuf[offset], JVC_ONE_SPACE)) 124 | data = (data << 1) | 1; // 1 125 | else if (matchSpace(results->rawbuf[offset], JVC_ZERO_SPACE)) 126 | data <<= 1; // 0 127 | else 128 | return false; 129 | offset++; 130 | } 131 | 132 | // Footer 133 | if (!matchMark(results->rawbuf[offset++], JVC_BIT_MARK)) 134 | return false; 135 | if (offset <= results->rawlen && 136 | !matchAtLeast(results->rawbuf[offset], JVC_MIN_GAP)) 137 | return false; 138 | 139 | // Success 140 | results->decode_type = JVC; 141 | results->bits = nbits; 142 | results->value = data; 143 | // command & address are transmitted LSB first, so we need to reverse them. 144 | results->address = reverseBits(data >> 8, 8); // The first 8 bits sent. 145 | results->command = reverseBits(data & 0xFF, 8); // The last 8 bits sent. 146 | results->repeat = isRepeat; 147 | return true; 148 | } 149 | #endif 150 | -------------------------------------------------------------------------------- /src/ir_Denon.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Massimiliano Pinto 2 | // Copyright 2017 David Conran 3 | 4 | #include 5 | #include "IRrecv.h" 6 | #include "IRsend.h" 7 | #include "IRtimer.h" 8 | 9 | // DDDD EEEEE N N OOO N N 10 | // D D E NN N O O NN N 11 | // D D EEE N N N O O N N N 12 | // D D E N NN O O N NN 13 | // DDDD EEEEE N N OOO N N 14 | 15 | // Original Denon support added by https://github.com/csBlueChip 16 | // Ported over by Massimiliano Pinto 17 | 18 | // Constants 19 | // Ref: 20 | // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp 21 | #define DENON_HDR_MARK 263U // The length of the Header:Mark 22 | #define DENON_HDR_SPACE 789U // The length of the Header:Space 23 | #define DENON_BIT_MARK 263U // The length of a Bit:Mark 24 | #define DENON_ONE_SPACE 1842U // The length of a Bit:Space for 1's 25 | #define DENON_ZERO_SPACE 789U // The length of a Bit:Space for 0's 26 | #define DENON_MIN_COMMAND_LENGTH 134052UL 27 | #define DENON_MIN_GAP DENON_MIN_COMMAND_LENGTH - \ 28 | (DENON_HDR_MARK + DENON_HDR_SPACE + DENON_BITS * \ 29 | (DENON_BIT_MARK + DENON_ONE_SPACE) + DENON_BIT_MARK) 30 | #define DENON_MANUFACTURER 0x2A4CULL 31 | 32 | #if SEND_DENON 33 | // Send a Denon message 34 | // 35 | // Args: 36 | // data: Contents of the message to be sent. 37 | // nbits: Nr. of bits of data to be sent. Typically DENON_BITS. 38 | // repeat: Nr. of additional times the message is to be sent. 39 | // 40 | // Status: BETA / Should be working. 41 | // 42 | // Notes: 43 | // Some Denon devices use a Kaseikyo/Panasonic 48-bit format 44 | // Others use the Sharp protocol. 45 | // Ref: 46 | // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp 47 | // http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls 48 | void IRsend::sendDenon(uint64_t data, uint16_t nbits, uint16_t repeat) { 49 | if (nbits >= PANASONIC_BITS) // Is this really Panasonic? 50 | sendPanasonic64(data, nbits, repeat); 51 | else if (nbits == DENON_LEGACY_BITS) 52 | // Support legacy (broken) calls of sendDenon(). 53 | sendSharpRaw(data & (~0x2000ULL), nbits + 1, repeat); 54 | else 55 | sendSharpRaw(data, nbits, repeat); 56 | } 57 | #endif 58 | 59 | #if DECODE_DENON 60 | // Decode a Denon message. 61 | // 62 | // Args: 63 | // results: Ptr to the data to decode and where to store the decode result. 64 | // nbits: Expected nr. of data bits. (Typically DENON_BITS) 65 | // Returns: 66 | // boolean: True if it can decode it, false if it can't. 67 | // 68 | // Status: BETA / Should work fine. 69 | // 70 | // Ref: 71 | // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp 72 | bool IRrecv::decodeDenon(decode_results *results, uint16_t nbits, bool strict) { 73 | // Compliance 74 | if (strict) { 75 | switch (nbits) { 76 | case DENON_BITS: 77 | case DENON_48_BITS: 78 | case DENON_LEGACY_BITS: 79 | break; 80 | default: 81 | return false; 82 | } 83 | } 84 | 85 | // Denon uses the Sharp & Panasonic(Kaseikyo) protocol for some 86 | // devices, so check for those first. 87 | // It is not exactly like Sharp's protocols, but close enough. 88 | // e.g. The expansion bit is not set for Denon vs. set for Sharp. 89 | // Ditto for Panasonic, it's the same except for a different 90 | // manufacturer code. 91 | 92 | if (!decodeSharp(results, nbits, true, false) && 93 | !decodePanasonic(results, nbits, true, DENON_MANUFACTURER)) { 94 | // We couldn't decode it as expected, so try the old legacy method. 95 | // NOTE: I don't this following protocol actually exists. 96 | // Looks like a partial version of the Sharp protocol. 97 | // Check we have enough data 98 | if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) 99 | return false; 100 | if (strict && nbits != DENON_LEGACY_BITS) 101 | return false; 102 | 103 | uint64_t data = 0; 104 | uint16_t offset = OFFSET_START; 105 | 106 | // Header 107 | if (!matchMark(results->rawbuf[offset++], DENON_HDR_MARK)) 108 | return false; 109 | if (!matchSpace(results->rawbuf[offset++], DENON_HDR_SPACE)) 110 | return false; 111 | // Data 112 | for (uint16_t i = 0; i < nbits; i++, offset++) { 113 | if (!matchMark(results->rawbuf[offset++], DENON_BIT_MARK)) 114 | return false; 115 | if (matchSpace(results->rawbuf[offset], DENON_ONE_SPACE)) 116 | data = (data << 1) | 1; // 1 117 | else if (matchSpace(results->rawbuf[offset], DENON_ZERO_SPACE)) 118 | data = (data << 1); // 0 119 | else 120 | return false; 121 | } 122 | 123 | // Footer 124 | if (!matchMark(results->rawbuf[offset++], DENON_BIT_MARK)) 125 | return false; 126 | 127 | // Success 128 | results->bits = nbits; 129 | results->value = data; 130 | results->address = 0; 131 | results->command = 0; 132 | } // Legacy decode. 133 | 134 | // Compliance 135 | if (strict && nbits != results->bits) return false; 136 | 137 | // Success 138 | results->decode_type = DENON; 139 | return true; 140 | } 141 | #endif 142 | -------------------------------------------------------------------------------- /src/ir_Coolix.cpp: -------------------------------------------------------------------------------- 1 | // Copyright bakrus 2 | // Copyright 2017 David Conran 3 | 4 | #include "IRrecv.h" 5 | #include "IRsend.h" 6 | #include "IRtimer.h" 7 | 8 | // CCCCC OOOOO OOOOO LL IIIII XX XX 9 | // CC C OO OO OO OO LL III XX XX 10 | // CC OO OO OO OO LL III XXXX 11 | // CC C OO OO OO OO LL III XX XX 12 | // CCCCC OOOO0 OOOO0 LLLLLLL IIIII XX XX 13 | 14 | // Coolix A/C / heatpump added by (send) bakrus & (decode) crankyoldgit 15 | 16 | // Constants 17 | // Pulse parms are *50-100 for the Mark and *50+100 for the space 18 | // First MARK is the one after the long gap 19 | // pulse parameters in usec 20 | #define COOLIX_BIT_MARK 560U // Approximately 21 cycles at 38kHz 21 | #define COOLIX_ONE_SPACE COOLIX_BIT_MARK * 3U 22 | #define COOLIX_ZERO_SPACE COOLIX_BIT_MARK * 1U 23 | #define COOLIX_HDR_MARK COOLIX_BIT_MARK * 8U 24 | #define COOLIX_HDR_SPACE COOLIX_BIT_MARK * 8U 25 | #define COOLIX_MIN_GAP COOLIX_HDR_SPACE + COOLIX_ZERO_SPACE 26 | 27 | #if SEND_COOLIX 28 | // Send a Coolix message 29 | // 30 | // Args: 31 | // data: Contents of the message to be sent. 32 | // nbits: Nr. of bits of data to be sent. Typically COOLIX_BITS. 33 | // repeat: Nr. of additional times the message is to be sent. 34 | // 35 | // Status: BETA / Probably works. 36 | // 37 | // Ref: 38 | // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_COOLIX.cpp 39 | // TODO(anyone): Verify repeat functionality against a real unit. 40 | void IRsend::sendCOOLIX(uint64_t data, uint16_t nbits, uint16_t repeat) { 41 | if (nbits % 8 != 0) 42 | return; // nbits is required to be a multiple of 8. 43 | 44 | // Set IR carrier frequency 45 | enableIROut(38); 46 | 47 | for (uint16_t r = 0; r <= repeat; r++) { 48 | // Header 49 | mark(COOLIX_HDR_MARK); 50 | space(COOLIX_HDR_SPACE); 51 | 52 | // Data 53 | // Break data into byte segments, starting at the Most Significant 54 | // Byte. Each byte then being sent normal, then followed inverted. 55 | for (uint16_t i = 8; i <= nbits; i += 8) { 56 | // Grab a bytes worth of data. 57 | uint8_t segment = (data >> (nbits - i)) & 0xFF; 58 | // Normal 59 | sendData(COOLIX_BIT_MARK, COOLIX_ONE_SPACE, 60 | COOLIX_BIT_MARK, COOLIX_ZERO_SPACE, 61 | segment, 8, true); 62 | // Inverted. 63 | sendData(COOLIX_BIT_MARK, COOLIX_ONE_SPACE, 64 | COOLIX_BIT_MARK, COOLIX_ZERO_SPACE, 65 | segment ^ 0xFF, 8, true); 66 | } 67 | 68 | // Footer 69 | mark(COOLIX_BIT_MARK); 70 | space(COOLIX_MIN_GAP); // Pause before repeating 71 | } 72 | } 73 | #endif 74 | 75 | #if DECODE_COOLIX 76 | // Decode the supplied Coolix message. 77 | // 78 | // Args: 79 | // results: Ptr to the data to decode and where to store the decode result. 80 | // nbits: The number of data bits to expect. Typically COOLIX_BITS. 81 | // strict: Flag indicating if we should perform strict matching. 82 | // Returns: 83 | // boolean: True if it can decode it, false if it can't. 84 | // 85 | // Status: BETA / Probably working. 86 | bool IRrecv::decodeCOOLIX(decode_results *results, uint16_t nbits, 87 | bool strict) { 88 | // The protocol sends the data normal + inverted, alternating on 89 | // each byte. Hence twice the number of expected data bits. 90 | if (results->rawlen < 2 * 2 * nbits + HEADER + FOOTER - 1) 91 | return false; // Can't possibly be a valid COOLIX message. 92 | if (strict && nbits != COOLIX_BITS) 93 | return false; // Not strictly an COOLIX message. 94 | if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte. 95 | return false; 96 | 97 | uint64_t data = 0; 98 | uint64_t inverted = 0; 99 | uint16_t offset = OFFSET_START; 100 | 101 | if (nbits > sizeof(data) * 8) 102 | return false; // We can't possibly capture a Coolix packet that big. 103 | 104 | // Header 105 | if (!matchMark(results->rawbuf[offset++], COOLIX_HDR_MARK)) 106 | return false; 107 | if (!matchSpace(results->rawbuf[offset++], COOLIX_HDR_SPACE)) 108 | return false; 109 | 110 | // Data 111 | // Twice as many bits as there are normal plus inverted bits. 112 | for (uint16_t i = 0; i < nbits * 2; i++, offset++) { 113 | bool flip = (i / 8) % 2; 114 | if (!matchMark(results->rawbuf[offset++], COOLIX_BIT_MARK)) 115 | return false; 116 | if (matchSpace(results->rawbuf[offset], COOLIX_ONE_SPACE)) { // 1 117 | if (flip) 118 | inverted = (inverted << 1) | 1; 119 | else 120 | data = (data << 1) | 1; 121 | } else if (matchSpace(results->rawbuf[offset], COOLIX_ZERO_SPACE)) { // 0 122 | if (flip) 123 | inverted <<= 1; 124 | else 125 | data <<= 1; 126 | } else { 127 | return false; 128 | } 129 | } 130 | 131 | // Footer 132 | if (!matchMark(results->rawbuf[offset++], COOLIX_BIT_MARK)) 133 | return false; 134 | if (offset <= results->rawlen && 135 | !matchAtLeast(results->rawbuf[offset], COOLIX_MIN_GAP)) 136 | return false; 137 | 138 | // Compliance 139 | uint64_t orig = data; // Save a copy of the data. 140 | if (strict) { 141 | for (uint16_t i = 0; i < nbits; i += 8, data >>= 8, inverted >>= 8) 142 | if ((data & 0xFF) != ((inverted & 0xFF) ^ 0xFF)) 143 | return false; 144 | } 145 | 146 | // Success 147 | results->decode_type = COOLIX; 148 | results->bits = nbits; 149 | results->value = orig; 150 | results->address = 0; 151 | results->command = 0; 152 | return true; 153 | } 154 | #endif 155 | -------------------------------------------------------------------------------- /test/IRsend_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRsend_test.h" 4 | #include "IRsend.h" 5 | #include "gtest/gtest.h" 6 | 7 | // Tests sendData(). 8 | 9 | // Test sending zero bits. 10 | TEST(TestSendData, SendZeroBits) { 11 | IRsendTest irsend(4); 12 | irsend.begin(); 13 | irsend.sendData(1, 2, 3, 4, 0b1, 0, true); 14 | EXPECT_EQ("", irsend.outputStr()); 15 | } 16 | 17 | // Test sending zero and one. 18 | TEST(TestSendData, SendSingleBit) { 19 | IRsendTest irsend(4); 20 | irsend.begin(); 21 | irsend.sendData(1, 2, 3, 4, 0b1, 1, true); 22 | EXPECT_EQ("m1s2", irsend.outputStr()); 23 | irsend.sendData(1, 2, 3, 4, 0b0, 1, true); 24 | EXPECT_EQ("m3s4", irsend.outputStr()); 25 | } 26 | 27 | // Test sending bit order. 28 | TEST(TestSendData, TestingBitSendOrder) { 29 | IRsendTest irsend(4); 30 | irsend.begin(); 31 | irsend.sendData(1, 2, 3, 4, 0b10, 2, true); 32 | EXPECT_EQ("m1s2m3s4", irsend.outputStr()); 33 | irsend.sendData(1, 2, 3, 4, 0b10, 2, false); 34 | EXPECT_EQ("m3s4m1s2", irsend.outputStr()); 35 | irsend.sendData(1, 2, 3, 4, 0b0001, 4, false); 36 | EXPECT_EQ("m1s2m3s4m3s4m3s4", irsend.outputStr()); 37 | } 38 | 39 | // Test sending typical data. 40 | TEST(TestSendData, SendTypicalData) { 41 | IRsendTest irsend(4); 42 | irsend.begin(); 43 | irsend.sendData(1, 2, 3, 4, 0b1010110011110000, 16, true); 44 | EXPECT_EQ("m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4m3s4", 45 | irsend.outputStr()); 46 | irsend.sendData(1, 2, 3, 4, 0x1234567890ABCDEF, 64, true); 47 | EXPECT_EQ("m3s4m3s4m3s4m1s2m3s4m3s4m1s2m3s4m3s4m3s4m1s2m1s2m3s4m1s2m3s4m3s4" 48 | "m3s4m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4" 49 | "m1s2m3s4m3s4m1s2m3s4m3s4m3s4m3s4m1s2m3s4m1s2m3s4m1s2m3s4m1s2m1s2" 50 | "m1s2m1s2m3s4m3s4m1s2m1s2m3s4m1s2m1s2m1s2m1s2m3s4m1s2m1s2m1s2m1s2", 51 | irsend.outputStr()); 52 | } 53 | 54 | // Test sending more than expected bits. 55 | TEST(TestSendData, SendOverLargeData) { 56 | IRsendTest irsend(4); 57 | irsend.begin(); 58 | irsend.sendData(1, 2, 3, 4, 0xFFFFFFFFFFFFFFFF, 70, true); 59 | EXPECT_EQ("m3s4m3s4m3s4m3s4m3s4m3s4" 60 | "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2" 61 | "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2" 62 | "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2" 63 | "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2", 64 | irsend.outputStr()); 65 | } 66 | 67 | // Test inverting the output. 68 | TEST(TestIRSend, InvertedOutput) { 69 | IRsendTest irsend(4, true); 70 | irsend.begin(); 71 | irsend.sendData(1, 2, 3, 4, 0b1, 1, true); 72 | EXPECT_EQ("s1m2", irsend.outputStr()); 73 | irsend.sendData(1, 2, 3, 4, 0b0, 1, true); 74 | EXPECT_EQ("s3m4", irsend.outputStr()); 75 | } 76 | 77 | // Test typical use of sendRaw(). 78 | TEST(TestSendRaw, GeneralUse) { 79 | IRsendTest irsend(4); 80 | IRrecv irrecv(0); 81 | 82 | irsend.begin(); 83 | // NEC C3E0E0E8 as measured in #204 84 | uint16_t rawData[67] = {8950, 4500, 550, 1650, 600, 1650, 550, 550, 600, 500, 85 | 600, 550, 550, 550, 600, 1650, 550, 1650, 600, 1650, 86 | 600, 1650, 550, 1700, 550, 550, 600, 550, 550, 550, 87 | 600, 500, 600, 550, 550, 1650, 600, 1650, 600, 1650, 88 | 550, 550, 600, 500, 600, 500, 600, 550, 550, 550, 89 | 600, 1650, 550, 1650, 600, 1650, 600, 500, 650, 1600, 90 | 600, 500, 600, 550, 550, 550, 600}; 91 | 92 | irsend.sendRaw(rawData, 67, 38); 93 | EXPECT_EQ( 94 | "m8950s4500" 95 | "m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650" 96 | "m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550" 97 | "m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550" 98 | "m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550" 99 | "m600", irsend.outputStr()); 100 | 101 | irsend.reset(); 102 | irsend.sendRaw(rawData, 67, 38); 103 | irsend.makeDecodeResult(); 104 | EXPECT_EQ( 105 | "m8950s4500" 106 | "m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650" 107 | "m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550" 108 | "m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550" 109 | "m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550" 110 | "m600", irsend.outputStr()); 111 | ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, NEC_BITS, false)); 112 | EXPECT_EQ(NEC, irsend.capture.decode_type); 113 | EXPECT_EQ(32, irsend.capture.bits); 114 | EXPECT_EQ(0xC3E0E0E8, irsend.capture.value); 115 | } 116 | 117 | // Incorrect handling of decodes from Raw. i.e. There is no gap recorded at 118 | // the end of a command when using the interrupt code. sendRaw() best emulates 119 | // this for unit testing purposes. sendGC() and sendXXX() will add the trailing 120 | // gap. Users won't see this in normal use. 121 | TEST(TestSendRaw, NoTrailingGap) { 122 | IRsendTest irsend(4); 123 | IRrecv irrecv(4); 124 | irsend.begin(); 125 | 126 | irsend.reset(); 127 | uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550, 128 | 600, 1650, 650, 550, 600, 1650, 650, 1650, 650, 1650, 129 | 600, 550, 650, 1650, 650, 1650, 650, 550, 600, 1650, 130 | 650, 1650, 650, 550, 650, 550, 650, 1650, 650, 550, 131 | 650, 550, 650, 550, 600, 550, 650, 550, 650, 550, 132 | 650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650, 133 | 650, 1650, 650, 1650, 650, 1650, 600}; 134 | irsend.sendRaw(rawData, 67, 38); 135 | irsend.makeDecodeResult(); 136 | EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture)); 137 | EXPECT_EQ(NEC, irsend.capture.decode_type); 138 | EXPECT_EQ(NEC_BITS, irsend.capture.bits); 139 | } 140 | -------------------------------------------------------------------------------- /src/ir_RCMM.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include 4 | #include "IRrecv.h" 5 | #include "IRsend.h" 6 | #include "IRtimer.h" 7 | 8 | // RRRRRR CCCCC MM MM MM MM 9 | // RR RR CC C MMM MMM MMM MMM 10 | // RRRRRR CC _____ MM MM MM MM MM MM 11 | // RR RR CC C MM MM MM MM 12 | // RR RR CCCCC MM MM MM MM 13 | 14 | // Send & decode support for RC-MM added by David Conran 15 | 16 | // Constants 17 | // Ref: 18 | // http://www.sbprojects.com/knowledge/ir/rcmm.php 19 | #define RCMM_HDR_MARK 416U 20 | #define RCMM_HDR_SPACE 277U 21 | #define RCMM_BIT_MARK 166U 22 | #define RCMM_BIT_SPACE_0 277U 23 | #define RCMM_BIT_SPACE_1 444U 24 | #define RCMM_BIT_SPACE_2 611U 25 | #define RCMM_BIT_SPACE_3 777U 26 | #define RCMM_RPT_LENGTH 27778U 27 | #define RCMM_MIN_GAP 3360U 28 | // Use a tolerance of +/-10% when matching some data spaces. 29 | #define RCMM_TOLERANCE 10U 30 | #define RCMM_EXCESS 50U 31 | 32 | #if SEND_RCMM 33 | // Send a Philips RC-MM packet. 34 | // 35 | // Args: 36 | // data: The data we want to send. MSB first. 37 | // nbits: The number of bits of data to send. (Typically 12, 24, or 32[Nokia]) 38 | // repeat: The nr. of times the message should be sent. 39 | // 40 | // Status: BETA / Should be working. 41 | // 42 | // Ref: 43 | // http://www.sbprojects.com/knowledge/ir/rcmm.php 44 | void IRsend::sendRCMM(uint64_t data, uint16_t nbits, uint16_t repeat) { 45 | // Set 36kHz IR carrier frequency & a 1/3 (33%) duty cycle. 46 | enableIROut(36, 33); 47 | IRtimer usecs = IRtimer(); 48 | 49 | for (uint16_t r = 0; r <= repeat; r++) { 50 | usecs.reset(); 51 | // Header 52 | mark(RCMM_HDR_MARK); 53 | space(RCMM_HDR_SPACE); 54 | // Data 55 | uint64_t mask = 0b11ULL << (nbits - 2); 56 | // RC-MM sends data 2 bits at a time. 57 | for (int32_t i = nbits; i > 0; i -= 2) { 58 | mark(RCMM_BIT_MARK); 59 | // Grab the next Most Significant Bits to send. 60 | switch ((data & mask) >> (i - 2)) { 61 | case 0b00: space(RCMM_BIT_SPACE_0); break; 62 | case 0b01: space(RCMM_BIT_SPACE_1); break; 63 | case 0b10: space(RCMM_BIT_SPACE_2); break; 64 | case 0b11: space(RCMM_BIT_SPACE_3); break; 65 | } 66 | mask >>= 2; 67 | } 68 | // Footer 69 | mark(RCMM_BIT_MARK); 70 | // Protocol requires us to wait at least RCMM_RPT_LENGTH usecs from the 71 | // start or RCMM_MIN_GAP usecs. 72 | space(std::max(RCMM_RPT_LENGTH - usecs.elapsed(), RCMM_MIN_GAP)); 73 | } 74 | } 75 | #endif 76 | 77 | #if DECODE_RCMM 78 | // Decode a Philips RC-MM packet (between 12 & 32 bits) if possible. 79 | // Places successful decode information in the results pointer. 80 | // Args: 81 | // results: Ptr to the data to decode and where to store the decode result. 82 | // nbits: Nr. of bits to expect in the data portion. Typically RCMM_BITS. 83 | // strict: Flag to indicate if we strictly adhere to the specification. 84 | // Returns: 85 | // boolean: True if it can decode it, false if it can't. 86 | // 87 | // Status: BETA / Should be working. 88 | // 89 | // Ref: 90 | // http://www.sbprojects.com/knowledge/ir/rcmm.php 91 | bool IRrecv::decodeRCMM(decode_results *results, uint16_t nbits, bool strict) { 92 | uint64_t data = 0; 93 | uint16_t offset = OFFSET_START; 94 | 95 | if (results->rawlen <= 4) 96 | return false; // Not enough entries to ever be RCMM. 97 | 98 | // Calc the maximum size in bits, the message can be, or that we can accept. 99 | int16_t maxBitSize = std::min((uint16_t) results->rawlen - 4, 100 | (uint16_t) sizeof(data) * 8); 101 | // Compliance 102 | if (strict) { 103 | // Technically the spec says bit sizes should be 12 xor 24. however 104 | // 32 bits has been seen from a device. We are going to assume 105 | // 12 <= bits <= 32 is the 'required' bit length for the spec. 106 | if (maxBitSize < 12 || maxBitSize > 32) 107 | return false; 108 | if (maxBitSize < nbits) 109 | return false; // Short cut, we can never reach the expected nr. of bits. 110 | } 111 | // Header decode 112 | if (!matchMark(results->rawbuf[offset++], RCMM_HDR_MARK)) 113 | return false; 114 | if (!matchSpace(results->rawbuf[offset++], RCMM_HDR_SPACE)) 115 | return false; 116 | // Data decode 117 | // RC-MM has two bits of data per mark/space pair. 118 | uint16_t actualBits; 119 | for (actualBits = 0; actualBits < maxBitSize; actualBits += 2, offset++) { 120 | if (!matchMark(results->rawbuf[offset++], RCMM_BIT_MARK)) 121 | return false; 122 | 123 | data <<= 2; 124 | // Use non-default tolerance & excess for matching some of the spaces as the 125 | // defaults are too generous and causes mis-matches in some cases. 126 | if (matchSpace(results->rawbuf[offset], 127 | RCMM_BIT_SPACE_0, TOLERANCE, RCMM_EXCESS)) 128 | data += 0; 129 | else if (matchSpace(results->rawbuf[offset], 130 | RCMM_BIT_SPACE_1, TOLERANCE, RCMM_EXCESS)) 131 | data += 1; 132 | else if (matchSpace(results->rawbuf[offset], 133 | RCMM_BIT_SPACE_2, RCMM_TOLERANCE, RCMM_EXCESS)) 134 | data += 2; 135 | else if (matchSpace(results->rawbuf[offset], 136 | RCMM_BIT_SPACE_3, RCMM_TOLERANCE, RCMM_EXCESS)) 137 | data += 3; 138 | else 139 | return false; 140 | } 141 | // Footer decode 142 | if (!matchMark(results->rawbuf[offset++], RCMM_BIT_MARK)) 143 | return false; 144 | if (offset <= results->rawlen && 145 | !matchAtLeast(results->rawbuf[offset], RCMM_MIN_GAP)) 146 | return false; 147 | 148 | // Compliance 149 | if (strict && actualBits != nbits) 150 | return false; 151 | 152 | // Success 153 | results->value = data; 154 | results->decode_type = RCMM; 155 | results->bits = actualBits; 156 | results->address = 0; 157 | results->command = 0; 158 | return true; 159 | } 160 | #endif 161 | -------------------------------------------------------------------------------- /src/ir_Samsung.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2009 Ken Shirriff 2 | // Copyright 2017 David Conran 3 | 4 | #include 5 | #include "IRrecv.h" 6 | #include "IRsend.h" 7 | #include "IRtimer.h" 8 | #include "IRutils.h" 9 | 10 | // SSSS AAA MMM SSSS U U N N GGGG 11 | // S A A M M M S U U NN N G 12 | // SSS AAAAA M M M SSS U U N N N G GG 13 | // S A A M M S U U N NN G G 14 | // SSSS A A M M SSSS UUU N N GGG 15 | 16 | // Samsung originally added from https://github.com/shirriff/Arduino-IRremote/ 17 | 18 | // Constants 19 | // Ref: 20 | // http://elektrolab.wz.cz/katalog/samsung_protocol.pdf 21 | #define SAMSUNG_HDR_MARK 4500U 22 | #define SAMSUNG_HDR_SPACE 4500U 23 | #define SAMSUNG_BIT_MARK 560U 24 | #define SAMSUNG_ONE_SPACE 1690U 25 | #define SAMSUNG_ZERO_SPACE 560U 26 | #define SAMSUNG_RPT_SPACE 2250U 27 | #define SAMSUNG_MIN_GAP 20000U // Completely made up figure. 28 | #define SAMSUNG_MIN_MESSAGE_LENGTH 108000UL 29 | 30 | #if SEND_SAMSUNG 31 | // Send a Samsung formatted message. 32 | // Samsung has a separate message to indicate a repeat, like NEC does. 33 | // TODO(crankyoldgit): Confirm that is actually how Samsung sends a repeat. 34 | // The refdoc doesn't indicate it is true. 35 | // 36 | // Args: 37 | // data: The message to be sent. 38 | // nbits: The bit size of the message being sent. typically SAMSUNG_BITS. 39 | // repeat: The number of times the message is to be repeated. 40 | // 41 | // Status: BETA / Should be working. 42 | // 43 | // Ref: http://elektrolab.wz.cz/katalog/samsung_protocol.pdf 44 | void IRsend::sendSAMSUNG(uint64_t data, uint16_t nbits, uint16_t repeat) { 45 | // Set 38kHz IR carrier frequency & a 1/3 (33%) duty cycle. 46 | enableIROut(38, 33); 47 | IRtimer usecTimer = IRtimer(); 48 | // We always send a message, even for repeat=0, hence '<= repeat'. 49 | for (uint16_t i=0; i <= repeat; i++) { 50 | usecTimer.reset(); 51 | // Header 52 | mark(SAMSUNG_HDR_MARK); 53 | space(SAMSUNG_HDR_SPACE); 54 | // Data 55 | sendData(SAMSUNG_BIT_MARK, SAMSUNG_ONE_SPACE, SAMSUNG_BIT_MARK, 56 | SAMSUNG_ZERO_SPACE, data, nbits, true); 57 | // Footer 58 | mark(SAMSUNG_BIT_MARK); 59 | space(std::max((uint32_t) SAMSUNG_MIN_GAP, 60 | (uint32_t) (SAMSUNG_MIN_MESSAGE_LENGTH - 61 | usecTimer.elapsed()))); 62 | } 63 | } 64 | 65 | // Construct a raw Samsung message from the supplied customer(address) & 66 | // command. 67 | // 68 | // Args: 69 | // customer: The customer code. (aka. Address) 70 | // command: The command code. 71 | // Returns: 72 | // A raw 32-bit Samsung message suitable for sendSAMSUNG(). 73 | // 74 | // Status: BETA / Should be working. 75 | uint32_t IRsend::encodeSAMSUNG(uint8_t customer, uint8_t command) { 76 | customer = reverseBits(customer, sizeof(customer) * 8); 77 | command = reverseBits(command, sizeof(command) * 8); 78 | return((command ^ 0xFF) | (command << 8) | 79 | (customer << 16) | (customer << 24)); 80 | } 81 | #endif 82 | 83 | #if DECODE_SAMSUNG 84 | // Decode the supplied Samsung message. 85 | // Samsung messages whilst 32 bits in size, only contain 16 bits of distinct 86 | // data. e.g. In transmition order: 87 | // customer_byte + customer_byte(same) + address_byte + invert(address_byte) 88 | // 89 | // Args: 90 | // results: Ptr to the data to decode and where to store the decode result. 91 | // nbits: Nr. of bits to expect in the data portion. Typically SAMSUNG_BITS. 92 | // strict: Flag to indicate if we strictly adhere to the specification. 93 | // Returns: 94 | // boolean: True if it can decode it, false if it can't. 95 | // 96 | // Status: STABLE 97 | // 98 | // Note: 99 | // LG 32bit protocol appears near identical to the Samsung protocol. 100 | // They differ on their compliance criteria and how they repeat. 101 | // Ref: 102 | // http://elektrolab.wz.cz/katalog/samsung_protocol.pdf 103 | bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits, 104 | bool strict) { 105 | if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) 106 | return false; // Can't possibly be a valid Samsung message. 107 | if (strict && nbits != SAMSUNG_BITS) 108 | return false; // We expect Samsung to be 32 bits of message. 109 | 110 | uint64_t data = 0; 111 | uint16_t offset = OFFSET_START; 112 | 113 | // Header 114 | if (!matchMark(results->rawbuf[offset++], SAMSUNG_HDR_MARK)) 115 | return false; 116 | if (!matchSpace(results->rawbuf[offset++], SAMSUNG_HDR_SPACE)) 117 | return false; 118 | // Data 119 | for (uint16_t i = 0; i < nbits; i++, offset++) { 120 | if (!matchMark(results->rawbuf[offset++], SAMSUNG_BIT_MARK)) 121 | return false; 122 | if (matchSpace(results->rawbuf[offset], SAMSUNG_ONE_SPACE)) 123 | data = (data << 1) | 1; // 1 124 | else if (matchSpace(results->rawbuf[offset], SAMSUNG_ZERO_SPACE)) 125 | data <<= 1; // 0 126 | else 127 | return false; 128 | } 129 | // Footer 130 | if (!matchMark(results->rawbuf[offset++], SAMSUNG_BIT_MARK)) 131 | return false; 132 | if (offset <= results->rawlen && 133 | !matchAtLeast(results->rawbuf[offset], SAMSUNG_MIN_GAP)) 134 | return false; 135 | 136 | // Compliance 137 | 138 | // According to the spec, the customer (address) code is the first 8 139 | // transmitted bits. It's then repeated. Check for that. 140 | uint8_t address = data >> 24; 141 | if (strict && address != ((data >> 16) & 0xFF)) 142 | return false; 143 | // Spec says the command code is the 3rd block of transmitted 8-bits, 144 | // followed by the inverted command code. 145 | uint8_t command = (data & 0xFF00) >> 8; 146 | if (strict && command != ((data & 0xFF) ^ 0xFF)) 147 | return false; 148 | 149 | // Success 150 | results->bits = nbits; 151 | results->value = data; 152 | results->decode_type = SAMSUNG; 153 | // command & address need to be reversed as they are transmitted LSB first, 154 | results->command = reverseBits(command, sizeof(command) * 8); 155 | results->address = reverseBits(address, sizeof(address) * 8); 156 | return true; 157 | } 158 | #endif 159 | -------------------------------------------------------------------------------- /examples/IRrecvDumpV2/IRrecvDumpV2.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRrecvDumpV2 - dump details of IR codes with IRrecv 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * Example circuit diagram: 5 | * https://github.com/markszabo/IRremoteESP8266/wiki#ir-receiving 6 | * Changes: 7 | * Version 0.2 April, 2017 8 | * - Decode from a copy of the data so we can start capturing faster thus 9 | * reduce the likelihood of miscaptures. 10 | * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com 11 | */ 12 | 13 | #include 14 | 15 | // An IR detector/demodulator is connected to GPIO pin 14(D5 on a NodeMCU 16 | // board). 17 | uint16_t RECV_PIN = 14; 18 | 19 | IRrecv irrecv(RECV_PIN); 20 | 21 | decode_results results; // Somewhere to store the results 22 | irparams_t save; // A place to copy the interrupt state while decoding. 23 | 24 | void setup() { 25 | // Status message will be sent to the PC at 115200 baud 26 | Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY); 27 | irrecv.enableIRIn(); // Start the receiver 28 | } 29 | 30 | // Print a uint64_t in Hex, to the Serial interface. 31 | // 32 | void serialPrintUint64Hex(uint64_t value) { 33 | // Serial.print() can't handle printing long longs. (uint64_t) 34 | // So we have to print the top and bottom halves separately. 35 | if (value >> 32) 36 | Serial.print((uint32_t) (value >> 32), HEX); 37 | Serial.print((uint32_t) (value & 0xFFFFFFFF), HEX); 38 | } 39 | 40 | // Display encoding type 41 | // 42 | void encoding(decode_results *results) { 43 | switch (results->decode_type) { 44 | default: 45 | case UNKNOWN: Serial.print("UNKNOWN"); break; 46 | case NEC: Serial.print("NEC"); break; 47 | case SONY: Serial.print("SONY"); break; 48 | case RC5: Serial.print("RC5"); break; 49 | case RC6: Serial.print("RC6"); break; 50 | case DISH: Serial.print("DISH"); break; 51 | case SHARP: Serial.print("SHARP"); break; 52 | case JVC: Serial.print("JVC"); break; 53 | case SANYO: Serial.print("SANYO"); break; 54 | case SANYO_LC7461: Serial.print("SANYO_LC7461"); break; 55 | case MITSUBISHI: Serial.print("MITSUBISHI"); break; 56 | case SAMSUNG: Serial.print("SAMSUNG"); break; 57 | case LG: Serial.print("LG"); break; 58 | case WHYNTER: Serial.print("WHYNTER"); break; 59 | case AIWA_RC_T501: Serial.print("AIWA_RC_T501"); break; 60 | case PANASONIC: Serial.print("PANASONIC"); break; 61 | case DENON: Serial.print("DENON"); break; 62 | case COOLIX: Serial.print("COOLIX"); break; 63 | } 64 | if (results->repeat) Serial.print(" (Repeat)"); 65 | } 66 | 67 | // Dump out the decode_results structure. 68 | // 69 | void dumpInfo(decode_results *results) { 70 | if (results->overflow) { 71 | Serial.println("IR code too long. Edit IRremoteInt.h and increase RAWBUF"); 72 | return; 73 | } 74 | 75 | // Show Encoding standard 76 | Serial.print("Encoding : "); 77 | encoding(results); 78 | Serial.println(""); 79 | 80 | // Show Code & length 81 | Serial.print("Code : "); 82 | serialPrintUint64Hex(results->value); 83 | Serial.print(" ("); 84 | Serial.print(results->bits, DEC); 85 | Serial.println(" bits)"); 86 | } 87 | 88 | // Dump out the decode_results structure. 89 | // 90 | void dumpRaw(decode_results *results) { 91 | // Print Raw data 92 | Serial.print("Timing["); 93 | Serial.print(results->rawlen - 1, DEC); 94 | Serial.println("]: "); 95 | 96 | for (uint16_t i = 1; i < results->rawlen; i++) { 97 | if (i % 100 == 0) 98 | yield(); // Preemptive yield every 100th entry to feed the WDT. 99 | uint32_t x = results->rawbuf[i] * USECPERTICK; 100 | if (!(i & 1)) { // even 101 | Serial.print("-"); 102 | if (x < 1000) Serial.print(" "); 103 | if (x < 100) Serial.print(" "); 104 | Serial.print(x, DEC); 105 | } else { // odd 106 | Serial.print(" "); 107 | Serial.print("+"); 108 | if (x < 1000) Serial.print(" "); 109 | if (x < 100) Serial.print(" "); 110 | Serial.print(x, DEC); 111 | if (i < results->rawlen - 1) 112 | Serial.print(", "); // ',' not needed for last one 113 | } 114 | if (!(i % 8)) Serial.println(""); 115 | } 116 | Serial.println(""); // Newline 117 | } 118 | 119 | // Dump out the decode_results structure. 120 | // 121 | void dumpCode(decode_results *results) { 122 | // Start declaration 123 | Serial.print("uint16_t "); // variable type 124 | Serial.print("rawData["); // array name 125 | Serial.print(results->rawlen - 1, DEC); // array size 126 | Serial.print("] = {"); // Start declaration 127 | 128 | // Dump data 129 | for (uint16_t i = 1; i < results->rawlen; i++) { 130 | Serial.print(results->rawbuf[i] * USECPERTICK, DEC); 131 | if (i < results->rawlen - 1) 132 | Serial.print(","); // ',' not needed on last one 133 | if (!(i & 1)) Serial.print(" "); 134 | } 135 | 136 | // End declaration 137 | Serial.print("};"); // 138 | 139 | // Comment 140 | Serial.print(" // "); 141 | encoding(results); 142 | Serial.print(" "); 143 | serialPrintUint64Hex(results->value); 144 | 145 | // Newline 146 | Serial.println(""); 147 | 148 | // Now dump "known" codes 149 | if (results->decode_type != UNKNOWN) { 150 | // Some protocols have an address &/or command. 151 | // NOTE: It will ignore the atypical case when a message has been decoded 152 | // but the address & the command are both 0. 153 | if (results->address > 0 || results->command > 0) { 154 | Serial.print("uint32_t address = 0x"); 155 | Serial.print(results->address, HEX); 156 | Serial.println(";"); 157 | Serial.print("uint32_t command = 0x"); 158 | Serial.print(results->command, HEX); 159 | Serial.println(";"); 160 | } 161 | 162 | // All protocols have data 163 | Serial.print("uint64_t data = 0x"); 164 | serialPrintUint64Hex(results->value); 165 | Serial.println(";"); 166 | } 167 | } 168 | 169 | // The repeating section of the code 170 | // 171 | void loop() { 172 | // Check if the IR code has been received. 173 | if (irrecv.decode(&results, &save)) { 174 | dumpInfo(&results); // Output the results 175 | dumpRaw(&results); // Output the results in RAW format 176 | dumpCode(&results); // Output the results as source code 177 | Serial.println(""); // Blank line between entries 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/ir_Panasonic.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Kristian Lauszus 2 | // Copyright 2017 David Conran 3 | 4 | #include 5 | #include "IRrecv.h" 6 | #include "IRsend.h" 7 | #include "IRtimer.h" 8 | 9 | // PPPP AAA N N AAA SSSS OOO N N IIIII CCCC 10 | // P P A A NN N A A S O O NN N I C 11 | // PPPP AAAAA N N N AAAAA SSS O O N N N I C 12 | // P A A N NN A A S O O N NN I C 13 | // P A A N N A A SSSS OOO N N IIIII CCCC 14 | 15 | // Panasonic protocol originally added by Kristian Lauszus from: 16 | // https://github.com/z3t0/Arduino-IRremote 17 | // (Thanks to zenwheel and other people at the original blog post) 18 | 19 | // Constants 20 | // Ref: 21 | // http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?26152 22 | #define PANASONIC_HDR_MARK 3456U 23 | #define PANASONIC_HDR_SPACE 1728U 24 | #define PANASONIC_BIT_MARK 432U 25 | #define PANASONIC_ONE_SPACE 1296U 26 | #define PANASONIC_ZERO_SPACE 432U 27 | #define PANASONIC_MIN_COMMAND_LENGTH 130000UL 28 | #define PANASONIC_MIN_GAP ((uint32_t)(PANASONIC_MIN_COMMAND_LENGTH - \ 29 | (PANASONIC_HDR_MARK + PANASONIC_HDR_SPACE + \ 30 | PANASONIC_BITS * (PANASONIC_BIT_MARK + PANASONIC_ONE_SPACE) + \ 31 | PANASONIC_BIT_MARK))) 32 | 33 | #if (SEND_PANASONIC || SEND_DENON) 34 | // Send a Panasonic formatted message. 35 | // 36 | // Args: 37 | // data: The message to be sent. 38 | // nbits: The number of bits of the message to be sent. (PANASONIC_BITS). 39 | // repeat: The number of times the command is to be repeated. 40 | // 41 | // Status: BETA / Should be working. 42 | // 43 | // Note: 44 | // This protocol is a modified version of Kaseikyo. 45 | void IRsend::sendPanasonic64(uint64_t data, uint16_t nbits, uint16_t repeat) { 46 | enableIROut(36700U); // Set IR carrier frequency of 36.7kHz. 47 | IRtimer usecTimer = IRtimer(); 48 | 49 | for (uint16_t i = 0; i <= repeat; i++) { 50 | usecTimer.reset(); 51 | // Header 52 | mark(PANASONIC_HDR_MARK); 53 | space(PANASONIC_HDR_SPACE); 54 | // Data 55 | sendData(PANASONIC_BIT_MARK, PANASONIC_ONE_SPACE, 56 | PANASONIC_BIT_MARK, PANASONIC_ZERO_SPACE, 57 | data, nbits, true); 58 | // Footer 59 | mark(PANASONIC_BIT_MARK); 60 | space(std::max((uint32_t) PANASONIC_MIN_COMMAND_LENGTH - 61 | usecTimer.elapsed(), 62 | PANASONIC_MIN_GAP)); 63 | } 64 | } 65 | 66 | // Send a Panasonic formatted message. 67 | // 68 | // Args: 69 | // address: The manufacturer code. 70 | // data: The data portion to be sent. 71 | // nbits: The number of bits of the message to be sent. (PANASONIC_BITS). 72 | // repeat: The number of times the command is to be repeated. 73 | // 74 | // Status: STABLE. 75 | // 76 | // Note: 77 | // This protocol is a modified version of Kaseikyo. 78 | void IRsend::sendPanasonic(uint16_t address, uint32_t data, uint16_t nbits, 79 | uint16_t repeat) { 80 | sendPanasonic64(((uint64_t) address << 32) | (uint64_t) data, nbits, repeat); 81 | } 82 | 83 | // Calculate the raw Panasonic data based on device, subdevice, & function. 84 | // 85 | // Args: 86 | // manufacturer: A 16-bit manufacturer code. e.g. 0x4004 is Panasonic. 87 | // device: An 8-bit code. 88 | // subdevice: An 8-bit code. 89 | // function: An 8-bit code. 90 | // Returns: 91 | // A raw uint64_t Panasonic message. 92 | // 93 | // Status: BETA / Should be working.. 94 | // 95 | // Note: 96 | // Panasonic 48-bit protocol is a modified version of Kaseikyo. 97 | // Ref: 98 | // http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?2615 99 | uint64_t IRsend::encodePanasonic(uint16_t manufacturer, 100 | uint8_t device, 101 | uint8_t subdevice, 102 | uint8_t function) { 103 | uint8_t checksum = device ^ subdevice ^ function; 104 | return (((uint64_t) manufacturer << 32) | 105 | ((uint64_t) device << 24) | 106 | ((uint64_t) subdevice << 16) | 107 | ((uint64_t) function << 8) | 108 | checksum); 109 | } 110 | #endif // (SEND_PANASONIC || SEND_DENON) 111 | 112 | #if (DECODE_PANASONIC || DECODE_DENON) 113 | // Decode the supplied Panasonic message. 114 | // 115 | // Args: 116 | // results: Ptr to the data to decode and where to store the decode result. 117 | // nbits: Nr. of data bits to expect. 118 | // strict: Flag indicating if we should perform strict matching. 119 | // Returns: 120 | // boolean: True if it can decode it, false if it can't. 121 | // 122 | // Status: BETA / Should be working. 123 | // Note: 124 | // Panasonic 48-bit protocol is a modified version of Kaseikyo. 125 | // Ref: 126 | // http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?26152 127 | // http://www.hifi-remote.com/wiki/index.php?title=Panasonic 128 | bool IRrecv::decodePanasonic(decode_results *results, uint16_t nbits, 129 | bool strict, uint32_t manufacturer) { 130 | if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1) 131 | return false; // Not enough entries to be a Panasonic message. 132 | if (strict && nbits != PANASONIC_BITS) 133 | return false; // Request is out of spec. 134 | 135 | uint64_t data = 0; 136 | uint16_t offset = OFFSET_START; 137 | 138 | // Header 139 | if (!matchMark(results->rawbuf[offset++], PANASONIC_HDR_MARK)) 140 | return false; 141 | if (!matchMark(results->rawbuf[offset++], PANASONIC_HDR_SPACE)) 142 | return false; 143 | 144 | // Data 145 | for (uint16_t i = 0; i < nbits; i++, offset++) { 146 | if (!match(results->rawbuf[offset++], PANASONIC_BIT_MARK)) 147 | return false; 148 | if (match(results->rawbuf[offset], PANASONIC_ONE_SPACE)) 149 | data = (data << 1) | 1; // 1 150 | else if (match(results->rawbuf[offset], PANASONIC_ZERO_SPACE)) 151 | data <<= 1; // 0 152 | else 153 | return false; 154 | } 155 | // Footer 156 | if (!match(results->rawbuf[offset++], PANASONIC_BIT_MARK)) 157 | return false; 158 | if (offset <= results->rawlen && 159 | !matchAtLeast(results->rawbuf[offset], PANASONIC_MIN_GAP)) 160 | return false; 161 | 162 | // Compliance 163 | uint32_t address = data >> 32; 164 | uint32_t command = data & 0xFFFFFFFF; 165 | if (strict) { 166 | if (address != manufacturer) // Verify the Manufacturer code. 167 | return false; 168 | // Verify the checksum. 169 | uint8_t checksumOrig = data & 0xFF; 170 | uint8_t checksumCalc = ((data >> 24) ^ (data >> 16) ^ (data >> 8)) & 0xFF; 171 | if (checksumOrig != checksumCalc) 172 | return false; 173 | } 174 | 175 | // Success 176 | results->value = data; 177 | results->address = address; 178 | results->command = command; 179 | results->decode_type = PANASONIC; 180 | results->bits = nbits; 181 | return true; 182 | } 183 | #endif // (DECODE_PANASONIC || DECODE_DENON) 184 | -------------------------------------------------------------------------------- /src/IRrecv.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009 Ken Shirriff 2 | // Copyright 2015 Mark Szabo 3 | // Copyright 2015 Sebastien Warin 4 | // Copyright 2017 David Conran 5 | 6 | #ifndef IRRECV_H_ 7 | #define IRRECV_H_ 8 | 9 | #ifndef UNIT_TEST 10 | #include 11 | #endif 12 | #include 13 | #define __STDC_LIMIT_MACROS 14 | #include 15 | #include "IRremoteESP8266.h" 16 | 17 | // Constants 18 | #define HEADER 2U // Usual nr. of header entries. 19 | #define FOOTER 2U // Usual nr. of footer (stop bits) entries. 20 | #define OFFSET_START 1U // Usual rawbuf entry to start processing from. 21 | // Marks tend to be 100us too long, and spaces 100us too short 22 | // when received due to sensor lag. 23 | #define MARK_EXCESS 100U 24 | #define RAWBUF 100U // Length of raw duration buffer 25 | #define REPEAT UINT64_MAX 26 | // receiver states 27 | #define STATE_IDLE 2U 28 | #define STATE_MARK 3U 29 | #define STATE_SPACE 4U 30 | #define STATE_STOP 5U 31 | #define TOLERANCE 25U // default percent tolerance in measurements 32 | #define USECPERTICK 50U // microseconds per clock interrupt tick 33 | #define TIMEOUT_MS 15U // How long before we give up wait for more data. 34 | 35 | // Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param 36 | #define FNV_PRIME_32 16777619UL 37 | #define FNV_BASIS_32 2166136261UL 38 | 39 | // Types 40 | // information for the interrupt handler 41 | typedef struct { 42 | uint8_t recvpin; // pin for IR data from detector 43 | uint8_t rcvstate; // state machine 44 | uint16_t timer; // state timer, counts 50uS ticks. 45 | uint16_t rawbuf[RAWBUF]; // raw data 46 | // uint16_t is used for rawlen as it saves 3 bytes of iram in the interrupt 47 | // handler. Don't ask why, I don't know. It just does. 48 | uint16_t rawlen; // counter of entries in rawbuf. 49 | uint8_t overflow; // Buffer overflow indicator. 50 | } irparams_t; 51 | 52 | // Classes 53 | 54 | // Results returned from the decoder 55 | class decode_results { 56 | public: 57 | decode_type_t decode_type; // NEC, SONY, RC5, UNKNOWN 58 | uint64_t value; // Decoded value 59 | uint16_t bits; // Number of bits in decoded value 60 | volatile uint16_t *rawbuf; // Raw intervals in .5 us ticks 61 | uint16_t rawlen; // Number of records in rawbuf. 62 | bool overflow; 63 | bool repeat; // Is the result a repeat code? 64 | uint32_t address; // Decoded device address. 65 | uint32_t command; // Decoded command. 66 | }; 67 | 68 | // main class for receiving IR 69 | class IRrecv { 70 | public: 71 | explicit IRrecv(uint16_t recvpin); 72 | bool decode(decode_results *results, irparams_t *save = NULL); 73 | void enableIRIn(); 74 | void disableIRIn(); 75 | void resume(); 76 | 77 | #ifndef UNIT_TEST 78 | 79 | private: 80 | #endif 81 | // These are called by decode 82 | void copyIrParams(irparams_t *dest); 83 | int16_t compare(uint16_t oldval, uint16_t newval); 84 | uint32_t ticksLow(uint32_t usecs, uint8_t tolerance = TOLERANCE); 85 | uint32_t ticksHigh(uint32_t usecs, uint8_t tolerance = TOLERANCE); 86 | bool match(uint32_t measured_ticks, uint32_t desired_us, 87 | uint8_t tolerance = TOLERANCE); 88 | bool matchAtLeast(uint32_t measured_ticks, uint32_t desired_us, 89 | uint8_t tolerance = TOLERANCE); 90 | bool matchMark(uint32_t measured_ticks, uint32_t desired_us, 91 | uint8_t tolerance = TOLERANCE, int16_t excess = MARK_EXCESS); 92 | bool matchSpace(uint32_t measured_ticks, uint32_t desired_us, 93 | uint8_t tolerance = TOLERANCE, int16_t excess = MARK_EXCESS); 94 | bool decodeHash(decode_results *results); 95 | #if (DECODE_NEC || DECODE_SHERWOOD || DECODE_AIWA_RC_T501 || SEND_SANYO) 96 | bool decodeNEC(decode_results *results, uint16_t nbits = NEC_BITS, 97 | bool strict = true); 98 | #endif 99 | #if DECODE_SONY 100 | bool decodeSony(decode_results *results, uint16_t nbits = SONY_MIN_BITS, 101 | bool strict = false); 102 | #endif 103 | #if DECODE_SANYO 104 | // DISABLED due to poor quality. 105 | // bool decodeSanyo(decode_results *results, 106 | // uint16_t nbits = SANYO_SA8650B_BITS, 107 | // bool strict = false); 108 | bool decodeSanyoLC7461(decode_results *results, 109 | uint16_t nbits = SANYO_LC7461_BITS, 110 | bool strict = true); 111 | #endif 112 | #if DECODE_MITSUBISHI 113 | bool decodeMitsubishi(decode_results *results, 114 | uint16_t nbits = MITSUBISHI_BITS, 115 | bool strict = true); 116 | #endif 117 | #if (DECODE_RC5 || DECODE_R6) 118 | int16_t getRClevel(decode_results *results, uint16_t *offset, uint16_t *used, 119 | uint16_t bitTime); 120 | #endif 121 | #if DECODE_RC5 122 | bool decodeRC5(decode_results *results, uint16_t nbits = RC5X_BITS, 123 | bool strict = true); 124 | #endif 125 | #if DECODE_RC6 126 | bool decodeRC6(decode_results *results, uint16_t nbits = RC6_MODE0_BITS, 127 | bool strict = false); 128 | #endif 129 | #if DECODE_RCMM 130 | bool decodeRCMM(decode_results *results, uint16_t nbits = RCMM_BITS, 131 | bool strict = false); 132 | #endif 133 | #if (DECODE_PANASONIC || DECODE_DENON) 134 | bool decodePanasonic(decode_results *results, uint16_t nbits = PANASONIC_BITS, 135 | bool strict = false, 136 | uint32_t manufacturer = PANASONIC_MANUFACTURER); 137 | #endif 138 | #if DECODE_LG 139 | bool decodeLG(decode_results *results, uint16_t nbits = LG_BITS, 140 | bool strict = false); 141 | #endif 142 | #if DECODE_JVC 143 | bool decodeJVC(decode_results *results, uint16_t nbits = JVC_BITS, 144 | bool strict = true); 145 | #endif 146 | #if DECODE_SAMSUNG 147 | bool decodeSAMSUNG(decode_results *results, uint16_t nbits = SAMSUNG_BITS, 148 | bool strict = true); 149 | #endif 150 | #if DECODE_WHYNTER 151 | bool decodeWhynter(decode_results *results, uint16_t nbits = WHYNTER_BITS, 152 | bool strict = true); 153 | #endif 154 | #if DECODE_COOLIX 155 | bool decodeCOOLIX(decode_results *results, uint16_t nbits = COOLIX_BITS, 156 | bool strict = true); 157 | #endif 158 | #if DECODE_DENON 159 | bool decodeDenon(decode_results *results, uint16_t nbits = DENON_BITS, 160 | bool strict = true); 161 | #endif 162 | #if DECODE_DISH 163 | bool decodeDISH(decode_results *results, uint16_t nbits = DISH_BITS, 164 | bool strict = true); 165 | #endif 166 | #if (DECODE_SHARP || DECODE_DENON) 167 | bool decodeSharp(decode_results *results, uint16_t nbits = SHARP_BITS, 168 | bool strict = true, bool expansion = true); 169 | #endif 170 | #if DECODE_AIWA_RC_T501 171 | bool decodeAiwaRCT501(decode_results *results, 172 | uint16_t nbits = AIWA_RC_T501_BITS, bool strict = true); 173 | #endif 174 | }; 175 | 176 | #endif // IRRECV_H_ 177 | -------------------------------------------------------------------------------- /src/ir_Sony.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2009 Ken Shirriff 2 | // Copyright 2016 marcosamarinho 3 | // Copyright 2017 David Conran 4 | 5 | #include 6 | #include "IRrecv.h" 7 | #include "IRsend.h" 8 | #include "IRtimer.h" 9 | #include "IRutils.h" 10 | 11 | // SSSS OOO N N Y Y 12 | // S O O NN N Y Y 13 | // SSS O O N N N Y 14 | // S O O N NN Y 15 | // SSSS OOO N N Y 16 | 17 | // Sony originally added from https://github.com/shirriff/Arduino-IRremote/ 18 | // Updates from marcosamarinho 19 | 20 | // Constants 21 | // Ref: 22 | // http://www.sbprojects.com/knowledge/ir/sirc.php 23 | #define SONY_HDR_MARK 2400U 24 | #define SONY_SPACE 600U 25 | #define SONY_ONE_MARK 1200U 26 | #define SONY_ZERO_MARK 600U 27 | #define SONY_RPT_LENGTH 45000U 28 | #define SONY_MIN_GAP 10000U 29 | 30 | #if SEND_SONY 31 | // Send a Sony/SIRC(Serial Infra-Red Control) message. 32 | // 33 | // Args: 34 | // data: message to be sent. 35 | // nbits: Nr. of bits of the message to be sent. 36 | // repeat: Nr. of additional times the message is to be sent. (Default: 2) 37 | // 38 | // Status: STABLE / Known working. 39 | // 40 | // Notes: 41 | // sendSony() should typically be called with repeat=2 as Sony devices 42 | // expect the message to be sent at least 3 times. 43 | // 44 | // Ref: 45 | // http://www.sbprojects.com/knowledge/ir/sirc.php 46 | void IRsend::sendSony(uint64_t data, uint16_t nbits, uint16_t repeat) { 47 | // Sony devices use a 40kHz IR carrier frequency & a 1/3 (33%) duty cycle. 48 | enableIROut(40, 33); 49 | IRtimer usecs = IRtimer(); 50 | 51 | for (uint16_t i = 0; i <= repeat; i++) { // Typically loop 3 or more times. 52 | usecs.reset(); 53 | // Header 54 | mark(SONY_HDR_MARK); 55 | space(SONY_SPACE); 56 | // Data 57 | sendData(SONY_ONE_MARK, SONY_SPACE, SONY_ZERO_MARK, SONY_SPACE, 58 | data, nbits, true); 59 | // Footer 60 | // The Sony protocol requires us to wait 45ms from start of a code to the 61 | // start of the next one. A 10ms minimum gap is also required. 62 | space(std::max(SONY_MIN_GAP, SONY_RPT_LENGTH - usecs.elapsed())); 63 | } 64 | // A space() is always performed last, so no need to turn off the LED. 65 | } 66 | 67 | // Convert Sony/SIRC command, address, & extended bits into sendSony format. 68 | // Args: 69 | // nbits: Sony protocol bit size. 70 | // command: Sony command bits. 71 | // address: Sony address bits. 72 | // extended: Sony extended bits. 73 | // Returns: 74 | // A sendSony compatible data message. 75 | // 76 | // Status: BETA / Should be working. 77 | uint32_t IRsend::encodeSony(uint16_t nbits, uint16_t command, 78 | uint16_t address, uint16_t extended) { 79 | uint32_t result = 0; 80 | switch (nbits) { 81 | case 12: // 5 address bits. 82 | result = address & 0x1F; 83 | break; 84 | case 15: // 8 address bits. 85 | result = address & 0xFF; 86 | break; 87 | case 20: // 5 address bits, 8 extended bits. 88 | result = address & 0x1F; 89 | result |= (extended & 0xFF) << 5; 90 | break; 91 | default: 92 | return 0; // This is not an expected Sony bit size/protocol. 93 | } 94 | result = (result << 7) | (command & 0x7F); // All sizes have 7 command bits. 95 | return reverseBits(result, nbits); // sendSony uses reverse ordered bits. 96 | } 97 | #endif 98 | 99 | #if DECODE_SONY 100 | // Decode the supplied Sony/SIRC message. 101 | // 102 | // Args: 103 | // results: Ptr to the data to decode and where to store the decode result. 104 | // nbits: The number of data bits to expect. 105 | // strict: Flag indicating if we should perform strict matching. 106 | // Returns: 107 | // boolean: True if it can decode it, false if it can't. 108 | // 109 | // Status: BETA / Should be working. strict mode is ALPHA / Untested. 110 | // 111 | // Notes: 112 | // SONY protocol, SIRC (Serial Infra-Red Control) can be 12,15,20 bits long. 113 | // Ref: 114 | // http://www.sbprojects.com/knowledge/ir/sirc.php 115 | bool IRrecv::decodeSony(decode_results *results, uint16_t nbits, bool strict) { 116 | if (results->rawlen < 2 * nbits + HEADER - 1) 117 | return false; // Message is smaller than we expected. 118 | 119 | // Compliance 120 | if (strict) { 121 | switch (nbits) { // Check we've been called with a correct bit size. 122 | case 12: 123 | case 15: 124 | case 20: 125 | break; 126 | default: 127 | return false; // The request doesn't strictly match the protocol defn. 128 | } 129 | } 130 | 131 | uint64_t data = 0; 132 | uint16_t offset = OFFSET_START; 133 | uint16_t actualBits; 134 | uint32_t timeSoFar = 0; // Time in uSecs of the message length. 135 | 136 | // Header 137 | timeSoFar += results->rawbuf[offset] * USECPERTICK; 138 | if (!matchMark(results->rawbuf[offset++], SONY_HDR_MARK)) 139 | return false; 140 | // Data 141 | for (actualBits = 0; offset < results->rawlen - 1; actualBits++, offset++) { 142 | // The gap after a Sony packet for a repeat should be SONY_MIN_GAP or 143 | // (SONY_RPT_LENGTH - timeSoFar) according to the spec. 144 | if (matchSpace(results->rawbuf[offset], SONY_MIN_GAP) || 145 | #ifdef UNIT_TEST 146 | matchSpace(results->rawbuf[offset], SONY_RPT_LENGTH) || 147 | #endif 148 | matchSpace(results->rawbuf[offset], SONY_RPT_LENGTH - timeSoFar)) 149 | break; // Found a repeat space. 150 | timeSoFar += results->rawbuf[offset] * USECPERTICK; 151 | if (!matchSpace(results->rawbuf[offset++], SONY_SPACE)) 152 | return false; 153 | timeSoFar += results->rawbuf[offset] * USECPERTICK; 154 | if (matchMark(results->rawbuf[offset], SONY_ONE_MARK)) 155 | data = (data << 1) | 1; 156 | else if (matchMark(results->rawbuf[offset], SONY_ZERO_MARK)) 157 | data <<= 1; 158 | else 159 | return false; 160 | } 161 | // No Footer for Sony. 162 | 163 | // Compliance 164 | if (strict && actualBits != nbits) 165 | return false; // We got the wrong number of bits. 166 | 167 | // Success 168 | results->bits = actualBits; 169 | results->value = data; 170 | results->decode_type = SONY; 171 | // Message comes in LSB first. Convert ot MSB first. 172 | data = reverseBits(data, actualBits); 173 | // Decode the address & command from raw decode value. 174 | switch (actualBits) { 175 | case 12: // 7 command bits, 5 address bits. 176 | case 15: // 7 command bits, 8 address bits. 177 | results->command = data & 0x7F; // Bits 0-6 178 | results->address = data >> 7; // Bits 7-14 179 | break; 180 | case 20: // 7 command bits, 5 address bits, 8 extended (command) bits. 181 | results->command = (data & 0x7F) + ((data >> 12) << 7); // Bits 0-6,12-19 182 | results->address = (data >> 7) & 0x1F; // Bits 7-11 183 | break; 184 | default: // Shouldn't happen, but just in case. 185 | results->address = 0; 186 | results->command = 0; 187 | } 188 | return true; 189 | } 190 | #endif 191 | -------------------------------------------------------------------------------- /src/ir_NEC.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2009 Ken Shirriff 2 | // Copyright 2017 David Conran 3 | 4 | #define __STDC_LIMIT_MACROS 5 | #include 6 | #include 7 | #include "IRrecv.h" 8 | #include "IRsend.h" 9 | #include "IRtimer.h" 10 | #include "IRutils.h" 11 | 12 | // N N EEEEE CCCC 13 | // NN N E C 14 | // N N N EEE C 15 | // N NN E C 16 | // N N EEEEE CCCC 17 | 18 | // NEC originally added from https://github.com/shirriff/Arduino-IRremote/ 19 | 20 | // Constants 21 | // Ref: 22 | // http://www.sbprojects.com/knowledge/ir/nec.php 23 | #define NEC_HDR_MARK 9000U 24 | #define NEC_HDR_SPACE 4500U 25 | #define NEC_BIT_MARK 560U 26 | #define NEC_ONE_SPACE 1690U 27 | #define NEC_ZERO_SPACE 560U 28 | #define NEC_RPT_SPACE 2250U 29 | #define NEC_RPT_LENGTH 4U 30 | #define NEC_MIN_COMMAND_LENGTH 108000UL 31 | #define NEC_MIN_GAP NEC_MIN_COMMAND_LENGTH - \ 32 | (NEC_HDR_MARK + NEC_HDR_SPACE + NEC_BITS * (NEC_BIT_MARK + NEC_ONE_SPACE) \ 33 | + NEC_BIT_MARK) 34 | 35 | #if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO) 36 | // Send a raw NEC(Renesas) formatted message. 37 | // 38 | // Args: 39 | // data: The message to be sent. 40 | // nbits: The number of bits of the message to be sent. Typically NEC_BITS. 41 | // repeat: The number of times the command is to be repeated. 42 | // 43 | // Status: STABLE / Known working. 44 | // 45 | // Ref: 46 | // http://www.sbprojects.com/knowledge/ir/nec.php 47 | void IRsend::sendNEC(uint64_t data, uint16_t nbits, uint16_t repeat) { 48 | // Set 38kHz IR carrier frequency & a 1/3 (33%) duty cycle. 49 | enableIROut(38, 33); 50 | IRtimer usecs = IRtimer(); 51 | // Header 52 | mark(NEC_HDR_MARK); 53 | space(NEC_HDR_SPACE); 54 | // Data 55 | sendData(NEC_BIT_MARK, NEC_ONE_SPACE, NEC_BIT_MARK, NEC_ZERO_SPACE, 56 | data, nbits, true); 57 | // Footer 58 | mark(NEC_BIT_MARK); 59 | // Gap to next command. 60 | space(std::max(NEC_MIN_GAP, NEC_MIN_COMMAND_LENGTH - usecs.elapsed())); 61 | 62 | // Optional command repeat sequence. 63 | for (uint16_t i = 0; i < repeat; i++) { 64 | usecs.reset(); 65 | mark(NEC_HDR_MARK); 66 | space(NEC_RPT_SPACE); 67 | mark(NEC_BIT_MARK); 68 | // Gap till next command. 69 | space(std::max(NEC_MIN_GAP, NEC_MIN_COMMAND_LENGTH - usecs.elapsed())); 70 | } 71 | } 72 | 73 | // Calculate the raw NEC data based on address and command. 74 | // Args: 75 | // address: An address value. 76 | // command: An 8-bit command value. 77 | // Returns: 78 | // A raw 32-bit NEC message. 79 | // 80 | // Status: BETA / Expected to work. 81 | // 82 | // Ref: 83 | // http://www.sbprojects.com/knowledge/ir/nec.php 84 | uint32_t IRsend::encodeNEC(uint16_t address, uint16_t command) { 85 | command &= 0xFF; // We only want the least significant byte of command. 86 | // sendNEC() sends MSB first, but protocol says this is LSB first. 87 | command = reverseBits(command, 8); 88 | command = (command << 8) + (command ^ 0xFF); // Calculate the new command. 89 | if (address > 0xFF) { // Is it Extended NEC? 90 | address = reverseBits(address, 16); 91 | return ((address << 16) + command); // Extended. 92 | } else { 93 | address = reverseBits(address, 8); 94 | return (address << 24) + ((address ^ 0xFF) << 16) + command; // Normal. 95 | } 96 | } 97 | #endif 98 | 99 | #if (DECODE_NEC || DECODE_SHERWOOD || DECODE_AIWA_RC_T501 || DECODE_SANYO) 100 | // Decode the supplied NEC message. 101 | // 102 | // Args: 103 | // results: Ptr to the data to decode and where to store the decode result. 104 | // nbits: The number of data bits to expect. Typically NEC_BITS. 105 | // strict: Flag indicating if we should perform strict matching. 106 | // Returns: 107 | // boolean: True if it can decode it, false if it can't. 108 | // 109 | // Status: STABLE / Known good. 110 | // 111 | // Notes: 112 | // NEC protocol has three varients/forms. 113 | // Normal: a 8 bit address & a 8 bit command in 32 bit data form. 114 | // i.e. address + inverted(address) + command + inverted(command) 115 | // Extended: a 16 bit address & a 8 bit command in 32 bit data form. 116 | // i.e. address + command + inverted(command) 117 | // Repeat: a 0-bit code. i.e. No data bits. Just the header + footer. 118 | // 119 | // Ref: 120 | // http://www.sbprojects.com/knowledge/ir/nec.php 121 | bool IRrecv::decodeNEC(decode_results *results, uint16_t nbits, bool strict) { 122 | if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1 && 123 | results->rawlen != NEC_RPT_LENGTH) 124 | return false; // Can't possibly be a valid NEC message. 125 | if (strict && nbits != NEC_BITS) 126 | return false; // Not strictly an NEC message. 127 | 128 | uint64_t data = 0; 129 | uint16_t offset = OFFSET_START; 130 | 131 | // Header 132 | if (!matchMark(results->rawbuf[offset++], NEC_HDR_MARK)) 133 | return false; 134 | // Check if it is a repeat code. 135 | if (results->rawlen == NEC_RPT_LENGTH && 136 | matchSpace(results->rawbuf[offset], NEC_RPT_SPACE) && 137 | matchMark(results->rawbuf[offset + 1], NEC_BIT_MARK)) { 138 | results->value = REPEAT; 139 | results->decode_type = NEC; 140 | results->bits = 0; 141 | results->address = 0; 142 | results->command = 0; 143 | results->repeat = true; 144 | return true; 145 | } 146 | 147 | // Header (cont.) 148 | if (!matchSpace(results->rawbuf[offset++], NEC_HDR_SPACE)) 149 | return false; 150 | // Data 151 | for (uint16_t i = 0; i < nbits; i++, offset++) { 152 | if (!matchMark(results->rawbuf[offset++], NEC_BIT_MARK)) 153 | return false; 154 | if (matchSpace(results->rawbuf[offset], NEC_ONE_SPACE)) 155 | data = (data << 1) | 1; 156 | else if (matchSpace(results->rawbuf[offset], NEC_ZERO_SPACE)) 157 | data <<= 1; 158 | else 159 | return false; 160 | } 161 | // Footer 162 | if (!matchMark(results->rawbuf[offset++], NEC_BIT_MARK)) 163 | return false; 164 | if (offset <= results->rawlen && 165 | !matchAtLeast(results->rawbuf[offset], NEC_MIN_GAP)) 166 | return false; 167 | 168 | // Compliance 169 | // Calculate command and optionally enforce integrity checking. 170 | uint8_t command = (data & 0xFF00) >> 8; 171 | // Command is sent twice, once as plain and then inverted. 172 | if ((command ^ 0xFF) != (data & 0xFF)) { 173 | if (strict) 174 | return false; // Command integrity failed. 175 | command = 0; // The command value isn't valid, so default to zero. 176 | } 177 | 178 | // Success 179 | results->bits = nbits; 180 | results->value = data; 181 | results->decode_type = NEC; 182 | // NEC command and address are technically in LSB first order so the 183 | // final versions have to be reversed. 184 | results->command = reverseBits(command, 8); 185 | // Normal NEC protocol has an 8 bit address sent, followed by it inverted. 186 | uint8_t address = (data & 0xFF000000) >> 24; 187 | uint8_t address_inverted = (data & 0x00FF0000) >> 16; 188 | if (address == (address_inverted ^ 0xFF)) 189 | // Inverted, so it is normal NEC protocol. 190 | results->address = reverseBits(address, 8); 191 | else // Not inverted, so must be Extended NEC protocol, thus 16 bit address. 192 | results->address = reverseBits((data >> 16) & UINT16_MAX, 16); 193 | return true; 194 | } 195 | #endif 196 | -------------------------------------------------------------------------------- /src/IRsend.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009 Ken Shirriff 2 | // Copyright 2015 Mark Szabo 3 | // Copyright 2017 David Conran 4 | #ifndef IRSEND_H_ 5 | #define IRSEND_H_ 6 | 7 | #define __STDC_LIMIT_MACROS 8 | #include 9 | #include "IRremoteESP8266.h" 10 | 11 | // Originally from https://github.com/shirriff/Arduino-IRremote/ 12 | // Updated by markszabo (https://github.com/markszabo/IRremoteESP8266) for 13 | // sending IR code on ESP8266 14 | 15 | #if TEST || UNIT_TEST 16 | #define VIRTUAL virtual 17 | #else 18 | #define VIRTUAL 19 | #endif 20 | 21 | // Constants 22 | // Offset (in microseconds) to use in Period time calculations to account for 23 | // code excution time in producing the software PWM signal. 24 | // Value determined in https://github.com/markszabo/IRremoteESP8266/issues/62 25 | #define PERIOD_OFFSET -3 26 | #define DUTY_DEFAULT 50 27 | 28 | // Classes 29 | class IRsend { 30 | public: 31 | explicit IRsend(uint16_t IRsendPin, bool inverted = false); 32 | void begin(); 33 | void enableIROut(uint32_t freq, uint8_t duty = DUTY_DEFAULT); 34 | VIRTUAL uint16_t mark(uint16_t usec); 35 | VIRTUAL void space(uint32_t usec); 36 | void calibrate(uint16_t hz = 38000U); 37 | void sendRaw(uint16_t buf[], uint16_t len, uint16_t hz); 38 | void sendData(uint16_t onemark, uint32_t onespace, uint16_t zeromark, 39 | uint32_t zerospace, uint64_t data, uint16_t nbits, 40 | bool MSBfirst = true); 41 | void send(uint16_t type, uint64_t data, uint16_t nbits); 42 | #if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO) 43 | void sendNEC(uint64_t data, uint16_t nbits = NEC_BITS, uint16_t repeat = 0); 44 | uint32_t encodeNEC(uint16_t address, uint16_t command); 45 | #endif 46 | #if SEND_SONY 47 | // sendSony() should typically be called with repeat=2 as Sony devices 48 | // expect the code to be sent at least 3 times. (code + 2 repeats = 3 codes) 49 | // Legacy use of this procedure was to only send a single code so call it with 50 | // repeat=0 for backward compatibility. As of v2.0 it defaults to sending 51 | // a Sony command that will be accepted be a device. 52 | void sendSony(uint64_t data, uint16_t nbits = SONY_20_BITS, 53 | uint16_t repeat = SONY_MIN_REPEAT); 54 | uint32_t encodeSony(uint16_t nbits, uint16_t command, uint16_t address, 55 | uint16_t extended = 0); 56 | #endif 57 | #if SEND_SHERWOOD 58 | void sendSherwood(uint64_t data, uint16_t nbits = SHERWOOD_BITS, 59 | uint16_t repeat = SHERWOOD_MIN_REPEAT); 60 | #endif 61 | #if SEND_SAMSUNG 62 | void sendSAMSUNG(uint64_t data, uint16_t nbits = SAMSUNG_BITS, 63 | uint16_t repeat = 0); 64 | uint32_t encodeSAMSUNG(uint8_t customer, uint8_t command); 65 | #endif 66 | #if SEND_LG 67 | void sendLG(uint64_t data, uint16_t nbits = LG_BITS, uint16_t repeat = 0); 68 | uint32_t encodeLG(uint16_t address, uint16_t command); 69 | #endif 70 | #if (SEND_SHARP || SEND_DENON) 71 | uint32_t encodeSharp(uint16_t address, uint16_t command, 72 | uint16_t expansion = 1, uint16_t check = 0, 73 | bool MSBfirst = false); 74 | void sendSharp(uint16_t address, uint16_t command, 75 | uint16_t nbits = SHARP_BITS, uint16_t repeat = 0); 76 | void sendSharpRaw(uint64_t data, uint16_t nbits = SHARP_BITS, 77 | uint16_t repeat = 0); 78 | #endif 79 | #if SEND_JVC 80 | void sendJVC(uint64_t data, uint16_t nbits = JVC_BITS, uint16_t repeat = 0); 81 | uint16_t encodeJVC(uint8_t address, uint8_t command); 82 | #endif 83 | #if SEND_DENON 84 | void sendDenon(uint64_t data, uint16_t nbits = DENON_BITS, 85 | uint16_t repeat = 0); 86 | #endif 87 | #if SEND_SANYO 88 | uint64_t encodeSanyoLC7461(uint16_t address, uint8_t command); 89 | void sendSanyoLC7461(uint64_t data, uint16_t nbits = SANYO_LC7461_BITS, 90 | uint16_t repeat = 0); 91 | #endif 92 | #if SEND_DISH 93 | // sendDISH() should typically be called with repeat=3 as DISH devices 94 | // expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes) 95 | // Legacy use of this procedure was only to send a single code 96 | // so use repeat=0 for backward compatibility. 97 | void sendDISH(uint64_t data, uint16_t nbits = DISH_BITS, 98 | uint16_t repeat = DISH_MIN_REPEAT); 99 | #endif 100 | #if (SEND_PANASONIC || SEND_DENON) 101 | void sendPanasonic64(uint64_t data, uint16_t nbits = PANASONIC_BITS, 102 | uint16_t repeat = 0); 103 | void sendPanasonic(uint16_t address, uint32_t data, 104 | uint16_t nbits = PANASONIC_BITS, uint16_t repeat = 0); 105 | uint64_t encodePanasonic(uint16_t manufacturer, uint8_t device, 106 | uint8_t subdevice, uint8_t function); 107 | #endif 108 | #if SEND_RC5 109 | void sendRC5(uint64_t data, uint16_t nbits = RC5X_BITS, uint16_t repeat = 0); 110 | uint16_t encodeRC5(uint8_t address, uint8_t command, 111 | bool key_released = false); 112 | uint16_t encodeRC5X(uint8_t address, uint8_t command, 113 | bool key_released = false); 114 | uint64_t toggleRC5(uint64_t data); 115 | #endif 116 | #if SEND_RC6 117 | void sendRC6(uint64_t data, uint16_t nbits = RC6_MODE0_BITS, 118 | uint16_t repeat = 0); 119 | uint64_t encodeRC6(uint32_t address, uint8_t command, 120 | uint16_t mode = RC6_MODE0_BITS); 121 | uint64_t toggleRC6(uint64_t data, uint16_t nbits = RC6_MODE0_BITS); 122 | #endif 123 | #if SEND_RCMM 124 | void sendRCMM(uint64_t data, uint16_t nbits = RCMM_BITS, uint16_t repeat = 0); 125 | #endif 126 | #if SEND_COOLIX 127 | void sendCOOLIX(uint64_t data, uint16_t nbits = COOLIX_BITS, 128 | uint16_t repeat = 0); 129 | #endif 130 | #if SEND_WHYNTER 131 | void sendWhynter(uint64_t data, uint16_t nbits = WHYNTER_BITS, 132 | uint16_t repeat = 0); 133 | #endif 134 | #if SEND_MITSUBISHI 135 | void sendMitsubishi(uint64_t data, uint16_t nbits = MITSUBISHI_BITS, 136 | uint16_t repeat = MITSUBISHI_MIN_REPEAT); 137 | #endif 138 | #if SEND_MITSUBISHI_AC 139 | void sendMitsubishiAC(unsigned char data[], 140 | uint16_t nbytes = MITSUBISHI_AC_STATE_LENGTH, 141 | uint16_t repeat = MITSUBISHI_AC_MIN_REPEAT); 142 | #endif 143 | #if SEND_GLOBALCACHE 144 | void sendGC(uint16_t buf[], uint16_t len); 145 | #endif 146 | #if SEND_KELVINATOR 147 | void sendKelvinator(unsigned char data[], 148 | uint16_t nbytes = KELVINATOR_STATE_LENGTH, 149 | uint16_t repeat = 0); 150 | #endif 151 | #if SEND_DAIKIN 152 | void sendDaikin(unsigned char data[], 153 | uint16_t nbytes = DAIKIN_COMMAND_LENGTH, 154 | uint16_t repeat = 0); 155 | #endif 156 | #if SEND_AIWA_RC_T501 157 | void sendAiwaRCT501(uint64_t data, uint16_t nbits = AIWA_RC_T501_BITS, 158 | uint16_t repeat = AIWA_RC_T501_MIN_REPEAT); 159 | #endif 160 | #if SEND_GREE 161 | void sendGree(uint64_t data, uint16_t nbits = GREE_BITS, uint16_t repeat = 0); 162 | void sendGree(uint8_t data[], uint16_t nbytes = GREE_STATE_LENGTH, 163 | uint16_t repeat = 0); 164 | #endif 165 | 166 | protected: 167 | #ifdef UNIT_TEST 168 | #ifndef HIGH 169 | #define HIGH 0x1 170 | #endif 171 | #ifndef LOW 172 | #define LOW 0x0 173 | #endif 174 | #endif // UNIT_TEST 175 | uint8_t outputOn; 176 | uint8_t outputOff; 177 | 178 | private: 179 | uint16_t onTimePeriod; 180 | uint16_t offTimePeriod; 181 | uint16_t IRpin; 182 | int8_t periodOffset; 183 | void ledOff(); 184 | uint32_t calcUSecPeriod(uint32_t hz); 185 | }; 186 | 187 | #endif // IRSEND_H_ 188 | -------------------------------------------------------------------------------- /src/ir_LG.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Darryl Smith 2 | // Copyright 2015 cheaplin 3 | // Copyright 2017 David Conran 4 | 5 | #include "ir_LG.h" 6 | #include 7 | #include "IRrecv.h" 8 | #include "IRsend.h" 9 | #include "IRtimer.h" 10 | 11 | // L GGGG 12 | // L G 13 | // L G GG 14 | // L G G 15 | // LLLLL GGG 16 | 17 | // LG decode originally added by Darryl Smith (based on the JVC protocol) 18 | // LG send originally added by https://github.com/chaeplin 19 | 20 | // Constants 21 | #define LG_HDR_MARK 8000U 22 | #define LG_HDR_SPACE 4000U 23 | #define LG_BIT_MARK 560U 24 | #define LG_ONE_SPACE 1690U 25 | #define LG_ZERO_SPACE 560U 26 | #define LG_RPT_SPACE 2250U 27 | #define LG_MIN_GAP 40000U 28 | #define LG_MIN_MESSAGE_LENGTH 108000UL 29 | #define LG32_HDR_MARK 4500U 30 | #define LG32_HDR_SPACE 4500U 31 | #define LG32_RPT_HDR_MARK 9000U 32 | 33 | #if (SEND_LG || DECODE_LG) 34 | // Calculate the rolling 4-bit wide checksum over all of the data. 35 | // Args: 36 | // data: The value to be checksum'ed. 37 | // Returns: 38 | // A 4-bit checksum. 39 | uint8_t calcLGChecksum(uint16_t data) { 40 | return(((data >> 12) + ((data >> 8) & 0xF) + ((data >> 4) & 0xF) + 41 | (data & 0xF)) & 0xF); 42 | } 43 | #endif 44 | 45 | #if SEND_LG 46 | // Send an LG formatted message. 47 | // 48 | // Args: 49 | // data: The contents of the message you want to send. 50 | // nbits: The bit size of the message being sent. 51 | // Typically LG_BITS or LG32_BITS. 52 | // repeat: The number of times you want the message to be repeated. 53 | // 54 | // Status: Beta / Should be working. 55 | // 56 | // Notes: 57 | // LG has a separate message to indicate a repeat, like NEC does. 58 | void IRsend::sendLG(uint64_t data, uint16_t nbits, uint16_t repeat) { 59 | // Set IR carrier frequency 60 | enableIROut(38); 61 | 62 | uint16_t repeatHeaderMark = 0; 63 | IRtimer usecTimer = IRtimer(); 64 | 65 | if (nbits >= LG32_BITS) { 66 | // LG 32bit protocol is near identical to Samsung except for repeats. 67 | sendSAMSUNG(data, nbits, 0); // Send it as a single Samsung message. 68 | repeatHeaderMark = LG32_RPT_HDR_MARK; 69 | repeat++; 70 | } else { 71 | // LG (28-bit) protocol. 72 | repeatHeaderMark = LG_HDR_MARK; 73 | // Header 74 | usecTimer.reset(); 75 | mark(LG_HDR_MARK); 76 | space(LG_HDR_SPACE); 77 | // Data 78 | sendData(LG_BIT_MARK, LG_ONE_SPACE, LG_BIT_MARK, LG_ZERO_SPACE, 79 | data, nbits, true); 80 | // Footer 81 | mark(LG_BIT_MARK); 82 | space(std::max((uint32_t) (LG_MIN_MESSAGE_LENGTH - usecTimer.elapsed()), 83 | (uint32_t) LG_MIN_GAP)); 84 | } 85 | 86 | // Repeat 87 | // Protocol has a mandatory repeat-specific code sent after every command. 88 | for (uint16_t i = 0; i < repeat; i++) { 89 | usecTimer.reset(); 90 | mark(repeatHeaderMark); 91 | space(LG_RPT_SPACE); 92 | mark(LG_BIT_MARK); 93 | space(std::max((uint32_t) LG_MIN_MESSAGE_LENGTH - usecTimer.elapsed(), 94 | (uint32_t) LG_MIN_GAP)); 95 | } 96 | } 97 | 98 | // Construct a raw 28-bit LG message from the supplied address & command. 99 | // 100 | // Args: 101 | // address: The address code. 102 | // command: The command code. 103 | // Returns: 104 | // A raw 28-bit LG message suitable for sendLG(). 105 | // 106 | // Status: BETA / Should work. 107 | // 108 | // Notes: 109 | // e.g. Sequence of bits = address + command + checksum. 110 | uint32_t IRsend::encodeLG(uint16_t address, uint16_t command) { 111 | return ((address << 20) | (command << 4) | calcLGChecksum(command)); 112 | } 113 | #endif 114 | 115 | #if DECODE_LG 116 | // Decode the supplied LG message. 117 | // LG protocol has a repeat code which is 4 items long. 118 | // Even though the protocol has 28/32 bits of data, only 24/28 bits are 119 | // distinct. 120 | // In transmission order, the 28/32 bits are constructed as follows: 121 | // 8/12 bits of address + 16 bits of command + 4 bits of checksum. 122 | // 123 | // Args: 124 | // results: Ptr to the data to decode and where to store the decode result. 125 | // nbits: Nr. of bits to expect in the data portion. 126 | // Typically LG_BITS or LG32_BITS. 127 | // strict: Flag to indicate if we strictly adhere to the specification. 128 | // Returns: 129 | // boolean: True if it can decode it, false if it can't. 130 | // 131 | // Status: BETA / Should work. 132 | // 133 | // Note: 134 | // LG 32bit protocol appears near identical to the Samsung protocol. 135 | // They possibly differ on how they repeat and initial HDR mark. 136 | 137 | // Ref: 138 | // https://funembedded.wordpress.com/2014/11/08/ir-remote-control-for-lg-conditioner-using-stm32f302-mcu-on-mbed-platform/ 139 | bool IRrecv::decodeLG(decode_results *results, uint16_t nbits, bool strict) { 140 | if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1 && results->rawlen != 4) 141 | return false; // Can't possibly be a valid LG message. 142 | if (strict && nbits != LG_BITS && nbits != LG32_BITS) 143 | return false; // Doesn't comply with expected LG protocol. 144 | 145 | uint64_t data = 0; 146 | uint16_t offset = OFFSET_START; 147 | 148 | // Header 149 | if (!matchMark(results->rawbuf[offset], LG_HDR_MARK) && 150 | !matchMark(results->rawbuf[offset], LG32_HDR_MARK)) 151 | return false; 152 | offset++; 153 | if (!matchSpace(results->rawbuf[offset], LG_HDR_SPACE) && 154 | !matchMark(results->rawbuf[offset], LG32_HDR_SPACE)) 155 | return false; 156 | offset++; 157 | // Data 158 | for (uint16_t i = 0; i < nbits; i++, offset++) { 159 | if (!matchMark(results->rawbuf[offset++], LG_BIT_MARK)) 160 | return false; 161 | if (matchSpace(results->rawbuf[offset], LG_ONE_SPACE)) 162 | data = (data << 1) | 1; // 1 163 | else if (matchSpace(results->rawbuf[offset], LG_ZERO_SPACE)) 164 | data <<= 1; // 0 165 | else 166 | return false; 167 | } 168 | // Footer 169 | if (!matchMark(results->rawbuf[offset++], LG_BIT_MARK)) 170 | return false; 171 | if (offset <= results->rawlen && 172 | !matchAtLeast(results->rawbuf[offset], LG_MIN_GAP)) 173 | return false; 174 | 175 | // Repeat 176 | if (nbits >= LG32_BITS) { 177 | // If we are expecting the LG 32-bit protocol, there is always 178 | // a repeat message. So, check for it. 179 | #ifndef UNIT_TEST 180 | if (!matchSpace(results->rawbuf[offset], LG_MIN_GAP)) 181 | #else 182 | if (!(matchSpace(results->rawbuf[offset], LG_MIN_MESSAGE_LENGTH) || 183 | matchSpace(results->rawbuf[offset], 65500) || 184 | matchSpace(results->rawbuf[offset], LG_MIN_GAP))) 185 | #endif // UNIT_TEST 186 | return false; 187 | offset++; 188 | if (!matchMark(results->rawbuf[offset++], LG32_RPT_HDR_MARK)) 189 | return false; 190 | if (!matchSpace(results->rawbuf[offset++], LG_RPT_SPACE)) 191 | return false; 192 | if (!matchMark(results->rawbuf[offset++], LG_BIT_MARK)) 193 | return false; 194 | if (!matchAtLeast(results->rawbuf[offset], LG_MIN_GAP)) 195 | return false; 196 | } 197 | 198 | // Compliance 199 | uint16_t command = (data >> 4) & 0xFFFF; // The 16 bits before the checksum. 200 | 201 | if (strict && (data & 0xF) != calcLGChecksum(command)) 202 | return false; // The last 4 bits sent are the expected checksum. 203 | 204 | // Success 205 | results->decode_type = LG; 206 | results->bits = nbits; 207 | results->value = data; 208 | results->command = command; 209 | results->address = data >> 20; // The bits before the command. 210 | return true; 211 | } 212 | #endif 213 | -------------------------------------------------------------------------------- /src/IRremoteESP8266.h: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | * IRremote for ESP8266 3 | * 4 | * Based on the IRremote library for Arduino by Ken Shirriff 5 | * Version 0.11 August, 2009 6 | * Copyright 2009 Ken Shirriff 7 | * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html 8 | * 9 | * Edited by Mitra to add new controller SANYO 10 | * 11 | * Interrupt code based on NECIRrcv by Joe Knapp 12 | * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 13 | * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ 14 | * 15 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 16 | * LG added by Darryl Smith (based on the JVC protocol) 17 | * Whynter A/C ARC-110WD added by Francesco Meschia 18 | * Coolix A/C / heatpump added by (send) bakrus & (decode) crankyoldgit 19 | * Denon: sendDenon, decodeDenon added by Massimiliano Pinto 20 | (from https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp) 21 | * Kelvinator A/C and Sherwood added by crankyoldgit 22 | * Mitsubishi (TV) sending added by crankyoldgit 23 | * Mitsubishi A/C added by crankyoldgit 24 | * (derived from https://github.com/r45635/HVAC-IR-Control) 25 | * DISH decode by marcosamarinho 26 | * Gree Heatpump sending added by Ville Skyttä (scop) 27 | * (derived from https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp) 28 | * Updated by markszabo (https://github.com/markszabo/IRremoteESP8266) for sending IR code on ESP8266 29 | * Updated by Sebastien Warin (http://sebastien.warin.fr) for receiving IR code on ESP8266 30 | * 31 | * Updated by sillyfrog for Daikin, adopted from 32 | * (https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/) 33 | * 34 | * GPL license, all text above must be included in any redistribution 35 | ****************************************************/ 36 | 37 | #ifndef IRREMOTEESP8266_H_ 38 | #define IRREMOTEESP8266_H_ 39 | 40 | #define __STDC_LIMIT_MACROS 41 | #include 42 | #ifdef UNIT_TEST 43 | #include 44 | #endif 45 | 46 | // Supported IR protocols 47 | // Each protocol you include costs memory and, during decode, costs time 48 | // Disable (set to false) all the protocols you do not need/want! 49 | // 50 | #define DECODE_NEC true 51 | #define SEND_NEC true 52 | 53 | #define DECODE_SHERWOOD true // Doesn't exist. Actually is DECODE_NEC 54 | #define SEND_SHERWOOD true 55 | 56 | #define DECODE_RC5 true 57 | #define SEND_RC5 true 58 | 59 | #define DECODE_RC6 true 60 | #define SEND_RC6 true 61 | 62 | #define DECODE_RCMM true 63 | #define SEND_RCMM true 64 | 65 | #define DECODE_SONY true 66 | #define SEND_SONY true 67 | 68 | #define DECODE_PANASONIC true 69 | #define SEND_PANASONIC true 70 | 71 | #define DECODE_JVC true 72 | #define SEND_JVC true 73 | 74 | #define DECODE_SAMSUNG true 75 | #define SEND_SAMSUNG true 76 | 77 | #define DECODE_WHYNTER true 78 | #define SEND_WHYNTER true 79 | 80 | #define DECODE_AIWA_RC_T501 true 81 | #define SEND_AIWA_RC_T501 true 82 | 83 | #define DECODE_LG true 84 | #define SEND_LG true 85 | 86 | #define DECODE_SANYO true 87 | #define SEND_SANYO true 88 | 89 | #define DECODE_MITSUBISHI true 90 | #define SEND_MITSUBISHI true 91 | 92 | #define DECODE_DISH true 93 | #define SEND_DISH true 94 | 95 | #define DECODE_SHARP true 96 | #define SEND_SHARP true 97 | 98 | #define DECODE_DENON true 99 | #define SEND_DENON true 100 | 101 | #define DECODE_KELVINATOR false // Not written. 102 | #define SEND_KELVINATOR true 103 | 104 | #define DECODE_MITSUBISHI_AC false // Not written. 105 | #define SEND_MITSUBISHI_AC true 106 | 107 | #define DECODE_DAIKIN false // Not finished. 108 | #define SEND_DAIKIN true 109 | 110 | #define DECODE_COOLIX true 111 | #define SEND_COOLIX true 112 | 113 | #define DECODE_GLOBALCACHE false // Not written. 114 | #define SEND_GLOBALCACHE true 115 | 116 | #define DECODE_GREE false // Not written. 117 | #define SEND_GREE true 118 | /* 119 | * Always add to the end of the list and should never remove entries 120 | * or change order. Projects may save the type number for later usage 121 | * so numbering should always stay the same. 122 | */ 123 | enum decode_type_t { 124 | UNKNOWN = -1, 125 | UNUSED = 0, 126 | RC5, 127 | RC6, 128 | NEC, 129 | SONY, 130 | PANASONIC, 131 | JVC, 132 | SAMSUNG, 133 | WHYNTER, 134 | AIWA_RC_T501, 135 | LG, 136 | SANYO, 137 | MITSUBISHI, 138 | DISH, 139 | SHARP, 140 | COOLIX, 141 | DAIKIN, 142 | DENON, 143 | KELVINATOR, 144 | SHERWOOD, 145 | MITSUBISHI_AC, 146 | RCMM, 147 | SANYO_LC7461, 148 | RC5X, 149 | GREE 150 | }; 151 | 152 | // Message lengths & required repeat values 153 | #define AIWA_RC_T501_BITS 15U 154 | #define AIWA_RC_T501_MIN_REPEAT 1U 155 | #define COOLIX_BITS 24U 156 | #define DAIKIN_BITS 99U 157 | #define DAIKIN_COMMAND_LENGTH 27U 158 | #define DENON_BITS SHARP_BITS 159 | #define DENON_48_BITS PANASONIC_BITS 160 | #define DENON_LEGACY_BITS 14U 161 | #define DISH_BITS 16U 162 | #define DISH_MIN_REPEAT 3U 163 | #define GREE_STATE_LENGTH 8U 164 | #define GREE_BITS (GREE_STATE_LENGTH * 8) 165 | #define JVC_BITS 16U 166 | #define KELVINATOR_STATE_LENGTH 16U 167 | #define LG_BITS 28U 168 | #define LG32_BITS 32U 169 | #define MITSUBISHI_BITS 16U 170 | // TODO(anyone): Verify that the Mitsubishi repeat is really needed. 171 | #define MITSUBISHI_MIN_REPEAT 1U // Based on marcosamarinho's code. 172 | #define MITSUBISHI_AC_STATE_LENGTH 18U 173 | #define MITSUBISHI_AC_MIN_REPEAT 1U 174 | #define NEC_BITS 32U 175 | #define PANASONIC_BITS 48U 176 | #define PANASONIC_MANUFACTURER 0x4004ULL 177 | #define RC5_RAW_BITS 14U 178 | #define RC5_BITS RC5_RAW_BITS - 2U 179 | #define RC5X_BITS RC5_RAW_BITS - 1U 180 | #define RC6_MODE0_BITS 20U // Excludes the 'start' bit. 181 | #define RC6_36_BITS 36U // Excludes the 'start' bit. 182 | #define RCMM_BITS 24U 183 | #define SAMSUNG_BITS 32U 184 | #define SANYO_SA8650B_BITS 12U 185 | #define SANYO_LC7461_ADDRESS_BITS 13U 186 | #define SANYO_LC7461_COMMAND_BITS 8U 187 | #define SANYO_LC7461_BITS ((SANYO_LC7461_ADDRESS_BITS + \ 188 | SANYO_LC7461_COMMAND_BITS) * 2) 189 | #define SHARP_ADDRESS_BITS 5U 190 | #define SHARP_COMMAND_BITS 8U 191 | #define SHARP_BITS (SHARP_ADDRESS_BITS + SHARP_COMMAND_BITS + 2) // 15U 192 | #define SHERWOOD_BITS NEC_BITS 193 | #define SHERWOOD_MIN_REPEAT 1U 194 | #define SONY_12_BITS 12U 195 | #define SONY_15_BITS 15U 196 | #define SONY_20_BITS 20U 197 | #define SONY_MIN_BITS SONY_12_BITS 198 | #define SONY_MIN_REPEAT 2U 199 | #define WHYNTER_BITS 32U 200 | 201 | // Turn on Debugging information by uncommenting the following line. 202 | // #define DEBUG 1 203 | 204 | #ifdef DEBUG 205 | #ifdef UNIT_TEST 206 | #define DPRINT(x) do { std::cout << x; } while (0) 207 | #define DPRINTLN(x) do { std::cout << x << std::endl; } while (0) 208 | #endif // UNIT_TEST 209 | #ifdef ARDUINO 210 | #define DPRINT(x) do { Serial.print(x); } while (0) 211 | #define DPRINTLN(x) do { Serial.println(x); } while (0) 212 | #endif // ARDUINO 213 | #else // DEBUG 214 | #define DPRINT(x) 215 | #define DPRINTLN(x) 216 | #endif // DEBUG 217 | 218 | #endif // IRREMOTEESP8266_H_ 219 | -------------------------------------------------------------------------------- /test/ir_RCMM_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRsend.h" 4 | #include "IRsend_test.h" 5 | #include "gtest/gtest.h" 6 | 7 | // Tests for sendRCMM(). 8 | 9 | // Test sending typical data only. 10 | TEST(TestSendRCMM, SendDataOnly) { 11 | IRsendTest irsend(4); 12 | irsend.begin(); 13 | 14 | irsend.reset(); 15 | irsend.sendRCMM(0xe0a600); 16 | EXPECT_EQ("m416s277" 17 | "m166s777m166s611m166s277m166s277" 18 | "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" 19 | "m166s27778", irsend.outputStr()); 20 | irsend.reset(); 21 | irsend.sendRCMM(0x28e0a600UL, 32); 22 | EXPECT_EQ("m416s277" 23 | "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" 24 | "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" 25 | "m166s27778", irsend.outputStr()); 26 | } 27 | 28 | // Test sending with different repeats. 29 | TEST(TestSendRCMM, SendWithRepeats) { 30 | IRsendTest irsend(4); 31 | irsend.begin(); 32 | 33 | irsend.reset(); 34 | irsend.sendRCMM(0x28e0a600, 32, 2); // 2 repeats. 35 | EXPECT_EQ("m416s277" 36 | "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" 37 | "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" 38 | "m166s27778" 39 | "m416s277" 40 | "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" 41 | "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" 42 | "m166s27778" 43 | "m416s277" 44 | "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" 45 | "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" 46 | "m166s27778", irsend.outputStr()); 47 | } 48 | 49 | // Test sending an atypical data size. 50 | TEST(TestSendRCMM, SendUsualSize) { 51 | IRsendTest irsend(4); 52 | irsend.begin(); 53 | 54 | irsend.reset(); 55 | irsend.sendRCMM(0xE0, 8); 56 | EXPECT_EQ("m416s277" 57 | "m166s777m166s611m166s277m166s277" 58 | "m166s27778", irsend.outputStr()); 59 | irsend.reset(); 60 | irsend.sendRCMM(0x28e0a60000UL, 40); 61 | EXPECT_EQ("m416s277" 62 | "m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277" 63 | "m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277" 64 | "m166s277m166s277m166s277m166s277m166s27778", irsend.outputStr()); 65 | } 66 | 67 | // Tests for decodeRCMM(). 68 | 69 | // Decode normal RCMM messages. 70 | TEST(TestDecodeRCMM, NormalDecodeWithStrict) { 71 | IRsendTest irsend(4); 72 | IRrecv irrecv(4); 73 | irsend.begin(); 74 | 75 | // Normal RCMM 24-bit message. 76 | irsend.reset(); 77 | irsend.sendRCMM(0xe0a600); 78 | irsend.makeDecodeResult(); 79 | ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, RCMM_BITS, true)); 80 | EXPECT_EQ(RCMM, irsend.capture.decode_type); 81 | EXPECT_EQ(RCMM_BITS, irsend.capture.bits); 82 | EXPECT_EQ(0xe0a600, irsend.capture.value); 83 | EXPECT_EQ(0x0, irsend.capture.address); 84 | EXPECT_EQ(0x0, irsend.capture.command); 85 | EXPECT_FALSE(irsend.capture.repeat); 86 | 87 | // Normal RCMM 12-bit message. 88 | irsend.reset(); 89 | irsend.sendRCMM(0x600, 12); 90 | irsend.makeDecodeResult(); 91 | ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, 12, true)); 92 | EXPECT_EQ(RCMM, irsend.capture.decode_type); 93 | EXPECT_EQ(12, irsend.capture.bits); 94 | EXPECT_EQ(0x600, irsend.capture.value); 95 | EXPECT_EQ(0x0, irsend.capture.address); 96 | EXPECT_EQ(0x0, irsend.capture.command); 97 | EXPECT_FALSE(irsend.capture.repeat); 98 | 99 | // Normal RCMM 32-bit message. 100 | irsend.reset(); 101 | irsend.sendRCMM(0x28e0a600, 32); 102 | irsend.makeDecodeResult(); 103 | ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, 32, true)); 104 | EXPECT_EQ(RCMM, irsend.capture.decode_type); 105 | EXPECT_EQ(32, irsend.capture.bits); 106 | EXPECT_EQ(0x28e0a600, irsend.capture.value); 107 | EXPECT_EQ(0x0, irsend.capture.address); 108 | EXPECT_EQ(0x0, irsend.capture.command); 109 | EXPECT_FALSE(irsend.capture.repeat); 110 | } 111 | 112 | // Decodes should fail for illegal bit sizes when in strict mode. 113 | TEST(TestDecodeRCMM, IllegalDecodeWithStrict) { 114 | IRsendTest irsend(4); 115 | IRrecv irrecv(4); 116 | irsend.begin(); 117 | 118 | // Illegal RCMM 8-bit message. 119 | irsend.reset(); 120 | irsend.sendRCMM(0x0, 8); 121 | irsend.makeDecodeResult(); 122 | ASSERT_FALSE(irrecv.decodeRCMM(&irsend.capture, 8, true)); 123 | ASSERT_FALSE(irrecv.decodeRCMM(&irsend.capture, 12, true)); 124 | 125 | // Illegal RCMM 36-bit message. 126 | irsend.reset(); 127 | irsend.sendRCMM(0x0, 36); 128 | irsend.makeDecodeResult(); 129 | ASSERT_FALSE(irrecv.decodeRCMM(&irsend.capture, 12, true)); 130 | ASSERT_FALSE(irrecv.decodeRCMM(&irsend.capture, 36, true)); 131 | } 132 | 133 | // Decodes without strict mode. 134 | TEST(TestDecodeRCMM, DecodeWithoutStrict) { 135 | IRsendTest irsend(4); 136 | IRrecv irrecv(4); 137 | irsend.begin(); 138 | 139 | // Illegal RCMM 8-bit message. 140 | irsend.reset(); 141 | irsend.sendRCMM(0x55, 8); 142 | irsend.makeDecodeResult(); 143 | ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, 8, false)); 144 | EXPECT_EQ(RCMM, irsend.capture.decode_type); 145 | EXPECT_EQ(8, irsend.capture.bits); 146 | EXPECT_EQ(0x55, irsend.capture.value); 147 | EXPECT_EQ(0x0, irsend.capture.address); 148 | EXPECT_EQ(0x0, irsend.capture.command); 149 | ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, 12, false)); 150 | EXPECT_EQ(RCMM, irsend.capture.decode_type); 151 | EXPECT_EQ(8, irsend.capture.bits); 152 | EXPECT_EQ(0x55, irsend.capture.value); 153 | EXPECT_EQ(0x0, irsend.capture.address); 154 | EXPECT_EQ(0x0, irsend.capture.command); 155 | 156 | // Illiegal RCMM 36-bit message. 157 | irsend.reset(); 158 | irsend.sendRCMM(0x123456789, 36); 159 | irsend.makeDecodeResult(); 160 | ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, 12, false)); 161 | EXPECT_EQ(RCMM, irsend.capture.decode_type); 162 | EXPECT_EQ(36, irsend.capture.bits); 163 | EXPECT_EQ(0x123456789, irsend.capture.value); 164 | EXPECT_EQ(0x0, irsend.capture.address); 165 | EXPECT_EQ(0x0, irsend.capture.command); 166 | ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, 24, false)); 167 | EXPECT_EQ(36, irsend.capture.bits); 168 | EXPECT_EQ(0x123456789, irsend.capture.value); 169 | EXPECT_EQ(0x0, irsend.capture.address); 170 | EXPECT_EQ(0x0, irsend.capture.command); 171 | ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, 36, false)); 172 | EXPECT_EQ(RCMM, irsend.capture.decode_type); 173 | EXPECT_EQ(36, irsend.capture.bits); 174 | EXPECT_EQ(0x123456789, irsend.capture.value); 175 | EXPECT_EQ(0x0, irsend.capture.address); 176 | EXPECT_EQ(0x0, irsend.capture.command); 177 | } 178 | 179 | // Decode (non-standard) 64-bit messages. 180 | TEST(TestDecodeRCMM, Decode64BitMessages) { 181 | IRsendTest irsend(4); 182 | IRrecv irrecv(4); 183 | irsend.begin(); 184 | 185 | irsend.reset(); 186 | // Illegal value & size RCMM 64-bit message. 187 | irsend.sendRCMM(0xFEDCBA9876543210, 64); 188 | irsend.makeDecodeResult(); 189 | // Should work with a 'normal' match (not strict) 190 | ASSERT_TRUE(irrecv.decodeRCMM(&irsend.capture, 64, false)); 191 | EXPECT_EQ(RCMM, irsend.capture.decode_type); 192 | EXPECT_EQ(64, irsend.capture.bits); 193 | EXPECT_EQ(0xFEDCBA9876543210, irsend.capture.value); 194 | EXPECT_EQ(0, irsend.capture.address); 195 | EXPECT_EQ(0, irsend.capture.command); 196 | } 197 | 198 | // Fail to decode a non-RCMM example via GlobalCache 199 | TEST(TestDecodeRCMM, FailToDecodeNonRCMMExample) { 200 | IRsendTest irsend(4); 201 | IRrecv irrecv(4); 202 | irsend.begin(); 203 | 204 | irsend.reset(); 205 | // Modified a few entries to unexpected values, based on previous test case. 206 | uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, 207 | 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, 208 | 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; 209 | irsend.sendGC(gc_test, 39); 210 | irsend.makeDecodeResult(); 211 | 212 | ASSERT_FALSE(irrecv.decodeRCMM(&irsend.capture)); 213 | ASSERT_FALSE(irrecv.decodeRCMM(&irsend.capture, RCMM_BITS, false)); 214 | } 215 | -------------------------------------------------------------------------------- /test/ir_Gree_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRsend.h" 4 | #include "IRsend_test.h" 5 | #include "gtest/gtest.h" 6 | 7 | // Tests for sendGree(). 8 | 9 | // Test sending typical data only. 10 | TEST(TestSendGreeChars, SendData) { 11 | IRsendTest irsend(4); 12 | irsend.begin(); 13 | 14 | uint8_t gree_code[GREE_STATE_LENGTH] = { 15 | 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; 16 | irsend.reset(); 17 | irsend.sendGree(gree_code); 18 | EXPECT_EQ( 19 | "m9000s4000" 20 | "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" 21 | "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" 22 | "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" 23 | "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" 24 | "m620s540m620s1600m620s540" 25 | "m620s19000" 26 | "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" 27 | "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" 28 | "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" 29 | "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" 30 | "m620s19000", irsend.outputStr()); 31 | } 32 | 33 | TEST(TestSendGreeUint64, SendData) { 34 | IRsendTest irsend(4); 35 | irsend.begin(); 36 | 37 | irsend.reset(); 38 | irsend.sendGree(0x1234567890ABCDEF); 39 | EXPECT_EQ( 40 | "m9000s4000" 41 | "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" 42 | "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" 43 | "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" 44 | "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" 45 | "m620s540m620s1600m620s540" 46 | "m620s19000" 47 | "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" 48 | "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" 49 | "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" 50 | "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" 51 | "m620s19000", irsend.outputStr()); 52 | } 53 | 54 | // Test sending with repeats. 55 | TEST(TestSendGreeChars, SendWithRepeats) { 56 | IRsendTest irsend(4); 57 | irsend.begin(); 58 | 59 | irsend.reset(); 60 | uint8_t gree_code[GREE_STATE_LENGTH] = { 61 | 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; 62 | irsend.reset(); 63 | 64 | irsend.sendGree(gree_code, GREE_STATE_LENGTH, 1); 65 | EXPECT_EQ( 66 | "m9000s4000" 67 | "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" 68 | "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" 69 | "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" 70 | "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" 71 | "m620s540m620s1600m620s540" 72 | "m620s19000" 73 | "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" 74 | "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" 75 | "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" 76 | "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" 77 | "m620s19000" 78 | "m9000s4000" 79 | "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" 80 | "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" 81 | "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" 82 | "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" 83 | "m620s540m620s1600m620s540" 84 | "m620s19000" 85 | "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" 86 | "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" 87 | "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" 88 | "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" 89 | "m620s19000", irsend.outputStr()); 90 | } 91 | 92 | TEST(TestSendGreeUint64, SendWithRepeats) { 93 | IRsendTest irsend(4); 94 | irsend.begin(); 95 | 96 | irsend.reset(); 97 | irsend.sendGree(0x1234567890ABCDEF, GREE_BITS, 1); 98 | EXPECT_EQ( 99 | "m9000s4000" 100 | "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" 101 | "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" 102 | "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" 103 | "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" 104 | "m620s540m620s1600m620s540" 105 | "m620s19000" 106 | "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" 107 | "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" 108 | "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" 109 | "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" 110 | "m620s19000" 111 | "m9000s4000" 112 | "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" 113 | "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" 114 | "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" 115 | "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" 116 | "m620s540m620s1600m620s540" 117 | "m620s19000" 118 | "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" 119 | "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" 120 | "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" 121 | "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" 122 | "m620s19000", irsend.outputStr()); 123 | } 124 | 125 | // Test sending atypical sizes. 126 | TEST(TestSendGreeChars, SendUnexpectedSizes) { 127 | IRsendTest irsend(4); 128 | irsend.begin(); 129 | 130 | uint8_t gree_short_code[GREE_STATE_LENGTH - 1] = { 131 | 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD}; 132 | uint8_t gree_long_code[GREE_STATE_LENGTH + 1] = { 133 | 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12}; 134 | irsend.reset(); 135 | irsend.sendGree(gree_short_code, GREE_STATE_LENGTH - 1); 136 | ASSERT_EQ("", irsend.outputStr()); 137 | 138 | irsend.reset(); 139 | irsend.sendGree(gree_long_code, GREE_STATE_LENGTH + 1); 140 | ASSERT_EQ( 141 | "m9000s4000" 142 | "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" 143 | "m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540" 144 | "m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540" 145 | "m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540" 146 | "m620s540m620s1600m620s540" 147 | "m620s19000" 148 | "m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600" 149 | "m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600" 150 | "m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600" 151 | "m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600" 152 | "m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540" 153 | "m620s19000", irsend.outputStr()); 154 | } 155 | 156 | TEST(TestSendGreeUint64, SendUnexpectedSizes) { 157 | IRsendTest irsend(4); 158 | irsend.begin(); 159 | 160 | irsend.reset(); 161 | irsend.sendGree(0x1234567890ABCDEF, GREE_BITS - 1); 162 | ASSERT_EQ("", irsend.outputStr()); 163 | 164 | irsend.reset(); 165 | irsend.sendGree(0x1234567890ABCDEF, GREE_BITS + 1); 166 | ASSERT_EQ("", irsend.outputStr()); 167 | } 168 | 169 | TEST(TestSendGree, CompareUint64ToCharResults) { 170 | IRsendTest irsend_chars(4); 171 | IRsendTest irsend_uint64(0); 172 | 173 | uint8_t gree_code[GREE_STATE_LENGTH] = { 174 | 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; 175 | 176 | irsend_chars.begin(); 177 | irsend_uint64.begin(); 178 | 179 | irsend_chars.reset(); 180 | irsend_uint64.reset(); 181 | irsend_chars.sendGree(gree_code); 182 | irsend_uint64.sendGree(0x1234567890ABCDEF); 183 | ASSERT_EQ(irsend_chars.outputStr(), irsend_uint64.outputStr()); 184 | 185 | uint8_t gree_zero_code[GREE_STATE_LENGTH] = { 186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 187 | irsend_chars.reset(); 188 | irsend_uint64.reset(); 189 | irsend_chars.sendGree(gree_zero_code); 190 | irsend_uint64.sendGree((uint64_t) 0x0); 191 | ASSERT_EQ(irsend_chars.outputStr(), irsend_uint64.outputStr()); 192 | } 193 | -------------------------------------------------------------------------------- /src/ir_Daikin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | An Arduino sketch to emulate IR Daikin ARC433** remote control unit 3 | Read more at: 4 | http://harizanov.com/2012/02/control-daikin-air-conditioner-over-the-internet/ 5 | 6 | Copyright 2016 sillyfrog 7 | */ 8 | 9 | #include "ir_Daikin.h" 10 | #include 11 | #include "IRremoteESP8266.h" 12 | #include "IRutils.h" 13 | 14 | // DDDDD AAA IIIII KK KK IIIII NN NN 15 | // DD DD AAAAA III KK KK III NNN NN 16 | // DD DD AA AA III KKKK III NN N NN 17 | // DD DD AAAAAAA III KK KK III NN NNN 18 | // DDDDDD AA AA IIIII KK KK IIIII NN NN 19 | 20 | // Constants 21 | // Ref: 22 | // https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote 23 | #define DAIKIN_HDR_MARK 3650U // DAIKIN_ZERO_MARK * 8 24 | #define DAIKIN_HDR_SPACE 1623U // DAIKIN_ZERO_MARK * 4 25 | #define DAIKIN_ONE_SPACE 1280U 26 | #define DAIKIN_ONE_MARK 428U 27 | #define DAIKIN_ZERO_MARK 428U 28 | #define DAIKIN_ZERO_SPACE 428U 29 | #define DAIKIN_GAP 29000U 30 | 31 | #if SEND_DAIKIN 32 | // Send a Daikin A/C message. 33 | // 34 | // Args: 35 | // data: An array of DAIKIN_COMMAND_LENGTH bytes containing the IR command. 36 | // 37 | // Status: STABLE 38 | // 39 | // Ref: 40 | // IRDaikinESP.cpp 41 | // https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote 42 | void IRsend::sendDaikin(unsigned char data[], uint16_t nbytes, 43 | uint16_t repeat) { 44 | if (nbytes < DAIKIN_COMMAND_LENGTH) 45 | return; // Not enough bytes to send a proper message. 46 | // Set IR carrier frequency 47 | enableIROut(38); 48 | for (uint16_t r = 0; r <= repeat; r++) { 49 | // Header #1 50 | mark(DAIKIN_HDR_MARK); 51 | space(DAIKIN_HDR_SPACE); 52 | // Data #1 53 | for (uint16_t i = 0; i < 8 && i < nbytes; i++) 54 | sendData(DAIKIN_ONE_MARK, DAIKIN_ONE_SPACE, DAIKIN_ZERO_MARK, 55 | DAIKIN_ZERO_SPACE, data[i], 8, false); 56 | // Footer #1 57 | mark(DAIKIN_ONE_MARK); 58 | space(DAIKIN_ZERO_SPACE + DAIKIN_GAP); 59 | 60 | // Header #2 61 | mark(DAIKIN_HDR_MARK); 62 | space(DAIKIN_HDR_SPACE); 63 | // Data #2 64 | for (uint16_t i = 8; i < nbytes; i++) 65 | sendData(DAIKIN_ONE_MARK, DAIKIN_ONE_SPACE, DAIKIN_ZERO_MARK, 66 | DAIKIN_ZERO_SPACE, data[i], 8, false); 67 | // Footer #2 68 | mark(DAIKIN_ONE_MARK); 69 | space(DAIKIN_ZERO_SPACE + DAIKIN_GAP); 70 | } 71 | } 72 | 73 | IRDaikinESP::IRDaikinESP(uint16_t pin) : _irsend(pin) { 74 | stateReset(); 75 | } 76 | 77 | void IRDaikinESP::begin() { 78 | _irsend.begin(); 79 | } 80 | 81 | void IRDaikinESP::send() { 82 | _irsend.sendDaikin(daikin); 83 | } 84 | 85 | void IRDaikinESP::checksum() { 86 | uint8_t sum = 0; 87 | uint8_t i; 88 | 89 | for (i = 0; i <= 6; i++) 90 | sum += daikin[i]; 91 | 92 | daikin[7] = sum & 0xFF; 93 | sum = 0; 94 | for (i = 8; i <= 25; i++) 95 | sum += daikin[i]; 96 | daikin[26] = sum & 0xFF; 97 | } 98 | 99 | 100 | void IRDaikinESP::stateReset() { 101 | for (uint8_t i = 4; i < DAIKIN_COMMAND_LENGTH; i++) 102 | daikin[i] = 0x0; 103 | 104 | daikin[0] = 0x11; 105 | daikin[1] = 0xDA; 106 | daikin[2] = 0x27; 107 | daikin[3] = 0xF0; 108 | daikin[7] = 0x20; 109 | daikin[8] = 0x11; 110 | daikin[9] = 0xDA; 111 | daikin[10] = 0x27; 112 | daikin[13] = 0x41; 113 | daikin[14] = 0x1E; 114 | daikin[16] = 0xB0; 115 | daikin[23] = 0xC0; 116 | daikin[26] = 0xE3; 117 | checksum(); 118 | } 119 | 120 | uint8_t* IRDaikinESP::getRaw() { 121 | checksum(); // Ensure correct settings before sending. 122 | return daikin; 123 | } 124 | 125 | void IRDaikinESP::on() { 126 | // state = ON; 127 | daikin[13] |= 0x01; 128 | checksum(); 129 | } 130 | 131 | void IRDaikinESP::off() { 132 | // state = OFF; 133 | daikin[13] &= 0xFE; 134 | checksum(); 135 | } 136 | 137 | void IRDaikinESP::setPower(bool state) { 138 | if (state) 139 | on(); 140 | else 141 | off(); 142 | } 143 | 144 | uint8_t IRDaikinESP::getPower() { 145 | return daikin[13] & 0x01; 146 | } 147 | 148 | // DAIKIN_SILENT or DAIKIN_POWERFUL 149 | void IRDaikinESP::setAux(uint8_t aux) { 150 | daikin[21] = aux; 151 | checksum(); 152 | } 153 | 154 | uint8_t IRDaikinESP::getAux() { 155 | return daikin[21]; 156 | } 157 | 158 | void IRDaikinESP::setQuiet(bool state) { 159 | if (state) 160 | setAux(DAIKIN_SILENT); 161 | else 162 | setAux(0x0); 163 | } 164 | 165 | bool IRDaikinESP::getQuiet() { 166 | return (getAux() == DAIKIN_SILENT); 167 | } 168 | 169 | void IRDaikinESP::setPowerful(bool state) { 170 | if (state) 171 | setAux(DAIKIN_POWERFUL); 172 | else 173 | setAux(0x0); 174 | } 175 | 176 | bool IRDaikinESP::getPowerful() { 177 | return (getAux() == DAIKIN_POWERFUL); 178 | } 179 | 180 | // Set the temp in deg C 181 | void IRDaikinESP::setTemp(uint8_t temp) { 182 | if (temp < DAIKIN_MIN_TEMP) 183 | temp = DAIKIN_MIN_TEMP; 184 | else if (temp > DAIKIN_MAX_TEMP) 185 | temp = DAIKIN_MAX_TEMP; 186 | daikin[14] = temp * 2; 187 | checksum(); 188 | } 189 | 190 | uint8_t IRDaikinESP::getTemp() { 191 | return daikin[14] / 2; 192 | } 193 | 194 | // Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed 195 | void IRDaikinESP::setFan(uint8_t fan) { 196 | // Set the fan speed bits, leave low 4 bits alone 197 | uint8_t fanset; 198 | daikin[16] &= 0x0F; 199 | fan = std::min(fan, DAIKIN_FAN_MAX); 200 | if (fan == DAIKIN_FAN_AUTO) 201 | fanset = 0xA0; 202 | else 203 | fanset = 0x20 + (0x10 * fan); 204 | daikin[16] |= fanset; 205 | checksum(); 206 | } 207 | 208 | uint8_t IRDaikinESP::getFan() { 209 | uint8_t fan = daikin[16] >> 4; 210 | fan -= 2; 211 | if (fan > DAIKIN_FAN_MAX) 212 | fan = DAIKIN_FAN_AUTO; 213 | return fan; 214 | } 215 | 216 | uint8_t IRDaikinESP::getMode() { 217 | /* 218 | DAIKIN_COOL 219 | DAIKIN_HEAT 220 | DAIKIN_FAN 221 | DAIKIN_AUTO 222 | DAIKIN_DRY 223 | */ 224 | return daikin[13] >> 4; 225 | } 226 | 227 | void IRDaikinESP::setMode(uint8_t mode) { 228 | switch (mode) { 229 | case DAIKIN_COOL: 230 | case DAIKIN_HEAT: 231 | case DAIKIN_FAN: 232 | case DAIKIN_DRY: 233 | break; 234 | default: 235 | mode = DAIKIN_AUTO; 236 | } 237 | daikin[13] = (mode << 4) | getPower(); 238 | checksum(); 239 | } 240 | 241 | void IRDaikinESP::setSwingVertical(bool state) { 242 | if (state) 243 | daikin[16] |= 0x0F; 244 | else 245 | daikin[16] &= 0xF0; 246 | checksum(); 247 | } 248 | 249 | bool IRDaikinESP::getSwingVertical() { 250 | return daikin[16] & 0x01; 251 | } 252 | 253 | void IRDaikinESP::setSwingHorizontal(bool state) { 254 | if (state) 255 | daikin[17] |= 0x0F; 256 | else 257 | daikin[17] &= 0xF0; 258 | checksum(); 259 | } 260 | 261 | bool IRDaikinESP::getSwingHorizontal() { 262 | return daikin[17] & 0x01; 263 | } 264 | #endif // SEND_DAIKIN 265 | 266 | #if DECODE_DAIKIN 267 | // TODO(crankyoldgit): NOT WORKING. This needs to be finished. 268 | // Decode the supplied Daikin A/C message. (NOT WORKING - DO NOT USE) 269 | // Args: 270 | // results: Ptr to the data to decode and where to store the decode result. 271 | // nbits: Nr. of bits to expect in the data portion. Typically SAMSUNG_BITS. 272 | // strict: Flag to indicate if we strictly adhere to the specification. 273 | // Returns: 274 | // boolean: True if it can decode it, false if it can't. 275 | // 276 | // Status: UNFINISHED / Completely not working, not even vaguely. 277 | // 278 | // Ref: 279 | // https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote 280 | bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits, 281 | bool strict) { 282 | if (results->rawlen < 2 * nbits + HEADER + FOOTER) 283 | return false; 284 | 285 | // Compliance 286 | if (strict && nbits != DAIKIN_BITS) 287 | return false; 288 | 289 | uint32_t data = 0; 290 | uint16_t offset = OFFSET_START; 291 | 292 | // Header 293 | if (!matchMark(results->rawbuf[offset++], DAIKIN_HDR_MARK)) 294 | return false; 295 | if (!matchSpace(results->rawbuf[offset++], DAIKIN_HDR_SPACE)) 296 | return false; 297 | 298 | // Data (#1) 299 | for (uint8_t i = 0; i < sizeof(data) * 8; i++, offset++) { 300 | if (!matchMark(results->rawbuf[offset++], DAIKIN_ONE_MARK)) 301 | return false; 302 | if (matchSpace(results->rawbuf[offset], DAIKIN_ONE_SPACE)) 303 | data = (data << 1) | 1; // 1 304 | else if (matchSpace(results->rawbuf[offset], DAIKIN_ZERO_SPACE)) 305 | data <<= 1; // 0 306 | else 307 | return false; 308 | } 309 | 310 | uint32_t number = data; // some number... 311 | uint32_t reversed = reverseBits(number, sizeof(number) * 8) 312 | 313 | DPRINT("Code "); 314 | DPRINTLN(reversed, HEX); 315 | 316 | // Data (#2) 317 | for (uint8_t i = 0; i < sizeof(data) * 8; i++, offset++) { 318 | if (!matchMark(results->rawbuf[offset++], DAIKIN_ONE_MARK)) 319 | return false; 320 | if (matchSpace(results->rawbuf[offset], DAIKIN_ONE_SPACE)) 321 | data = (data << 1) | 1; // 1 322 | else if (matchSpace(results->rawbuf[offset], DAIKIN_ZERO_SPACE)) 323 | data <<= 1; // 0 324 | else 325 | return false; 326 | } 327 | 328 | number = data; // some number... 329 | reversed = reverseBits(number, sizeof(number) * 8) 330 | 331 | DPRINT("Code2 "); 332 | DPRINTLN(reversed, HEX); 333 | 334 | if (!matchSpace(results->rawbuf[offset++], DAIKIN_GAP)) { 335 | DPRINTLN("no gap"); 336 | return false; 337 | } 338 | 339 | // Success 340 | results->bits = DAIKIN_BITS; 341 | results->value = reversed; 342 | results->decode_type = DAIKIN; 343 | results->address = 0; 344 | results->command = 0; 345 | return true; 346 | } 347 | #endif // DECODE_DAIKIN 348 | -------------------------------------------------------------------------------- /src/ir_Sanyo.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2009 Ken Shirriff 2 | // Copyright 2016 marcosamarinho 3 | // Copyright 2017 David Conran 4 | 5 | #include 6 | #include "IRrecv.h" 7 | #include "IRsend.h" 8 | #include "IRtimer.h" 9 | 10 | // SSSS AAA N N Y Y OOO 11 | // S A A NN N Y Y O O 12 | // SSS AAAAA N N N Y O O 13 | // S A A N NN Y O O 14 | // SSSS A A N N Y OOO 15 | 16 | // Sanyo SA 8650B originally added from: 17 | // https://github.com/shirriff/Arduino-IRremote/ 18 | // Sanyo LC7461 support originally by marcosamarinho 19 | 20 | // Constants 21 | // Sanyo SA 8650B 22 | // Ref: 23 | // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Sanyo.cpp 24 | #define SANYO_SA8650B_HDR_MARK 3500U // seen range 3500 25 | #define SANYO_SA8650B_HDR_SPACE 950U // seen 950 26 | #define SANYO_SA8650B_ONE_MARK 2400U // seen 2400 27 | #define SANYO_SA8650B_ZERO_MARK 700U // seen 700 28 | // usually see 713 - not using ticks as get number wrapround 29 | #define SANYO_SA8650B_DOUBLE_SPACE_USECS 800U 30 | #define SANYO_SA8650B_RPT_LENGTH 45000U 31 | // Sanyo LC7461 32 | // Ref: 33 | // https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp 34 | // http://slydiman.narod.ru/scr/kb/sanyo.htm 35 | // http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf 36 | #define SANYO_LC7461_ADDRESS_MASK ((1 << SANYO_LC7461_ADDRESS_BITS) - 1) 37 | #define SANYO_LC7461_COMMAND_MASK ((1 << SANYO_LC7461_COMMAND_BITS) - 1) 38 | #define SANYO_LC7461_HDR_MARK 9000U 39 | #define SANYO_LC7461_HDR_SPACE 4500U 40 | #define SANYO_LC7461_BIT_MARK 560U // 1T 41 | #define SANYO_LC7461_ONE_SPACE 1690U // 3T 42 | #define SANYO_LC7461_ZERO_SPACE 560U // 1T 43 | #define SANYO_LC7461_MIN_COMMAND_LENGTH 108000UL 44 | #define SANYO_LC7461_MIN_GAP SANYO_LC7461_MIN_COMMAND_LENGTH - \ 45 | (SANYO_LC7461_HDR_MARK + SANYO_LC7461_HDR_SPACE + SANYO_LC7461_BITS * \ 46 | (SANYO_LC7461_BIT_MARK + (SANYO_LC7461_ONE_SPACE + \ 47 | SANYO_LC7461_ZERO_SPACE) / 2) \ 48 | + SANYO_LC7461_BIT_MARK) 49 | 50 | #if SEND_SANYO 51 | // Construct a Sanyo LC7461 message. 52 | // 53 | // Args: 54 | // address: The 13 bit value of the address(Custom) portion of the protocol. 55 | // command: The 8 bit value of the command(Key) portion of the protocol. 56 | // Returns: 57 | // An uint64_t with the encoded raw 42 bit Sanyo LC7461 data value. 58 | // 59 | // Notes: 60 | // This protocol uses the NEC protocol timings. However, data is 61 | // formatted as : address(13 bits), !address, command(8 bits), !command. 62 | // According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon 63 | uint64_t IRsend::encodeSanyoLC7461(uint16_t address, uint8_t command) { 64 | // Mask our input values to ensure the correct bit sizes. 65 | address &= SANYO_LC7461_ADDRESS_MASK; 66 | command &= SANYO_LC7461_COMMAND_MASK; 67 | 68 | uint64_t data = address; 69 | address ^= SANYO_LC7461_ADDRESS_MASK; // Invert the 13 LSBs. 70 | // Append the now inverted address. 71 | data = (data << SANYO_LC7461_ADDRESS_BITS) | address; 72 | // Append the command. 73 | data = (data << SANYO_LC7461_COMMAND_BITS) | command; 74 | command ^= SANYO_LC7461_COMMAND_MASK; // Invert the command. 75 | // Append the now inverted command. 76 | data = (data << SANYO_LC7461_COMMAND_BITS) | command; 77 | 78 | return data; 79 | } 80 | 81 | // Send a Sanyo LC7461 message. 82 | // 83 | // Args: 84 | // data: The contents of the command you want to send. 85 | // nbits: The bit size of the command being sent. 86 | // repeat: The number of times you want the command to be repeated. 87 | // 88 | // Status: BETA / Probably works. 89 | // 90 | // Notes: 91 | // Based on @marcosamarinho's work. 92 | // This protocol uses the NEC protocol timings. However, data is 93 | // formatted as : address(13 bits), !address, command (8 bits), !command. 94 | // According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon 95 | // Information for this protocol is available at the Sanyo LC7461 datasheet. 96 | // Repeats are performed similar to the NEC method of sending a special 97 | // repeat message, rather than duplicating the entire message. 98 | // Ref: 99 | // https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp 100 | // http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf 101 | void IRsend::sendSanyoLC7461(uint64_t data, uint16_t nbits, uint16_t repeat) { 102 | // This protocol appears to be another 42-bit varient of the NEC protcol. 103 | sendNEC(data, nbits, repeat); 104 | } 105 | #endif // SEND_SANYO 106 | 107 | #if DECODE_SANYO 108 | // Decode the supplied SANYO LC7461 message. 109 | // 110 | // Args: 111 | // results: Ptr to the data to decode and where to store the decode result. 112 | // nbits: Nr. of data bits to expect. 113 | // strict: Flag indicating if we should perform strict matching. 114 | // Returns: 115 | // boolean: True if it can decode it, false if it can't. 116 | // 117 | // Status: BETA / Probably works. 118 | // 119 | // Notes: 120 | // Based on @marcosamarinho's work. 121 | // This protocol uses the NEC protocol. However, data is 122 | // formatted as : address(13 bits), !address, command (8 bits), !command. 123 | // According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon 124 | // Information for this protocol is available at the Sanyo LC7461 datasheet. 125 | // Ref: 126 | // http://slydiman.narod.ru/scr/kb/sanyo.htm 127 | // https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp 128 | // http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf 129 | bool IRrecv::decodeSanyoLC7461(decode_results *results, uint16_t nbits, 130 | bool strict) { 131 | if (strict && nbits != SANYO_LC7461_BITS) 132 | return false; // Not strictly in spec. 133 | // This protocol is basically a 42-bit varient of the NEC protocol. 134 | if (!decodeNEC(results, nbits, false)) 135 | return false; // Didn't match a NEC format (without strict) 136 | 137 | // Bits 30 to 42+. 138 | uint16_t address = results->value >> (SANYO_LC7461_BITS - 139 | SANYO_LC7461_ADDRESS_BITS); 140 | // Bits 9 to 16. 141 | uint8_t command = (results->value >> SANYO_LC7461_COMMAND_BITS) & 142 | SANYO_LC7461_COMMAND_MASK; 143 | // Compliance 144 | if (strict) { 145 | if (results->bits != nbits) 146 | return false; 147 | // Bits 17 to 29. 148 | uint16_t inverted_address = 149 | (results->value >> (SANYO_LC7461_COMMAND_BITS * 2)) & 150 | SANYO_LC7461_ADDRESS_MASK; 151 | // Bits 1-8. 152 | uint8_t inverted_command = results->value & SANYO_LC7461_COMMAND_MASK; 153 | if ((address ^ SANYO_LC7461_ADDRESS_MASK) != inverted_address) 154 | return false; // Address integrity check failed. 155 | if ((command ^ SANYO_LC7461_COMMAND_MASK) != inverted_command) 156 | return false; // Command integrity check failed. 157 | } 158 | 159 | // Success 160 | results->decode_type = SANYO_LC7461; 161 | results->address = address; 162 | results->command = command; 163 | return true; 164 | } 165 | 166 | /* NOTE: Disabled due to poor quality. 167 | // Decode the supplied Sanyo SA 8650B message. 168 | // 169 | // Args: 170 | // results: Ptr to the data to decode and where to store the decode result. 171 | // nbits: Nr. of data bits to expect. 172 | // strict: Flag indicating if we should perform strict matching. 173 | // Returns: 174 | // boolean: True if it can decode it, false if it can't. 175 | // 176 | // Status: Depricated. 177 | // 178 | // NOTE: This decoder looks like rubbish. Only keeping it for compatibility 179 | // with the Arduino IRremote library. Seriously, don't trust it. 180 | // If someone has a device that this is supposed to be for, please log an 181 | // Issue on github with a rawData dump please. We should probably remove 182 | // it. We think this is a Sanyo decoder - serial = SA 8650B 183 | // Ref: 184 | // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Sanyo.cpp 185 | bool IRrecv::decodeSanyo(decode_results *results, uint16_t nbits, bool strict) { 186 | if (results->rawlen < 2 * nbits + HEADER - 1) 187 | return false; // Shorter than shortest possible. 188 | if (strict && nbits != SANYO_SA8650B_BITS) 189 | return false; // Doesn't match the spec. 190 | 191 | uint16_t offset = 0; 192 | 193 | // TODO(crankyoldgit): This repeat code looks like garbage, it should never 194 | // match or if it does, it won't be reliable. We should probably just 195 | // remove it. 196 | if (results->rawbuf[offset++] < SANYO_SA8650B_DOUBLE_SPACE_USECS) { 197 | results->bits = 0; 198 | results->value = REPEAT; 199 | results->decode_type = SANYO; 200 | results->address = 0; 201 | results->command = 0; 202 | results->repeat = true; 203 | return true; 204 | } 205 | 206 | // Header 207 | if (!matchMark(results->rawbuf[offset++], SANYO_SA8650B_HDR_MARK)) 208 | return false; 209 | // NOTE: These next two lines look very wrong. Treat as suspect. 210 | if (!matchMark(results->rawbuf[offset++], SANYO_SA8650B_HDR_MARK)) 211 | return false; 212 | // Data 213 | uint64_t data = 0; 214 | while (offset + 1 < results->rawlen) { 215 | if (!matchSpace(results->rawbuf[offset], SANYO_SA8650B_HDR_SPACE)) 216 | break; 217 | offset++; 218 | if (matchMark(results->rawbuf[offset], SANYO_SA8650B_ONE_MARK)) 219 | data = (data << 1) | 1; // 1 220 | else if (matchMark(results->rawbuf[offset], SANYO_SA8650B_ZERO_MARK)) 221 | data <<= 1; // 0 222 | else 223 | return false; 224 | offset++; 225 | } 226 | 227 | if (strict && SANYO_SA8650B_BITS > (offset - 1U) / 2U) 228 | return false; 229 | 230 | // Success 231 | results->bits = (offset - 1) / 2; 232 | results->decode_type = SANYO; 233 | results->value = data; 234 | results->address = 0; 235 | results->command = 0; 236 | return true; 237 | } 238 | */ 239 | #endif // DECODE_SANYO 240 | -------------------------------------------------------------------------------- /test/ir_Sanyo_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 David Conran 2 | 3 | #include "IRsend.h" 4 | #include "IRsend_test.h" 5 | #include "gtest/gtest.h" 6 | 7 | 8 | // Tests for encodeSanyoLC7461(). 9 | 10 | TEST(TestEncodeSanyoLC7461, NormalEncoding) { 11 | IRsendTest irsend(4); 12 | EXPECT_EQ(0x1FFF00FF, irsend.encodeSanyoLC7461(0, 0)); 13 | EXPECT_EQ(0x3FFE01FE, irsend.encodeSanyoLC7461(1, 1)); 14 | EXPECT_EQ(0x3FFE02FD, irsend.encodeSanyoLC7461(1, 2)); 15 | EXPECT_EQ(0x3FFE000FF00, irsend.encodeSanyoLC7461(0x1FFF, 0xFF)); 16 | EXPECT_EQ(0x2AAAAAA55AA, irsend.encodeSanyoLC7461(0x1555, 0x55)); 17 | EXPECT_EQ(0x3FFE000FF00, irsend.encodeSanyoLC7461(0xFFFF, 0xFF)); 18 | EXPECT_EQ(0x1D8113F00FF, irsend.encodeSanyoLC7461(0xEC0, 0x0)); 19 | } 20 | 21 | // Tests for sendSanyoLC7461(). 22 | 23 | // Test sending typical data only. 24 | TEST(TestEncodeSanyoLC7461, SendDataOnly) { 25 | IRsendTest irsend(4); 26 | irsend.begin(); 27 | 28 | irsend.reset(); 29 | irsend.sendSanyoLC7461(0x1D8113F00FF); 30 | EXPECT_EQ( 31 | "m9000s4500" 32 | "m560s560m560s1690m560s1690m560s1690m560s560m560s1690m560s1690m560s560" 33 | "m560s560m560s560m560s560m560s560m560s560m560s1690m560s560m560s560" 34 | "m560s560m560s1690m560s560m560s560m560s1690m560s1690m560s1690m560s1690" 35 | "m560s1690m560s1690m560s560m560s560m560s560m560s560m560s560m560s560" 36 | "m560s560m560s560m560s1690m560s1690m560s1690m560s1690m560s1690m560s1690" 37 | "m560s1690m560s1690m560s108000", irsend.outputStr()); 38 | } 39 | 40 | // Test sending with different repeats. 41 | TEST(TestEncodeSanyoLC7461, SendWithRepeats) { 42 | IRsendTest irsend(4); 43 | irsend.begin(); 44 | 45 | irsend.reset(); 46 | irsend.sendSanyoLC7461(0x1D8113F00FF, SANYO_LC7461_BITS, 1); // 1 repeat. 47 | EXPECT_EQ( 48 | "m9000s4500" 49 | "m560s560m560s1690m560s1690m560s1690m560s560m560s1690m560s1690m560s560" 50 | "m560s560m560s560m560s560m560s560m560s560m560s1690m560s560m560s560" 51 | "m560s560m560s1690m560s560m560s560m560s1690m560s1690m560s1690m560s1690" 52 | "m560s1690m560s1690m560s560m560s560m560s560m560s560m560s560m560s560" 53 | "m560s560m560s560m560s1690m560s1690m560s1690m560s1690m560s1690m560s1690" 54 | "m560s1690m560s1690m560s108000" 55 | "m9000s2250m560s108000", irsend.outputStr()); 56 | } 57 | 58 | // Tests for decodeSanyoLC7461(). 59 | 60 | // Decode normal Sanyo LC7461 messages. 61 | TEST(TestDecodeSanyoLC7461, NormalDecodeWithStrict) { 62 | IRsendTest irsend(4); 63 | IRrecv irrecv(4); 64 | irsend.begin(); 65 | 66 | // Normal Sanyo LC7461 42-bit message. 67 | irsend.reset(); 68 | irsend.sendSanyoLC7461(0x1D8113F00FF); 69 | irsend.makeDecodeResult(); 70 | ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 71 | true)); 72 | EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); 73 | EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); 74 | EXPECT_EQ(0x1D8113F00FF, irsend.capture.value); 75 | EXPECT_EQ(0xEC0, irsend.capture.address); 76 | EXPECT_EQ(0x0, irsend.capture.command); 77 | EXPECT_FALSE(irsend.capture.repeat); 78 | 79 | // Synthesised Normal Sanyo LC7461 42-bit message. 80 | irsend.reset(); 81 | irsend.sendSanyoLC7461(irsend.encodeSanyoLC7461(0x1234, 0x56)); 82 | irsend.makeDecodeResult(); 83 | ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 84 | true)); 85 | EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); 86 | EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); 87 | EXPECT_EQ(0x2468DCB56A9, irsend.capture.value); 88 | EXPECT_EQ(0x1234, irsend.capture.address); 89 | EXPECT_EQ(0x56, irsend.capture.command); 90 | EXPECT_FALSE(irsend.capture.repeat); 91 | 92 | // Synthesised Normal Sanyo LC7461 42-bit message. 93 | irsend.reset(); 94 | irsend.sendSanyoLC7461(irsend.encodeSanyoLC7461(0x1, 0x1)); 95 | irsend.makeDecodeResult(); 96 | ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 97 | true)); 98 | EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); 99 | EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); 100 | EXPECT_EQ(0x3FFE01FE, irsend.capture.value); 101 | EXPECT_EQ(0x1, irsend.capture.address); 102 | EXPECT_EQ(0x1, irsend.capture.command); 103 | EXPECT_FALSE(irsend.capture.repeat); 104 | } 105 | 106 | // Decode normal repeated Sanyo LC7461 messages. 107 | TEST(TestDecodeSanyoLC7461, NormalDecodeWithRepeatAndStrict) { 108 | IRsendTest irsend(4); 109 | IRrecv irrecv(4); 110 | irsend.begin(); 111 | 112 | // Normal Sanyo LC7461 16-bit message with 1 repeat. 113 | irsend.reset(); 114 | irsend.sendSanyoLC7461(0x3FFE01FE, SANYO_LC7461_BITS, 1); 115 | irsend.makeDecodeResult(); 116 | ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 117 | true)); 118 | EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); 119 | EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); 120 | EXPECT_EQ(0x3FFE01FE, irsend.capture.value); 121 | EXPECT_EQ(0x1, irsend.capture.address); 122 | EXPECT_EQ(0x1, irsend.capture.command); 123 | EXPECT_FALSE(irsend.capture.repeat); 124 | } 125 | 126 | // Decode unsupported Sanyo LC7461 messages. 127 | TEST(TestDecodeSanyoLC7461, DecodeWithNonStrictValues) { 128 | IRsendTest irsend(4); 129 | IRrecv irrecv(4); 130 | irsend.begin(); 131 | 132 | irsend.reset(); 133 | irsend.sendSanyoLC7461(0x0); // Illegal value Sanyo LC7461 message. 134 | irsend.makeDecodeResult(); 135 | // Should fail with strict on. 136 | ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 137 | true)); 138 | // Should pass if strict off. 139 | ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 140 | false)); 141 | EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); 142 | EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); 143 | EXPECT_EQ(0x0, irsend.capture.value); 144 | EXPECT_EQ(0x0, irsend.capture.address); 145 | EXPECT_EQ(0x0, irsend.capture.command); 146 | 147 | irsend.reset(); 148 | // Illegal value Sanyo LC7461 42-bit message. 149 | irsend.sendSanyoLC7461(0x1234567890A); 150 | irsend.makeDecodeResult(); 151 | ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 152 | true)); 153 | 154 | // Should fail with strict when we ask for the wrong bit size. 155 | ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, 32, 156 | true)); 157 | ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, 64, 158 | true)); 159 | // And should fail for a bad value. 160 | ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 161 | true)); 162 | // Should pass if strict off. 163 | ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 164 | false)); 165 | EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); 166 | EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); 167 | EXPECT_EQ(0x1234567890A, irsend.capture.value); 168 | EXPECT_EQ(0x91A, irsend.capture.address); 169 | EXPECT_EQ(0x89, irsend.capture.command); 170 | 171 | // Shouldn't pass if strict off and looking for a smaller size. 172 | ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, 34, false)); 173 | } 174 | 175 | // Decode (non-standard) 64-bit messages. 176 | TEST(TestDecodeSanyoLC7461, Decode64BitMessages) { 177 | IRsendTest irsend(4); 178 | IRrecv irrecv(4); 179 | irsend.begin(); 180 | 181 | irsend.reset(); 182 | // Illegal value & size Sanyo LC7461 64-bit message. 183 | irsend.sendSanyoLC7461(0xFFFFFFFFFFFFFFFF, 64); 184 | irsend.makeDecodeResult(); 185 | // Should work with a 'normal' match (not strict) 186 | ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, 64, false)); 187 | EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); 188 | EXPECT_EQ(64, irsend.capture.bits); 189 | EXPECT_EQ(0xFFFFFFFFFFFFFFFF, irsend.capture.value); 190 | EXPECT_EQ(0xFFFF, irsend.capture.address); 191 | EXPECT_EQ(0xFF, irsend.capture.command); 192 | } 193 | 194 | // Decode a 'real' example via GlobalCache 195 | TEST(TestDecodeSanyoLC7461, DecodeGlobalCacheExample) { 196 | IRsendTest irsend(4); 197 | IRrecv irrecv(4); 198 | irsend.begin(); 199 | 200 | irsend.reset(); 201 | uint16_t gc_test[95] = {38000, 1, 89, 342, 171, 21, 21, 21, 64, 21, 64, 202 | 21, 64, 21, 21, 21, 64, 21, 64, 21, 21, 21, 21, 203 | 21, 21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, 204 | 21, 21, 21, 21, 21, 64, 21, 21, 21, 21, 21, 64, 205 | 21, 64, 21, 64, 21, 64, 21, 64, 21, 64, 21, 21, 206 | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 207 | 21, 21, 21, 64, 21, 64, 21, 64, 21, 64, 21, 64, 208 | 21, 64, 21, 64, 21, 64, 21, 875, 342, 171, 21, 3565}; 209 | irsend.sendGC(gc_test, 95); 210 | irsend.makeDecodeResult(); 211 | 212 | ASSERT_TRUE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, true)); 213 | EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type); 214 | EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits); 215 | EXPECT_EQ(0x1D8113F00FF, irsend.capture.value); 216 | EXPECT_EQ(0xEC0, irsend.capture.address); 217 | EXPECT_EQ(0x0, irsend.capture.command); 218 | EXPECT_FALSE(irsend.capture.repeat); 219 | 220 | // Confirm what the 42-bit NEC decode is. 221 | ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, 42, false)); 222 | EXPECT_EQ(0x1D8113F00FF, irsend.capture.value); 223 | } 224 | 225 | // Fail to decode a non-Sanyo LC7461 example via GlobalCache 226 | TEST(TestDecodeSanyoLC7461, FailToDecodeNonSanyoLC7461Example) { 227 | IRsendTest irsend(4); 228 | IRrecv irrecv(4); 229 | irsend.begin(); 230 | 231 | irsend.reset(); 232 | // Modified a few entries to unexpected values, based on previous test case. 233 | uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20, 234 | 20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20, 235 | 61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884}; 236 | irsend.sendGC(gc_test, 39); 237 | irsend.makeDecodeResult(); 238 | 239 | ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture)); 240 | ASSERT_FALSE(irrecv.decodeSanyoLC7461(&irsend.capture, SANYO_LC7461_BITS, 241 | false)); 242 | } 243 | --------------------------------------------------------------------------------