├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── custom.md │ ├── feature_request.md │ └── bug_report.md ├── workflows │ ├── stale.yml │ ├── sync_issues.yml │ └── LibraryBuild.yml └── issue_template.md ├── examples ├── LegoPowerFunctionsSendDemo │ └── LegoPowerFunctionsSendDemo.ino ├── JVCPanasonicSendDemo │ └── JVCPanasonicSendDemo.ino ├── AiwaRCT501SendDemo │ └── AiwaRCT501SendDemo.ino ├── IRrecvDemo │ └── IRrecvDemo.ino ├── IRsendDemo │ └── IRsendDemo.ino ├── IRsendProntoDemo │ └── IRsendProntoDemo.ino ├── IRsendRawDemo │ └── IRsendRawDemo.ino ├── IRrecvDump │ └── IRrecvDump.ino ├── IRrelay │ └── IRrelay.ino ├── BoseWaveSendDemo │ └── BoseWaveSendDemo.ino ├── LGACSendDemo │ ├── LGACSendDemo.md │ └── LGACSendDemo.ino ├── IRtest │ └── IRtest.ino ├── IRrecord │ └── IRrecord.ino ├── IRrecvDumpV2 │ └── IRrecvDumpV2.ino └── LegoPowerFunctionsTests │ └── LegoPowerFunctionsTests.ino ├── library.properties ├── library.json ├── keywords.txt ├── src ├── esp32.cpp ├── ir_Lego_PF.cpp ├── ir_Dish.cpp ├── ir_LG.cpp ├── ir_Panasonic.cpp ├── ir_Sanyo.cpp ├── ir_Mitsubishi.cpp ├── ir_Samsung.cpp ├── ir_Sony.cpp ├── ir_JVC.cpp ├── ir_Whynter.cpp ├── ir_NEC.cpp ├── ir_Denon.cpp ├── sam.cpp ├── ir_Aiwa.cpp ├── ir_Lego_PF_BitStreamEncoder.h ├── ir_MagiQuest.cpp ├── ir_Sharp_alt.cpp ├── private │ └── IRremoteInt.h ├── irPronto.cpp ├── irSend.cpp ├── ir_Template.cpp ├── ir_Sharp.cpp ├── ir_BoseWave.cpp ├── irRecv.cpp └── IRremote.cpp ├── Contributors.md ├── Contributing.md ├── CODE_OF_CONDUCT.md ├── changelog.md ├── readmdFrench.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject 2 | api-doc 3 | *~ 4 | docs 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/LegoPowerFunctionsSendDemo/LegoPowerFunctionsSendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * LegoPowerFunctionsSendDemo: LEGO Power Functions 3 | * Copyright (c) 2016 Philipp Henkel 4 | */ 5 | 6 | #include 7 | 8 | IRsend irsend; 9 | 10 | void setup() { 11 | } 12 | 13 | void loop() { 14 | // Send repeated command "channel 1, blue forward, red backward" 15 | irsend.sendLegoPowerFunctions(0x197); 16 | delay(2000); 17 | 18 | // Send single command "channel 1, blue forward, red backward" 19 | irsend.sendLegoPowerFunctions(0x197, false); 20 | delay(2000); 21 | } 22 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=IRremote 2 | version=2.6.1 3 | author=shirriff, z3t0 4 | maintainer=Armin Joachimsmeyer 5 | sentence=Send and receive infrared signals with multiple protocols 6 | paragraph=Currently included protocols: Aiwa, BoseWave, Denon, Dish, JVC, Lego, LG, MagiQuest, Mitsubishi, Panasonic, RC5, RC6, Samsung, Sanyo, Sharp, Sony, Whynter, (Pronto).

New:ESP32 bug fixed, corrected Samsung timing, NEC repeat implementation.
7 | category=Communication 8 | url=https://github.com/z3t0/Arduino-IRremote 9 | architectures=* 10 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "IRremote", 3 | "keywords": "infrared, ir, remote", 4 | "description": "Send and receive infrared signals with multiple protocols", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/z3t0/Arduino-IRremote.git" 9 | }, 10 | "version": "2.6.1", 11 | "frameworks": "arduino", 12 | "platforms": "atmelavr", 13 | "authors" : 14 | [ 15 | { 16 | "name":"Rafi Khan", 17 | "email":"zetoslab@gmail.com" 18 | }, 19 | { 20 | "name":"Ken Shirriff", 21 | "email":"ken.shirriff@gmail.com" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 4 * * *' 7 | 8 | jobs: 9 | stale: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Checkout script repository 17 | uses: actions/checkout@v4 18 | with: 19 | repository: Seeed-Studio/sync-github-all-issues 20 | path: ci 21 | 22 | - name: Run script 23 | run: ./ci/tools/stale.sh 24 | env: 25 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/sync_issues.yml: -------------------------------------------------------------------------------- 1 | name: Automate Issue Management 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - edited 8 | - assigned 9 | - unassigned 10 | - labeled 11 | - unlabeled 12 | - reopened 13 | 14 | jobs: 15 | add_issue_to_project: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Add issue to GitHub Project 19 | uses: actions/add-to-project@v1.0.2 20 | with: 21 | project-url: https://github.com/orgs/Seeed-Studio/projects/17 22 | github-token: ${{ secrets.ISSUE_ASSEMBLE }} 23 | labeled: bug 24 | label-operator: NOT -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRsendDemo - demonstrates sending IR codes with IRsend 3 | * An IR LED must be connected to Arduino PWM pin 3. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 8 | */ 9 | #include 10 | 11 | #define PanasonicAddress 0x4004 // Panasonic address (Pre data) 12 | #define PanasonicPower 0x100BCBD // Panasonic Power button 13 | 14 | #define JVCPower 0xC5E8 15 | 16 | IRsend irsend; 17 | 18 | void setup() 19 | { 20 | } 21 | 22 | void loop() { 23 | irsend.sendPanasonic(PanasonicAddress,PanasonicPower); // This should turn your TV on and off 24 | 25 | irsend.sendJVC(JVCPower, 16,0); // hex value, 16 bits, no repeat 26 | delayMicroseconds(50); // see http://www.sbprojects.com/knowledge/ir/jvc.php for information 27 | irsend.sendJVC(JVCPower, 16,1); // hex value, 16 bits, repeat 28 | delayMicroseconds(50); 29 | } 30 | -------------------------------------------------------------------------------- /examples/AiwaRCT501SendDemo/AiwaRCT501SendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRsendDemo - demonstrates sending IR codes with IRsend 3 | * An IR LED must be connected to Arduino PWM pin 3. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | */ 8 | 9 | #include "IRremote.h" 10 | 11 | #define POWER 0x7F80 12 | 13 | IRsend irsend; 14 | 15 | // On the Zero and others we switch explicitly to SerialUSB 16 | #if defined(ARDUINO_ARCH_SAMD) 17 | #define Serial SerialUSB 18 | #endif 19 | 20 | void setup() { 21 | pinMode(LED_BUILTIN, OUTPUT); 22 | 23 | Serial.begin(115200); 24 | #if defined(__AVR_ATmega32U4__) 25 | while (!Serial); //delay for Leonardo, but this loops forever for Maple Serial 26 | #endif 27 | #if defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) 28 | delay(2000); // To be able to connect Serial monitor after reset and before first printout 29 | #endif 30 | // Just to know which program is running on my Arduino 31 | Serial.println(F("START " __FILE__ " from " __DATE__)); 32 | } 33 | 34 | void loop() { 35 | if (Serial.read() != -1) { 36 | irsend.sendAiwaRCT501(POWER); 37 | delay(60); // Optional 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For IRremote 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | decode_results KEYWORD1 10 | IRrecv KEYWORD1 11 | IRsend KEYWORD1 12 | 13 | ####################################### 14 | # Methods and Functions (KEYWORD2) 15 | ####################################### 16 | 17 | blink13 KEYWORD2 18 | decode KEYWORD2 19 | enableIRIn KEYWORD2 20 | resume KEYWORD2 21 | enableIROut KEYWORD2 22 | sendNEC KEYWORD2 23 | sendSony KEYWORD2 24 | sendSanyo KEYWORD2 25 | sendMitsubishi KEYWORD2 26 | sendRaw KEYWORD2 27 | sendRC5 KEYWORD2 28 | sendRC6 KEYWORD2 29 | sendDISH KEYWORD2 30 | sendSAMSUNG KEYWORD2 31 | sendSharp KEYWORD2 32 | sendSharpRaw KEYWORD2 33 | sendSharpAlt KEYWORD2 34 | sendSharpAltRaw KEYWORD2 35 | sendPanasonic KEYWORD2 36 | sendJVC KEYWORD2 37 | sendLG KEYWORD2 38 | sendMagiQuest KEYWORD2 39 | 40 | ####################################### 41 | # Constants (LITERAL1) 42 | ####################################### 43 | 44 | NEC LITERAL1 45 | SONY LITERAL1 46 | SANYO LITERAL1 47 | MITSUBISHI LITERAL1 48 | RC5 LITERAL1 49 | RC6 LITERAL1 50 | DISH LITERAL1 51 | SAMSUNGL ITERAL1 52 | SHARP LITERAL1 53 | SHARP_ALT LITERAL1 54 | PANASONIC LITERAL1 55 | JVC LITERAL1 56 | LG LITERAL1 57 | AIWA_RC_T501 LITERAL1 58 | MAGIQUEST LITERAL1 59 | UNKNOWN LITERAL1 60 | REPEAT LITERAL1 61 | -------------------------------------------------------------------------------- /src/esp32.cpp: -------------------------------------------------------------------------------- 1 | #ifdef ESP32 2 | 3 | // This file contains functions specific to the ESP32. 4 | 5 | #include "IRremote.h" 6 | 7 | // "Idiot check" 8 | #ifdef USE_DEFAULT_ENABLE_IR_IN 9 | #error Must undef USE_DEFAULT_ENABLE_IR_IN 10 | #endif 11 | 12 | hw_timer_t *timer; 13 | IRAM_ATTR void IRTimer(); // defined in IRremote.cpp, masqueraded as ISR(TIMER_INTR_NAME) 14 | 15 | //+============================================================================= 16 | // initialization 17 | // 18 | void IRrecv::enableIRIn() { 19 | // Interrupt Service Routine - Fires every 50uS 20 | // ESP32 has a proper API to setup timers, no weird chip macros needed 21 | // simply call the readable API versions :) 22 | // 3 timers, choose #1, 80 divider nanosecond precision, 1 to count up 23 | timer = timerBegin(1, 80, 1); 24 | timerAttachInterrupt(timer, &IRTimer, 1); 25 | // every 50ns, autoreload = true 26 | timerAlarmWrite(timer, 50, true); 27 | timerAlarmEnable(timer); 28 | 29 | // Initialize state machine variables 30 | irparams.rcvstate = IR_REC_STATE_IDLE; 31 | irparams.rawlen = 0; 32 | 33 | // Set pin modes 34 | pinMode(irparams.recvpin, INPUT); 35 | } 36 | 37 | void IRrecv::disableIRIn() { 38 | timerEnd(timer); 39 | timerDetachInterrupt(timer); 40 | } 41 | 42 | void IRsend::enableIROut(int khz) { 43 | ledcSetup(LEDCHANNEL, khz * 1000, 8); // 8 bit PWM resolution 44 | ledcAttachPin(IR_SEND_PIN, LEDCHANNEL); // bind pin to channel 45 | } 46 | 47 | #endif // ESP32 48 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Board 2 | * [ ] Arduino ATmega328* board (UNO, Nano) 3 | * [ ] Arduino ATmega2560 board (Mega) 4 | * [ ] Arduino ATmega32U4 board (Leonardo) 5 | * [ ] Arduino SAM board (Due) 6 | * [ ] Arduino SAMD board (Zero, MKR*) 7 | * [ ] ESP32 board 8 | * [ ] Teensy board 9 | * [ ] Other - please specify 10 | 11 | ### Protocol 12 | * [ ] Unknown 13 | * [ ] Aiwa 14 | * [ ] BoseWave 15 | * [ ] Denon 16 | * [ ] Dish 17 | * [ ] JVC 18 | * [ ] Lego 19 | * [ ] LG 20 | * [ ] Mitsubishi 21 | * [ ] Panasonic 22 | * [ ] RC5, RC6 23 | * [ ] Samsung 24 | * [ ] Sanyo 25 | * [ ] Sharp 26 | * [ ] Sony 27 | * [ ] Whynter 28 | * [ ] Other - please specify 29 | 30 | 31 | **Code Block:** 32 | ```c 33 | 34 | #include 35 | 36 | ..... 37 | 38 | ``` 39 | 40 | Use [a gist](gist.github.com) if the code exceeds 30 lines 41 | 42 | **checklist:** 43 | - [] I have **read** the README.md file thoroughly 44 | - [] I have searched existing issues to see if there is anything I have missed. 45 | - [] The latest [release](https://github.com/z3t0/Arduino-IRremote/releases/latest) is used 46 | - [] Any code referenced is provided and if over 30 lines a gist is linked INSTEAD of it being pasted in here 47 | - [] The title of the issue is helpful and relevant 48 | 49 | ** We will start to close issues that do not follow these guidelines as it doesn't help the contributors who spend time trying to solve issues if the community ignores guidelines!** 50 | 51 | The above is a short template allowing you to make detailed issues! 52 | -------------------------------------------------------------------------------- /src/ir_Lego_PF.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | #include "ir_Lego_PF_BitStreamEncoder.h" 3 | 4 | //============================================================================== 5 | // L EEEEEE EEEE OOOO 6 | // L E E O O 7 | // L EEEE E EEE O O 8 | // L E E E O O LEGO Power Functions 9 | // LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016 Philipp Henkel 10 | //============================================================================== 11 | 12 | // Supported Devices 13 | // LEGO® Power Functions IR Receiver 8884 14 | 15 | //+============================================================================= 16 | // 17 | #if SEND_LEGO_PF 18 | 19 | #if DEBUG 20 | namespace { 21 | void logFunctionParameters(uint16_t data, bool repeat) { 22 | DBG_PRINT("sendLegoPowerFunctions(data="); 23 | DBG_PRINT(data); 24 | DBG_PRINT(", repeat="); 25 | DBG_PRINTLN(repeat?"true)" : "false)"); 26 | } 27 | } // anonymous namespace 28 | #endif // DEBUG 29 | 30 | void IRsend::sendLegoPowerFunctions(uint16_t data, bool repeat) { 31 | #if DEBUG 32 | ::logFunctionParameters(data, repeat); 33 | #endif // DEBUG 34 | 35 | enableIROut(38); 36 | static LegoPfBitStreamEncoder bitStreamEncoder; 37 | bitStreamEncoder.reset(data, repeat); 38 | do { 39 | mark(bitStreamEncoder.getMarkDuration()); 40 | space(bitStreamEncoder.getPauseDuration()); 41 | } while (bitStreamEncoder.next()); 42 | } 43 | 44 | #endif // SEND_LEGO_PF 45 | -------------------------------------------------------------------------------- /Contributors.md: -------------------------------------------------------------------------------- 1 | ## Contributors 2 | These are the active contributors of this project that you may contact if there is anything you need help with or if you have suggestions. 3 | 4 | - [z3t0](https://github.com/z3t0) and currently also the main contributor. 5 | * Email: zetoslab@gmail.com 6 | - [shirriff](https://github.com/shirriff): An amazing person who worked to create this awesome library and provide unending support 7 | - [Informatic](https://github.com/Informatic) 8 | - [fmeschia](https://github.com/fmeschia) 9 | - [PaulStoffregen](https://github.com/paulstroffregen) 10 | - [crash7](https://github.com/crash7) 11 | - [Neco777](https://github.com/neco777) 12 | - [Lauszus](https://github.com/lauszus) 13 | - [csBlueChip](https://github.com/csbluechip) contributed major and vital changes to the code base. 14 | - [Sebazzz](https://github.com/sebazz) 15 | - [lumbric](https://github.com/lumbric) 16 | - [ElectricRCAircraftGuy](https://github.com/electricrcaircraftguy) 17 | - [philipphenkel](https://github.com/philipphenkel) 18 | - [MCUdude](https://github.com/MCUdude) 19 | - [adamlhumphreys](https://github.com/adamlhumphreys) (code space improvements) 20 | - [marcmerlin](https://github.com/marcmerlin) (ESP32 port) 21 | - [MrBryonMiller](https://github.com/MrBryonMiller) 22 | - [bengtmartensson](https://github.com/bengtmartensson) providing support 23 | - [AnalysIR](https:/github.com/AnalysIR) providing support 24 | - [ArminJo](https://github.com/ArminJo) Maintainer 25 | - [eshicks4](https://github.com/eshicks4) 26 | 27 | Note: Please let [z3t0](https://github.com/z3t0) know if you have been missed. 28 | -------------------------------------------------------------------------------- /examples/IRrecvDemo/IRrecvDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | */ 8 | 9 | #include 10 | 11 | #if defined(ESP32) 12 | int IR_RECEIVE_PIN = 15; 13 | #else 14 | int IR_RECEIVE_PIN = 11; 15 | #endif 16 | IRrecv irrecv(IR_RECEIVE_PIN); 17 | 18 | decode_results results; 19 | 20 | // On the Zero and others we switch explicitly to SerialUSB 21 | #if defined(ARDUINO_ARCH_SAMD) 22 | #define Serial SerialUSB 23 | #endif 24 | 25 | void setup() { 26 | pinMode(LED_BUILTIN, OUTPUT); 27 | 28 | Serial.begin(115200); 29 | #if defined(__AVR_ATmega32U4__) 30 | while (!Serial) 31 | ; //delay for Leonardo, but this loops forever for Maple Serial 32 | #endif 33 | #if defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) 34 | delay(2000); // To be able to connect Serial monitor after reset and before first printout 35 | #endif 36 | // Just to know which program is running on my Arduino 37 | Serial.println(F("START " __FILE__ " from " __DATE__)); 38 | 39 | // In case the interrupt driver crashes on setup, give a clue 40 | // to the user what's going on. 41 | Serial.println("Enabling IRin"); 42 | irrecv.enableIRIn(); // Start the receiver 43 | 44 | Serial.print(F("Ready to receive IR signals at pin ")); 45 | Serial.println(IR_RECEIVE_PIN); 46 | } 47 | 48 | void loop() { 49 | if (irrecv.decode(&results)) { 50 | Serial.println(results.value, HEX); 51 | irrecv.resume(); // Receive the next value 52 | } 53 | delay(100); 54 | } 55 | -------------------------------------------------------------------------------- /examples/IRsendDemo/IRsendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRsendDemo - demonstrates sending IR codes with IRsend 3 | * An IR LED must be connected to Arduino PWM pin 3. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | */ 8 | 9 | #include 10 | 11 | IRsend irsend; 12 | 13 | // On the Zero and others we switch explicitly to SerialUSB 14 | #if defined(ARDUINO_ARCH_SAMD) 15 | #define Serial SerialUSB 16 | #endif 17 | 18 | void setup() { 19 | pinMode(LED_BUILTIN, OUTPUT); 20 | 21 | Serial.begin(115200); 22 | #if defined(__AVR_ATmega32U4__) 23 | while (!Serial); //delay for Leonardo, but this loops forever for Maple Serial 24 | #endif 25 | #if defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) 26 | delay(2000); // To be able to connect Serial monitor after reset and before first printout 27 | #endif 28 | // Just to know which program is running on my Arduino 29 | Serial.println(F("START " __FILE__ " from " __DATE__)); 30 | Serial.print(F("Ready to send IR signals at pin ")); 31 | Serial.println(IR_SEND_PIN); 32 | } 33 | 34 | unsigned long tData = 0xa90; 35 | 36 | void loop() { 37 | 38 | for (int i = 0; i < 3; i++) { 39 | irsend.sendSony(tData, 12); 40 | Serial.print(F("sendSony(0x")); 41 | Serial.print(tData,HEX); 42 | Serial.println(F(", 12)")); 43 | // irsend.sendJVC(0xC5B8, 16,0); // hex value, 16 bits, no repeat 44 | // delayMicroseconds(50); // see http://www.sbprojects.com/knowledge/ir/jvc.php for information 45 | // irsend.sendJVC(0xC5B8, 16,1); // hex value, 16 bits, repeat 46 | // Serial.println(F("sendJVC(9xC5B8, 16)")); 47 | 48 | delay(40); 49 | } 50 | 51 | tData++; 52 | delay(5000); //5 second delay between each signal burst 53 | } 54 | -------------------------------------------------------------------------------- /examples/IRsendProntoDemo/IRsendProntoDemo.ino: -------------------------------------------------------------------------------- 1 | // Define exactly one of these 2 | //#define VAR_IN_PROGMEM 3 | #define VAR_IN_MEM 4 | //#define USE_F_FORM 5 | 6 | #define TIMES_TO_SEND 10U 7 | 8 | #include 9 | 10 | const char yamahaVolDown[] 11 | #ifdef VAR_IN_PROGMEM 12 | PROGMEM 13 | #endif 14 | = "0000 006C 0022 0002 " 15 | "015B 00AD 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0016 0016 0041 " 16 | "0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0016 0016 0016 " 17 | "0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0016 0016 0041 0016 0041 0016 0041 0016 05F7 015B 0057 0016 0E6C"; 18 | 19 | IRsend irsend; 20 | 21 | void setup() { 22 | Serial.begin(115200); 23 | while (!Serial) 24 | ; 25 | 26 | // Just to know which program is running on my Arduino 27 | Serial.println(F("START " __FILE__ " from " __DATE__)); 28 | 29 | Serial.print(F("Will send IR signals at pin ")); 30 | Serial.println(IR_SEND_PIN); 31 | } 32 | 33 | void loop() { 34 | 35 | 36 | #ifdef VAR_IN_PROGMEM 37 | Serial.println(F("Sending from PROGMEM")); 38 | irsend.sendPronto_PF(yamahaVolDown, TIMES_TO_SEND); 39 | #elif defined(VAR_IN_MEM) 40 | Serial.println(F("Sending from normal memory")); 41 | irsend.sendPronto(yamahaVolDown, TIMES_TO_SEND); 42 | #else 43 | Serial.println(F("Sending using the F()-form")); 44 | irsend.sendPronto(F("0000 006C 0022 0002 " 45 | "015B 00AD 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0016 0016 0041 " 46 | "0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0016 0016 0016 " 47 | "0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0016 0016 0041 0016 0041 0016 0041 0016 05F7 015B 0057 0016 0E6C"), TIMES_TO_SEND); 48 | #endif 49 | 50 | delay(5000); 51 | } 52 | -------------------------------------------------------------------------------- /src/ir_Dish.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // DDDD IIIII SSSS H H 5 | // D D I S H H 6 | // D D I SSS HHHHH 7 | // D D I S H H 8 | // DDDD IIIII SSSS H H 9 | //============================================================================== 10 | 11 | // Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand ) 12 | // 13 | // The sned function needs to be repeated 4 times 14 | // 15 | // Only send the last for characters of the hex. 16 | // I.E. Use 0x1C10 instead of 0x0000000000001C10 as listed in the LIRC file. 17 | // 18 | // Here is the LIRC file I found that seems to match the remote codes from the 19 | // oscilloscope: 20 | // DISH NETWORK (echostar 301): 21 | // http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx 22 | 23 | #define DISH_BITS 16 24 | #define DISH_HDR_MARK 400 25 | #define DISH_HDR_SPACE 6100 26 | #define DISH_BIT_MARK 400 27 | #define DISH_ONE_SPACE 1700 28 | #define DISH_ZERO_SPACE 2800 29 | #define DISH_RPT_SPACE 6200 30 | 31 | //+============================================================================= 32 | #if SEND_DISH 33 | void IRsend::sendDISH(unsigned long data, int nbits) { 34 | // Set IR carrier frequency 35 | enableIROut(56); 36 | 37 | mark(DISH_HDR_MARK); 38 | space(DISH_HDR_SPACE); 39 | 40 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 41 | if (data & mask) { 42 | mark(DISH_BIT_MARK); 43 | space(DISH_ONE_SPACE); 44 | } else { 45 | mark(DISH_BIT_MARK); 46 | space(DISH_ZERO_SPACE); 47 | } 48 | } 49 | mark(DISH_HDR_MARK); //added 26th March 2016, by AnalysIR ( https://www.AnalysIR.com ) 50 | } 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | This library is the culmination of the expertise of many members of the open source community who have dedicated their time and hard work. The best way to ask for help or propose a new idea is to [create a new issue](https://github.com/z3t0/Arduino-IRremote/issues/new) while creating a Pull Request with your code changes allows you to share your own innovations with the rest of the community. 4 | 5 | The following are some guidelines to observe when creating issues or PRs: 6 | - Be friendly; it is important that we can all enjoy a safe space as we are all working on the same project and it is okay for people to have different ideas 7 | - [Use code blocks](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code); **it helps us help you when we can read your code!** On that note also refrain from pasting more than 30 lines of code in a post, instead **[create a gist](https://gist.github.com/) if you need to share large snippets** 8 | - Use reasonable titles; refrain from using overly long or capitalized titles as they are usually annoying and do little to encourage others to help :smile: 9 | - Be detailed; refrain from mentioning code problems without sharing your source code and always give information regarding your board and version of the library 10 | - Use the style; we use the original [C Style by Kerninghan / Ritchie](https://en.wikipedia.org/wiki/Indentation_style#K&R_style) in [variant: 1TBS (OTBS)](https://en.wikipedia.org/wiki/Indentation_style#Variant:_1TBS_(OTBS)). In short: 4 spaces indentation, no tabs, opening braces on the same line, braces are mandatory on all if/while/do, no hard line length limit. To beautify your code, you may use the online formatter [here](https://www.freecodeformat.com/c-format.php). 11 | - Choose the right Pull Request target; if you only have **minor changes or adding a new protocol**, choose **master** as target for your Pull Request. If have a change **addressing more general aspects** of this library or think, that the PR should be **discussed and reviewed**, choose the **dev** branch as target for your Pull Request like described [here](https://guides.github.com/introduction/flow/). 12 | 13 | If there is any need to contact me then you can find my email on the README, I do not mind responding to emails but it would be in your own interests to create issues if you need help with the library as responses would be from a larger community with greater knowledge! -------------------------------------------------------------------------------- /src/ir_LG.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // L GGGG 5 | // L G 6 | // L G GG 7 | // L G G 8 | // LLLLL GGG 9 | //============================================================================== 10 | 11 | #define LG_BITS 28 12 | 13 | #define LG_HDR_MARK 8400 14 | #define LG_HDR_SPACE 4200 15 | #define LG_BIT_MARK 600 16 | #define LG_ONE_SPACE 1600 17 | #define LG_ZERO_SPACE 550 18 | #define LG_RPT_LENGTH 60000 19 | 20 | //+============================================================================= 21 | #if DECODE_LG 22 | bool IRrecv::decodeLG(decode_results *results) { 23 | long data = 0; 24 | int offset = 1; // Skip first space 25 | 26 | // Check we have the right amount of data 27 | if (irparams.rawlen < (2 * LG_BITS) + 1) 28 | return false; 29 | 30 | // Initial mark/space 31 | if (!MATCH_MARK(results->rawbuf[offset], LG_HDR_MARK)) { 32 | return false; 33 | } 34 | offset++; 35 | 36 | if (!MATCH_SPACE(results->rawbuf[offset], LG_HDR_SPACE)) { 37 | return false; 38 | } 39 | offset++; 40 | 41 | for (int i = 0; i < LG_BITS; i++) { 42 | if (!MATCH_MARK(results->rawbuf[offset], LG_BIT_MARK)) { 43 | return false; 44 | } 45 | offset++; 46 | 47 | if (MATCH_SPACE(results->rawbuf[offset], LG_ONE_SPACE)) { 48 | data = (data << 1) | 1; 49 | } else if (MATCH_SPACE(results->rawbuf[offset], LG_ZERO_SPACE)) { 50 | data = (data << 1) | 0; 51 | } else { 52 | return false; 53 | } 54 | offset++; 55 | } 56 | 57 | // Stop bit 58 | if (!MATCH_MARK(results->rawbuf[offset], LG_BIT_MARK)) { 59 | return false; 60 | } 61 | 62 | // Success 63 | results->bits = LG_BITS; 64 | results->value = data; 65 | results->decode_type = LG; 66 | return true; 67 | } 68 | #endif 69 | 70 | //+============================================================================= 71 | #if SEND_LG 72 | void IRsend::sendLG(unsigned long data, int nbits) { 73 | // Set IR carrier frequency 74 | enableIROut(38); 75 | 76 | // Header 77 | mark(LG_HDR_MARK); 78 | space(LG_HDR_SPACE); 79 | mark(LG_BIT_MARK); 80 | 81 | // Data 82 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 83 | if (data & mask) { 84 | space(LG_ONE_SPACE); 85 | mark(LG_BIT_MARK); 86 | } else { 87 | space(LG_ZERO_SPACE); 88 | mark(LG_BIT_MARK); 89 | } 90 | } 91 | space(0); // Always end with the LED off 92 | } 93 | #endif 94 | 95 | -------------------------------------------------------------------------------- /examples/IRsendRawDemo/IRsendRawDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRsendRawDemo - demonstrates sending IR codes with sendRaw 3 | * An IR LED must be connected to Arduino PWM pin 3. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | * 8 | * IRsendRawDemo - added by AnalysIR (via www.AnalysIR.com), 24 August 2015 9 | * 10 | * This example shows how to send a RAW signal using the IRremote library. 11 | * The example signal is actually a 32 bit NEC signal. 12 | * Remote Control button: LGTV Power On/Off. 13 | * Hex Value: 0x20DF10EF, 32 bits 14 | * 15 | * It is more efficient to use the sendNEC function to send NEC signals. 16 | * Use of sendRaw here, serves only as an example of using the function. 17 | * 18 | */ 19 | 20 | #include 21 | 22 | IRsend irsend; 23 | 24 | // On the Zero and others we switch explicitly to SerialUSB 25 | #if defined(ARDUINO_ARCH_SAMD) 26 | #define Serial SerialUSB 27 | #endif 28 | 29 | void setup() { 30 | pinMode(LED_BUILTIN, OUTPUT); 31 | 32 | Serial.begin(115200); 33 | #if defined(__AVR_ATmega32U4__) 34 | while (!Serial); //delay for Leonardo, but this loops forever for Maple Serial 35 | #endif 36 | #if defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) 37 | delay(2000); // To be able to connect Serial monitor after reset and before first printout 38 | #endif 39 | // Just to know which program is running on my Arduino 40 | Serial.println(F("START " __FILE__ " from " __DATE__)); 41 | Serial.print(F("Ready to send IR signals at pin ")); 42 | Serial.println(IR_SEND_PIN); 43 | } 44 | 45 | void loop() { 46 | int khz = 38; // 38kHz carrier frequency for the NEC protocol 47 | /* 48 | * Send data from RAM 49 | */ 50 | unsigned int irSignal[] = { 9000, 4500, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 51 | 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 52 | 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 53 | 1690, 560, 1690, 560, 39416, 9000, 2210, 560 }; // AnalysIR Batch Export (IRremote) - RAW 54 | irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); // Note the approach used to automatically calculate the size of the array. 55 | 56 | delay(2000); 57 | /* 58 | * Send data direct from FLASH 59 | */ 60 | unsigned int irSignalP[] PROGMEM = { 9000, 4500, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 61 | 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 560, 560, 560, 62 | 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 63 | 1690, 560, 1690, 560, 39416, 9000, 2210, 560 }; // AnalysIR Batch Export (IRremote) - RAW 64 | irsend.sendRaw_P(irSignalP, sizeof(irSignalP) / sizeof(irSignalP[0]), khz); // Note the approach used to automatically calculate the size of the array. 65 | 66 | delay(5000); //In this example, the signal will be repeated every 7 seconds, approximately. 67 | } 68 | -------------------------------------------------------------------------------- /src/ir_Panasonic.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // PPPP AAA N N AAA SSSS OOO N N IIIII CCCC 5 | // P P A A NN N A A S O O NN N I C 6 | // PPPP AAAAA N N N AAAAA SSS O O N N N I C 7 | // P A A N NN A A S O O N NN I C 8 | // P A A N N A A SSSS OOO N N IIIII CCCC 9 | //============================================================================== 10 | 11 | #define PANASONIC_BITS 48 12 | #define PANASONIC_HDR_MARK 3502 13 | #define PANASONIC_HDR_SPACE 1750 14 | #define PANASONIC_BIT_MARK 502 15 | #define PANASONIC_ONE_SPACE 1244 16 | #define PANASONIC_ZERO_SPACE 400 17 | 18 | //+============================================================================= 19 | #if SEND_PANASONIC 20 | void IRsend::sendPanasonic(unsigned int address, unsigned long data) { 21 | // Set IR carrier frequency 22 | enableIROut(37); // 36.7kHz is the correct frequency 23 | 24 | // Header 25 | mark(PANASONIC_HDR_MARK); 26 | space(PANASONIC_HDR_SPACE); 27 | 28 | // Address 29 | for (unsigned long mask = 1UL << (16 - 1); mask; mask >>= 1) { 30 | mark(PANASONIC_BIT_MARK); 31 | if (address & mask) 32 | space(PANASONIC_ONE_SPACE); 33 | else 34 | space(PANASONIC_ZERO_SPACE); 35 | } 36 | 37 | // Data 38 | for (unsigned long mask = 1UL << (32 - 1); mask; mask >>= 1) { 39 | mark(PANASONIC_BIT_MARK); 40 | if (data & mask) 41 | space(PANASONIC_ONE_SPACE); 42 | else 43 | space(PANASONIC_ZERO_SPACE); 44 | } 45 | 46 | // Footer 47 | mark(PANASONIC_BIT_MARK); 48 | space(0); // Always end with the LED off 49 | } 50 | #endif 51 | 52 | //+============================================================================= 53 | #if DECODE_PANASONIC 54 | bool IRrecv::decodePanasonic(decode_results *results) { 55 | unsigned long long data = 0; 56 | int offset = 1; 57 | 58 | if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_MARK)) { 59 | return false; 60 | } 61 | offset++; 62 | if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_SPACE)) { 63 | return false; 64 | } 65 | offset++; 66 | 67 | // decode address 68 | for (int i = 0; i < PANASONIC_BITS; i++) { 69 | if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_BIT_MARK)) { 70 | return false; 71 | } 72 | offset++; 73 | 74 | if (MATCH_SPACE(results->rawbuf[offset], PANASONIC_ONE_SPACE)) { 75 | data = (data << 1) | 1; 76 | } else if (MATCH_SPACE(results->rawbuf[offset], PANASONIC_ZERO_SPACE)) { 77 | data = (data << 1) | 0; 78 | } else { 79 | return false; 80 | } 81 | offset++; 82 | } 83 | 84 | results->value = (unsigned long) data; 85 | results->address = (unsigned int) (data >> 32); 86 | results->decode_type = PANASONIC; 87 | results->bits = PANASONIC_BITS; 88 | 89 | return true; 90 | } 91 | #endif 92 | 93 | -------------------------------------------------------------------------------- /src/ir_Sanyo.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // SSSS AAA N N Y Y OOO 5 | // S A A NN N Y Y O O 6 | // SSS AAAAA N N N Y O O 7 | // S A A N NN Y O O 8 | // SSSS A A N N Y OOO 9 | //============================================================================== 10 | 11 | // I think this is a Sanyo decoder: Serial = SA 8650B 12 | // Looks like Sony except for timings, 48 chars of data and time/space different 13 | 14 | #define SANYO_BITS 12 15 | #define SANYO_HDR_MARK 3500 // seen range 3500 16 | #define SANYO_HDR_SPACE 950 // seen 950 17 | #define SANYO_ONE_MARK 2400 // seen 2400 18 | #define SANYO_ZERO_MARK 700 // seen 700 19 | #define SANYO_DOUBLE_SPACE_USECS 800 // usually see 713 - not using ticks as get number wrap around 20 | #define SANYO_RPT_LENGTH 45000 21 | 22 | //+============================================================================= 23 | #if DECODE_SANYO 24 | bool IRrecv::decodeSanyo(decode_results *results) { 25 | long data = 0; 26 | unsigned int offset = 0; // Skip first space <-- CHECK THIS! 27 | 28 | if (irparams.rawlen < (2 * SANYO_BITS) + 2) { 29 | return false; 30 | } 31 | 32 | #if 0 33 | // Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay 34 | Serial.print("IR Gap: "); 35 | Serial.println( results->rawbuf[offset] * MICROS_PER_TICK); 36 | Serial.println( "test against:"); 37 | Serial.println(SANYO_DOUBLE_SPACE_USECS); 38 | #endif 39 | 40 | // Initial space 41 | if ((results->rawbuf[offset] * MICROS_PER_TICK) < SANYO_DOUBLE_SPACE_USECS) { 42 | //Serial.print("IR Gap found: "); 43 | results->bits = 0; 44 | results->value = REPEAT; 45 | results->decode_type = SANYO; 46 | return true; 47 | } 48 | offset++; 49 | 50 | // Initial mark 51 | if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) { 52 | return false; 53 | } 54 | offset++; 55 | 56 | // Skip Second Mark 57 | if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) { 58 | return false; 59 | } 60 | offset++; 61 | 62 | while (offset + 1 < irparams.rawlen) { 63 | if (!MATCH_SPACE(results->rawbuf[offset], SANYO_HDR_SPACE)) { 64 | break; 65 | } 66 | offset++; 67 | 68 | if (MATCH_MARK(results->rawbuf[offset], SANYO_ONE_MARK)) { 69 | data = (data << 1) | 1; 70 | } else if (MATCH_MARK(results->rawbuf[offset], SANYO_ZERO_MARK)) { 71 | data = (data << 1) | 0; 72 | } else { 73 | return false; 74 | } 75 | offset++; 76 | } 77 | 78 | // Success 79 | results->bits = (offset - 1) / 2; 80 | if (results->bits < 12) { 81 | results->bits = 0; 82 | return false; 83 | } 84 | 85 | results->value = data; 86 | results->decode_type = SANYO; 87 | return true; 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /src/ir_Mitsubishi.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // MMMMM IIIII TTTTT SSSS U U BBBB IIIII SSSS H H IIIII 5 | // M M M I T S U U B B I S H H I 6 | // M M M I T SSS U U BBBB I SSS HHHHH I 7 | // M M I T S U U B B I S H H I 8 | // M M IIIII T SSSS UUU BBBBB IIIII SSSS H H IIIII 9 | //============================================================================== 10 | 11 | // Looks like Sony except for timings, 48 chars of data and time/space different 12 | 13 | #define MITSUBISHI_BITS 16 14 | 15 | // Mitsubishi RM 75501 16 | // 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7 17 | // #define MITSUBISHI_HDR_MARK 250 // seen range 3500 18 | #define MITSUBISHI_HDR_SPACE 350 // 7*50+100 19 | #define MITSUBISHI_ONE_MARK 1950 // 41*50-100 20 | #define MITSUBISHI_ZERO_MARK 750 // 17*50-100 21 | // #define MITSUBISHI_DOUBLE_SPACE_USECS 800 // usually see 713 - not using ticks as get number wrap around 22 | // #define MITSUBISHI_RPT_LENGTH 45000 23 | 24 | //+============================================================================= 25 | #if DECODE_MITSUBISHI 26 | bool IRrecv::decodeMitsubishi (decode_results *results) 27 | { 28 | // Serial.print("?!? decoding Mitsubishi:");Serial.print(irparams.rawlen); Serial.print(" want "); Serial.println( 2 * MITSUBISHI_BITS + 2); 29 | long data = 0; 30 | if (irparams.rawlen < 2 * MITSUBISHI_BITS + 2) return false ; 31 | unsigned int offset = 0; // Skip first space 32 | // Initial space 33 | 34 | #if 0 35 | // Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay 36 | Serial.print("IR Gap: "); 37 | Serial.println( results->rawbuf[offset]); 38 | Serial.println( "test against:"); 39 | Serial.println(results->rawbuf[offset]); 40 | #endif 41 | 42 | #if 0 43 | // Not seeing double keys from Mitsubishi 44 | if (results->rawbuf[offset] < MITSUBISHI_DOUBLE_SPACE_USECS) { 45 | // Serial.print("IR Gap found: "); 46 | results->bits = 0; 47 | results->value = REPEAT; 48 | results->decode_type = MITSUBISHI; 49 | return true; 50 | } 51 | #endif 52 | 53 | offset++; 54 | 55 | // Typical 56 | // 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7 57 | 58 | // Initial Space 59 | if (!MATCH_MARK(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) return false ; 60 | offset++; 61 | 62 | while (offset + 1 < irparams.rawlen) { 63 | if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ONE_MARK)) data = (data << 1) | 1 ; 64 | else if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ZERO_MARK)) data <<= 1 ; 65 | else return false ; 66 | offset++; 67 | 68 | if (!MATCH_SPACE(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) break ; 69 | offset++; 70 | } 71 | 72 | // Success 73 | results->bits = (offset - 1) / 2; 74 | if (results->bits < MITSUBISHI_BITS) { 75 | results->bits = 0; 76 | return false; 77 | } 78 | 79 | results->value = data; 80 | results->decode_type = MITSUBISHI; 81 | return true; 82 | } 83 | #endif 84 | 85 | -------------------------------------------------------------------------------- /src/ir_Samsung.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // SSSS AAA MMM SSSS U U N N GGGG 5 | // S A A M M M S U U NN N G 6 | // SSS AAAAA M M M SSS U U N N N G GG 7 | // S A A M M S U U N NN G G 8 | // SSSS A A M M SSSS UUU N N GGG 9 | //============================================================================== 10 | 11 | #define SAMSUNG_BITS 32 12 | #define SAMSUNG_HDR_MARK 4500 13 | #define SAMSUNG_HDR_SPACE 4500 14 | #define SAMSUNG_BIT_MARK 560 15 | #define SAMSUNG_ONE_SPACE 1600 16 | #define SAMSUNG_ZERO_SPACE 560 17 | #define SAMSUNG_RPT_SPACE 2250 18 | 19 | //+============================================================================= 20 | #if SEND_SAMSUNG 21 | void IRsend::sendSAMSUNG(unsigned long data, int nbits) { 22 | // Set IR carrier frequency 23 | enableIROut(38); 24 | 25 | // Header 26 | mark(SAMSUNG_HDR_MARK); 27 | space(SAMSUNG_HDR_SPACE); 28 | 29 | // Data 30 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 31 | if (data & mask) { 32 | mark(SAMSUNG_BIT_MARK); 33 | space(SAMSUNG_ONE_SPACE); 34 | } else { 35 | mark(SAMSUNG_BIT_MARK); 36 | space(SAMSUNG_ZERO_SPACE); 37 | } 38 | } 39 | 40 | // Footer 41 | mark(SAMSUNG_BIT_MARK); 42 | space(0); // Always end with the LED off 43 | } 44 | #endif 45 | 46 | //+============================================================================= 47 | // SAMSUNGs have a repeat only 4 items long 48 | // 49 | #if DECODE_SAMSUNG 50 | bool IRrecv::decodeSAMSUNG(decode_results *results) { 51 | long data = 0; 52 | int offset = 1; // Skip first space 53 | 54 | // Initial mark 55 | if (!MATCH_MARK(results->rawbuf[offset], SAMSUNG_HDR_MARK)) { 56 | return false; 57 | } 58 | offset++; 59 | 60 | // Check for repeat 61 | if ((irparams.rawlen == 4) && MATCH_SPACE(results->rawbuf[offset], SAMSUNG_RPT_SPACE) 62 | && MATCH_MARK(results->rawbuf[offset + 1], SAMSUNG_BIT_MARK)) { 63 | results->bits = 0; 64 | results->value = REPEAT; 65 | results->decode_type = SAMSUNG; 66 | return true; 67 | } 68 | if (irparams.rawlen < (2 * SAMSUNG_BITS) + 4) { 69 | return false; 70 | } 71 | 72 | // Initial space 73 | if (!MATCH_SPACE(results->rawbuf[offset], SAMSUNG_HDR_SPACE)) { 74 | return false; 75 | } 76 | offset++; 77 | 78 | for (int i = 0; i < SAMSUNG_BITS; i++) { 79 | if (!MATCH_MARK(results->rawbuf[offset], SAMSUNG_BIT_MARK)) { 80 | return false; 81 | } 82 | offset++; 83 | 84 | if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ONE_SPACE)) { 85 | data = (data << 1) | 1; 86 | } else if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ZERO_SPACE)) { 87 | data = (data << 1) | 0; 88 | } else { 89 | return false; 90 | } 91 | offset++; 92 | } 93 | 94 | // Success 95 | results->bits = SAMSUNG_BITS; 96 | results->value = data; 97 | results->decode_type = SAMSUNG; 98 | return true; 99 | } 100 | #endif 101 | 102 | -------------------------------------------------------------------------------- /src/ir_Sony.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // SSSS OOO N N Y Y 5 | // S O O NN N Y Y 6 | // SSS O O N N N Y 7 | // S O O N NN Y 8 | // SSSS OOO N N Y 9 | //============================================================================== 10 | 11 | #define SONY_BITS 12 12 | #define SONY_HDR_MARK 2400 13 | #define SONY_HDR_SPACE 600 14 | #define SONY_ONE_MARK 1200 15 | #define SONY_ZERO_MARK 600 16 | #define SONY_RPT_LENGTH 45000 17 | #define SONY_DOUBLE_SPACE_USECS 500 // usually see 713 - not using ticks as get number wrap around 18 | 19 | //+============================================================================= 20 | #if SEND_SONY 21 | void IRsend::sendSony(unsigned long data, int nbits) { 22 | // Set IR carrier frequency 23 | enableIROut(40); 24 | 25 | // Header 26 | mark(SONY_HDR_MARK); 27 | space(SONY_HDR_SPACE); 28 | 29 | // Data 30 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 31 | if (data & mask) { 32 | mark(SONY_ONE_MARK); 33 | space(SONY_HDR_SPACE); 34 | } else { 35 | mark(SONY_ZERO_MARK); 36 | space(SONY_HDR_SPACE); 37 | } 38 | } 39 | 40 | // We will have ended with LED off 41 | } 42 | #endif 43 | 44 | //+============================================================================= 45 | #if DECODE_SONY 46 | bool IRrecv::decodeSony(decode_results *results) { 47 | long data = 0; 48 | unsigned int offset = 0; // Dont skip first space, check its size 49 | 50 | if (irparams.rawlen < (2 * SONY_BITS) + 2) { 51 | return false; 52 | } 53 | 54 | // Some Sony's deliver repeats fast after first 55 | // unfortunately can't spot difference from of repeat from two fast clicks 56 | if (results->rawbuf[offset] * MICROS_PER_TICK < SONY_DOUBLE_SPACE_USECS) { 57 | // Serial.print("IR Gap found: "); 58 | results->bits = 0; 59 | results->value = REPEAT; 60 | 61 | # ifdef DECODE_SANYO 62 | results->decode_type = SANYO; 63 | # else 64 | results->decode_type = UNKNOWN; 65 | # endif 66 | 67 | return true; 68 | } 69 | offset++; 70 | 71 | // Initial mark 72 | if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) { 73 | return false; 74 | } 75 | offset++; 76 | 77 | while (offset + 1 < irparams.rawlen) { 78 | if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) { 79 | break; 80 | } 81 | offset++; 82 | 83 | if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) { 84 | data = (data << 1) | 1; 85 | } else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) { 86 | data = (data << 1) | 0; 87 | } else { 88 | return false; 89 | } 90 | offset++; 91 | } 92 | 93 | // Success 94 | results->bits = (offset - 1) / 2; 95 | if (results->bits < 12) { 96 | results->bits = 0; 97 | return false; 98 | } 99 | results->value = data; 100 | results->decode_type = SONY; 101 | return true; 102 | } 103 | #endif 104 | 105 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at zuobaozhu@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /src/ir_JVC.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // JJJJJ V V CCCC 5 | // J V V C 6 | // J V V C 7 | // J J V V C 8 | // J V CCCC 9 | //============================================================================== 10 | 11 | #define JVC_BITS 16 12 | #define JVC_HDR_MARK 8400 13 | #define JVC_HDR_SPACE 4200 14 | #define JVC_BIT_MARK 600 15 | #define JVC_ONE_SPACE 1600 16 | #define JVC_ZERO_SPACE 550 17 | #define JVC_RPT_LENGTH 60000 18 | 19 | //+============================================================================= 20 | // JVC does NOT repeat by sending a separate code (like NEC does). 21 | // The JVC protocol repeats by skipping the header. 22 | // To send a JVC repeat signal, send the original code value 23 | // and set 'repeat' to true 24 | // 25 | #if SEND_JVC 26 | void IRsend::sendJVC(unsigned long data, int nbits, bool repeat) { 27 | // Set IR carrier frequency 28 | enableIROut(38); 29 | 30 | // Only send the Header if this is NOT a repeat command 31 | if (!repeat) { 32 | mark(JVC_HDR_MARK); 33 | space(JVC_HDR_SPACE); 34 | } 35 | 36 | // Data 37 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 38 | if (data & mask) { 39 | mark(JVC_BIT_MARK); 40 | space(JVC_ONE_SPACE); 41 | } else { 42 | mark(JVC_BIT_MARK); 43 | space(JVC_ZERO_SPACE); 44 | } 45 | } 46 | 47 | // Footer 48 | mark(JVC_BIT_MARK); 49 | space(0); // Always end with the LED off 50 | } 51 | #endif 52 | 53 | //+============================================================================= 54 | #if DECODE_JVC 55 | bool IRrecv::decodeJVC(decode_results *results) { 56 | long data = 0; 57 | int offset = 1; // Skip first space 58 | 59 | // Check for repeat 60 | if ((irparams.rawlen - 1 == 33) && MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK) 61 | && MATCH_MARK(results->rawbuf[irparams.rawlen - 1], JVC_BIT_MARK)) { 62 | results->bits = 0; 63 | results->value = REPEAT; 64 | results->decode_type = JVC; 65 | return true; 66 | } 67 | 68 | // Initial mark 69 | if (!MATCH_MARK(results->rawbuf[offset], JVC_HDR_MARK)) { 70 | return false; 71 | } 72 | offset++; 73 | 74 | if (irparams.rawlen < (2 * JVC_BITS) + 1) { 75 | return false; 76 | } 77 | 78 | // Initial space 79 | if (!MATCH_SPACE(results->rawbuf[offset], JVC_HDR_SPACE)) { 80 | return false; 81 | } 82 | offset++; 83 | 84 | for (int i = 0; i < JVC_BITS; i++) { 85 | if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)) { 86 | return false; 87 | } 88 | offset++; 89 | 90 | if (MATCH_SPACE(results->rawbuf[offset], JVC_ONE_SPACE)) { 91 | data = (data << 1) | 1; 92 | } else if (MATCH_SPACE(results->rawbuf[offset], JVC_ZERO_SPACE)) { 93 | data = (data << 1) | 0; 94 | } else { 95 | return false; 96 | } 97 | offset++; 98 | } 99 | 100 | // Stop bit 101 | if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)) { 102 | return false; 103 | } 104 | 105 | // Success 106 | results->bits = JVC_BITS; 107 | results->value = data; 108 | results->decode_type = JVC; 109 | 110 | return true; 111 | } 112 | #endif 113 | 114 | -------------------------------------------------------------------------------- /src/ir_Whynter.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // W W H H Y Y N N TTTTT EEEEE RRRRR 5 | // W W H H Y Y NN N T E R R 6 | // W W W HHHHH Y N N N T EEE RRRR 7 | // W W W H H Y N NN T E R R 8 | // WWW H H Y N N T EEEEE R R 9 | //============================================================================== 10 | 11 | #define WHYNTER_BITS 32 12 | #define WHYNTER_HDR_MARK 2850 13 | #define WHYNTER_HDR_SPACE 2850 14 | #define WHYNTER_BIT_MARK 750 15 | #define WHYNTER_ONE_MARK 750 16 | #define WHYNTER_ONE_SPACE 2150 17 | #define WHYNTER_ZERO_MARK 750 18 | #define WHYNTER_ZERO_SPACE 750 19 | 20 | //+============================================================================= 21 | #if SEND_WHYNTER 22 | void IRsend::sendWhynter(unsigned long data, int nbits) { 23 | // Set IR carrier frequency 24 | enableIROut(38); 25 | 26 | // Start 27 | mark(WHYNTER_ZERO_MARK); 28 | space(WHYNTER_ZERO_SPACE); 29 | 30 | // Header 31 | mark(WHYNTER_HDR_MARK); 32 | space(WHYNTER_HDR_SPACE); 33 | 34 | // Data 35 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 36 | if (data & mask) { 37 | mark(WHYNTER_ONE_MARK); 38 | space(WHYNTER_ONE_SPACE); 39 | } else { 40 | mark(WHYNTER_ZERO_MARK); 41 | space(WHYNTER_ZERO_SPACE); 42 | } 43 | } 44 | 45 | // Footer 46 | mark(WHYNTER_ZERO_MARK); 47 | space(WHYNTER_ZERO_SPACE); // Always end with the LED off 48 | } 49 | #endif 50 | 51 | //+============================================================================= 52 | #if DECODE_WHYNTER 53 | bool IRrecv::decodeWhynter(decode_results *results) { 54 | long data = 0; 55 | int offset = 1; // skip initial space 56 | 57 | // Check we have the right amount of data 58 | if (irparams.rawlen < (2 * WHYNTER_BITS) + 6) { 59 | return false; 60 | } 61 | 62 | // Sequence begins with a bit mark and a zero space 63 | if (!MATCH_MARK(results->rawbuf[offset], WHYNTER_BIT_MARK)) { 64 | return false; 65 | } 66 | offset++; 67 | 68 | if (!MATCH_SPACE(results->rawbuf[offset], WHYNTER_ZERO_SPACE)) { 69 | return false; 70 | } 71 | offset++; 72 | 73 | // header mark and space 74 | if (!MATCH_MARK(results->rawbuf[offset], WHYNTER_HDR_MARK)) { 75 | return false; 76 | } 77 | offset++; 78 | 79 | if (!MATCH_SPACE(results->rawbuf[offset], WHYNTER_HDR_SPACE)) { 80 | return false; 81 | } 82 | offset++; 83 | 84 | // data bits 85 | for (int i = 0; i < WHYNTER_BITS; i++) { 86 | if (!MATCH_MARK(results->rawbuf[offset], WHYNTER_BIT_MARK)) { 87 | return false; 88 | } 89 | offset++; 90 | 91 | if (MATCH_SPACE(results->rawbuf[offset], WHYNTER_ONE_SPACE)) { 92 | data = (data << 1) | 1; 93 | } else if (MATCH_SPACE(results->rawbuf[offset], WHYNTER_ZERO_SPACE)) { 94 | data = (data << 1) | 0; 95 | } else { 96 | return false; 97 | } 98 | offset++; 99 | } 100 | 101 | // trailing mark 102 | if (!MATCH_MARK(results->rawbuf[offset], WHYNTER_BIT_MARK)) { 103 | return false; 104 | } 105 | 106 | // Success 107 | results->bits = WHYNTER_BITS; 108 | results->value = data; 109 | results->decode_type = WHYNTER; 110 | return true; 111 | } 112 | #endif 113 | 114 | -------------------------------------------------------------------------------- /src/ir_NEC.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // N N EEEEE CCCC 5 | // NN N E C 6 | // N N N EEE C 7 | // N NN E C 8 | // N N EEEEE CCCC 9 | //============================================================================== 10 | 11 | #define NEC_BITS 32 12 | #define NEC_HDR_MARK 9000 13 | #define NEC_HDR_SPACE 4500 14 | #define NEC_BIT_MARK 560 15 | #define NEC_ONE_SPACE 1690 16 | #define NEC_ZERO_SPACE 560 17 | #define NEC_RPT_SPACE 2250 18 | 19 | //+============================================================================= 20 | #if SEND_NEC 21 | /* 22 | * Repeat commands should be sent in a 110 ms raster. 23 | * https://www.sbprojects.net/knowledge/ir/nec.php 24 | */ 25 | void IRsend::sendNEC(unsigned long data, int nbits, bool repeat) { 26 | // Set IR carrier frequency 27 | enableIROut(38); 28 | 29 | // Header 30 | mark(NEC_HDR_MARK); 31 | 32 | if (data == REPEAT || repeat) { 33 | // repeat "space and data" 34 | space(NEC_RPT_SPACE); 35 | mark(NEC_BIT_MARK); 36 | } else { 37 | 38 | space(NEC_HDR_SPACE); 39 | 40 | // Data 41 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 42 | if (data & mask) { 43 | mark(NEC_BIT_MARK); 44 | space(NEC_ONE_SPACE); 45 | } else { 46 | mark(NEC_BIT_MARK); 47 | space(NEC_ZERO_SPACE); 48 | } 49 | } 50 | 51 | // Footer 52 | mark(NEC_BIT_MARK); 53 | } 54 | space(0); // Always end with the LED off 55 | } 56 | #endif 57 | 58 | //+============================================================================= 59 | // NECs have a repeat only 4 items long 60 | // 61 | #if DECODE_NEC 62 | bool IRrecv::decodeNEC(decode_results *results) { 63 | long data = 0; // We decode in to here; Start with nothing 64 | int offset = 1; // Index in to results; Skip first entry!? 65 | 66 | // Check header "mark" 67 | if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) { 68 | return false; 69 | } 70 | offset++; 71 | 72 | // Check for repeat 73 | if ((irparams.rawlen == 4) && MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) 74 | && MATCH_MARK(results->rawbuf[offset + 1], NEC_BIT_MARK)) { 75 | results->bits = 0; 76 | results->value = REPEAT; 77 | results->decode_type = NEC; 78 | return true; 79 | } 80 | 81 | // Check we have enough data 82 | if (irparams.rawlen < (2 * NEC_BITS) + 4) { 83 | return false; 84 | } 85 | // Check header "space" 86 | if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) { 87 | return false; 88 | } 89 | offset++; 90 | 91 | // Build the data 92 | for (int i = 0; i < NEC_BITS; i++) { 93 | // Check data "mark" 94 | if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) { 95 | return false; 96 | } 97 | offset++; 98 | 99 | if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) { 100 | data = (data << 1) | 1; 101 | } else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) { 102 | data = (data << 1) | 0; 103 | } else { 104 | return false; 105 | } 106 | offset++; 107 | } 108 | 109 | // Success 110 | results->bits = NEC_BITS; 111 | results->value = data; 112 | results->decode_type = NEC; 113 | 114 | return true; 115 | } 116 | #endif 117 | -------------------------------------------------------------------------------- /src/ir_Denon.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | // Reverse Engineered by looking at RAW dumps generated by IRremote 4 | 5 | // I have since discovered that Denon publish all their IR codes: 6 | // https://www.google.co.uk/search?q=DENON+MASTER+IR+Hex+Command+Sheet 7 | // -> http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls 8 | 9 | // Having looked at the official Denon Pronto sheet and reverse engineered 10 | // the timing values from it, it is obvious that Denon have a range of 11 | // different timings and protocols ...the values here work for my AVR-3801 Amp! 12 | 13 | //============================================================================== 14 | // DDDD EEEEE N N OOO N N 15 | // D D E NN N O O NN N 16 | // D D EEE N N N O O N N N 17 | // D D E N NN O O N NN 18 | // DDDD EEEEE N N OOO N N 19 | //============================================================================== 20 | 21 | #define BITS 14 // The number of bits in the command 22 | 23 | #define HDR_MARK 300 // The length of the Header:Mark 24 | #define HDR_SPACE 750 // The lenght of the Header:Space 25 | 26 | #define BIT_MARK 300 // The length of a Bit:Mark 27 | #define ONE_SPACE 1800 // The length of a Bit:Space for 1's 28 | #define ZERO_SPACE 750 // The length of a Bit:Space for 0's 29 | 30 | //+============================================================================= 31 | // 32 | #if SEND_DENON 33 | void IRsend::sendDenon(unsigned long data, int nbits) { 34 | // Set IR carrier frequency 35 | enableIROut(38); 36 | 37 | // Header 38 | mark(HDR_MARK); 39 | space(HDR_SPACE); 40 | 41 | // Data 42 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 43 | if (data & mask) { 44 | mark(BIT_MARK); 45 | space(ONE_SPACE); 46 | } else { 47 | mark(BIT_MARK); 48 | space(ZERO_SPACE); 49 | } 50 | } 51 | 52 | // Footer 53 | mark(BIT_MARK); 54 | space(0); // Always end with the LED off 55 | } 56 | #endif 57 | 58 | //+============================================================================= 59 | // 60 | #if DECODE_DENON 61 | bool IRrecv::decodeDenon(decode_results *results) { 62 | unsigned long data = 0; // Somewhere to build our code 63 | int offset = 1; // Skip the Gap reading 64 | 65 | // Check we have the right amount of data 66 | if (irparams.rawlen != 1 + 2 + (2 * BITS) + 1) { 67 | return false; 68 | } 69 | 70 | // Check initial Mark+Space match 71 | if (!MATCH_MARK(results->rawbuf[offset], HDR_MARK)) { 72 | return false; 73 | } 74 | offset++; 75 | 76 | if (!MATCH_SPACE(results->rawbuf[offset], HDR_SPACE)) { 77 | return false; 78 | } 79 | offset++; 80 | 81 | // Read the bits in 82 | for (int i = 0; i < BITS; i++) { 83 | // Each bit looks like: MARK + SPACE_1 -> 1 84 | // or : MARK + SPACE_0 -> 0 85 | if (!MATCH_MARK(results->rawbuf[offset], BIT_MARK)) { 86 | return false; 87 | } 88 | offset++; 89 | 90 | // IR data is big-endian, so we shuffle it in from the right: 91 | if (MATCH_SPACE(results->rawbuf[offset], ONE_SPACE)) { 92 | data = (data << 1) | 1; 93 | } else if (MATCH_SPACE(results->rawbuf[offset], ZERO_SPACE)) { 94 | data = (data << 1) | 0; 95 | } else { 96 | return false; 97 | } 98 | offset++; 99 | } 100 | 101 | // Success 102 | results->bits = BITS; 103 | results->value = data; 104 | results->decode_type = DENON; 105 | return true; 106 | } 107 | #endif 108 | -------------------------------------------------------------------------------- /examples/IRrecvDump/IRrecvDump.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: 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 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 8 | * LG added by Darryl Smith (based on the JVC protocol) 9 | */ 10 | 11 | #include 12 | 13 | /* 14 | * Default is Arduino pin D11. 15 | * You can change this to another available Arduino Pin. 16 | * Your IR receiver should be connected to the pin defined here 17 | */ 18 | #if defined(ESP32) 19 | int IR_RECEIVE_PIN = 15; 20 | #else 21 | int IR_RECEIVE_PIN = 11; 22 | #endif 23 | 24 | IRrecv irrecv(IR_RECEIVE_PIN); 25 | 26 | decode_results results; 27 | 28 | // On the Zero and others we switch explicitly to SerialUSB 29 | #if defined(ARDUINO_ARCH_SAMD) 30 | #define Serial SerialUSB 31 | #endif 32 | 33 | void setup() { 34 | pinMode(LED_BUILTIN, OUTPUT); 35 | 36 | Serial.begin(115200); 37 | #if defined(__AVR_ATmega32U4__) 38 | while (!Serial) 39 | ; //delay for Leonardo, but this loops forever for Maple Serial 40 | #endif 41 | #if defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) 42 | delay(2000); // To be able to connect Serial monitor after reset and before first printout 43 | #endif 44 | // Just to know which program is running on my Arduino 45 | Serial.println(F("START " __FILE__ " from " __DATE__)); 46 | irrecv.enableIRIn(); // Start the receiver 47 | 48 | Serial.print(F("Ready to receive IR signals at pin ")); 49 | Serial.println(IR_RECEIVE_PIN); 50 | } 51 | 52 | void dump(decode_results *results) { 53 | // Dumps out the decode_results structure. 54 | // Call this after IRrecv::decode() 55 | int count = results->rawlen; 56 | if (results->decode_type == UNKNOWN) { 57 | Serial.print("Unknown encoding: "); 58 | } else if (results->decode_type == NEC) { 59 | Serial.print("Decoded NEC: "); 60 | 61 | } else if (results->decode_type == SONY) { 62 | Serial.print("Decoded SONY: "); 63 | } else if (results->decode_type == RC5) { 64 | Serial.print("Decoded RC5: "); 65 | } else if (results->decode_type == RC6) { 66 | Serial.print("Decoded RC6: "); 67 | } else if (results->decode_type == PANASONIC) { 68 | Serial.print("Decoded PANASONIC - Address: "); 69 | Serial.print(results->address, HEX); 70 | Serial.print(" Value: "); 71 | } else if (results->decode_type == LG) { 72 | Serial.print("Decoded LG: "); 73 | } else if (results->decode_type == JVC) { 74 | Serial.print("Decoded JVC: "); 75 | } else if (results->decode_type == AIWA_RC_T501) { 76 | Serial.print("Decoded AIWA RC T501: "); 77 | } else if (results->decode_type == WHYNTER) { 78 | Serial.print("Decoded Whynter: "); 79 | } else if (results->decode_type == BOSEWAVE) { 80 | Serial.print("Decoded Bose Wave Radio / CD: "); 81 | } 82 | Serial.print(results->value, HEX); 83 | Serial.print(" ("); 84 | Serial.print(results->bits, DEC); 85 | Serial.println(" bits)"); 86 | Serial.print("Raw ("); 87 | Serial.print(count, DEC); 88 | Serial.print("): "); 89 | 90 | for (int i = 1; i < count; i++) { 91 | if (i & 1) { 92 | Serial.print(results->rawbuf[i] * MICROS_PER_TICK, DEC); 93 | } else { 94 | Serial.write('-'); 95 | Serial.print((unsigned long) results->rawbuf[i] * MICROS_PER_TICK, DEC); 96 | } 97 | Serial.print(" "); 98 | } 99 | Serial.println(); 100 | } 101 | 102 | void loop() { 103 | if (irrecv.decode(&results)) { 104 | Serial.println(results.value, HEX); 105 | dump(&results); 106 | irrecv.resume(); // Receive the next value 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /examples/IRrelay/IRrelay.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRrelay - demonstrates receiving IR codes with IRrecv 3 | * Toggles an output pin at each command received 4 | * An IR detector/demodulator must be connected to the input RECV_PIN. 5 | * Version 0.1 July, 2009 6 | * Copyright 2009 Ken Shirriff 7 | * http://arcfn.com 8 | */ 9 | 10 | #include 11 | 12 | #if defined(ESP32) 13 | int IR_RECEIVE_PIN = 15; 14 | #else 15 | int IR_RECEIVE_PIN = 11; 16 | #endif 17 | int RELAY_PIN = 4; // is labeled D2 on the Chinese SAMD21 M0-Mini clone 18 | 19 | IRrecv irrecv(IR_RECEIVE_PIN); 20 | decode_results results; 21 | 22 | // On the Zero and others we switch explicitly to SerialUSB 23 | #if defined(ARDUINO_ARCH_SAMD) 24 | #define Serial SerialUSB 25 | // The Chinese SAMD21 M0-Mini clone has no led connected, if you connect it, it is on pin 24 like on the original board. 26 | // Attention! D2 and D4 are reversed on these boards 27 | //#undef LED_BUILTIN 28 | //#define LED_BUILTIN 25 // Or choose pin 25, it is the RX pin, but active low. 29 | #endif 30 | 31 | void dump(decode_results *results); 32 | 33 | void setup() { 34 | pinMode(LED_BUILTIN, OUTPUT); 35 | pinMode(RELAY_PIN, OUTPUT); 36 | 37 | Serial.begin(115200); 38 | #if defined(__AVR_ATmega32U4__) 39 | while (!Serial); //delay for Leonardo, but this loops forever for Maple Serial 40 | #endif 41 | #if defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) 42 | delay(2000); // To be able to connect Serial monitor after reset and before first printout 43 | #endif 44 | // Just to know which program is running on my Arduino 45 | Serial.println(F("START " __FILE__ " from " __DATE__)); 46 | 47 | irrecv.enableIRIn(); // Start the receiver 48 | 49 | Serial.print(F("Ready to receive IR signals at pin ")); 50 | Serial.println(IR_RECEIVE_PIN); 51 | } 52 | 53 | int on = 0; 54 | unsigned long last = millis(); 55 | 56 | void loop() { 57 | if (irrecv.decode(&results)) { 58 | // If it's been at least 1/4 second since the last 59 | // IR received, toggle the relay 60 | if (millis() - last > 250) { 61 | on = !on; 62 | Serial.print(F("Switch relay ")); 63 | if (on) { 64 | digitalWrite(RELAY_PIN, HIGH); 65 | digitalWrite(LED_BUILTIN, HIGH); 66 | Serial.println(F("on")); 67 | } else { 68 | digitalWrite(RELAY_PIN, LOW); 69 | digitalWrite(LED_BUILTIN, LOW); 70 | Serial.println(F("off")); 71 | } 72 | dump(&results); 73 | } 74 | last = millis(); 75 | irrecv.resume(); // Receive the next value 76 | } 77 | } 78 | 79 | 80 | // Dumps out the decode_results structure. 81 | // Call this after IRrecv::decode() 82 | // void * to work around compiler issue 83 | //void dump(void *v) { 84 | // decode_results *results = (decode_results *)v 85 | void dump(decode_results *results) { 86 | int count = results->rawlen; 87 | if (results->decode_type == UNKNOWN) { 88 | Serial.println("Could not decode message"); 89 | } else { 90 | if (results->decode_type == NEC) { 91 | Serial.print("Decoded NEC: "); 92 | } else if (results->decode_type == SONY) { 93 | Serial.print("Decoded SONY: "); 94 | } else if (results->decode_type == RC5) { 95 | Serial.print("Decoded RC5: "); 96 | } else if (results->decode_type == RC6) { 97 | Serial.print("Decoded RC6: "); 98 | } 99 | Serial.print(results->value, HEX); 100 | Serial.print(" ("); 101 | Serial.print(results->bits, DEC); 102 | Serial.println(" bits)"); 103 | } 104 | Serial.print("Raw ("); 105 | Serial.print(count, DEC); 106 | Serial.print("): "); 107 | 108 | for (int i = 0; i < count; i++) { 109 | if ((i % 2) == 1) { 110 | Serial.print(results->rawbuf[i] * MICROS_PER_TICK, DEC); 111 | } else { 112 | Serial.print(-(int) results->rawbuf[i] * MICROS_PER_TICK, DEC); 113 | } 114 | Serial.print(" "); 115 | } 116 | Serial.println(""); 117 | } 118 | -------------------------------------------------------------------------------- /src/sam.cpp: -------------------------------------------------------------------------------- 1 | // Support routines for SAM processor boards 2 | 3 | #include "IRremote.h" 4 | 5 | #if defined(ARDUINO_ARCH_SAMD) 6 | 7 | // "Idiot check" 8 | #ifdef USE_DEFAULT_ENABLE_IR_IN 9 | #error Must undef USE_DEFAULT_ENABLE_IR_IN 10 | #endif 11 | 12 | //+============================================================================= 13 | // ATSAMD Timer setup & IRQ functions 14 | // 15 | 16 | // following based on setup from GitHub jdneo/timerInterrupt.ino 17 | 18 | static void setTimerFrequency(int frequencyHz) 19 | { 20 | int compareValue = (SYSCLOCK / (TIMER_PRESCALER_DIV * frequencyHz)) - 1; 21 | //Serial.println(compareValue); 22 | TcCount16 *TC = (TcCount16 *)TC3; 23 | // Make sure the count is in a proportional position to where it was 24 | // to prevent any jitter or disconnect when changing the compare value. 25 | TC->COUNT.reg = map(TC->COUNT.reg, 0, TC->CC[0].reg, 0, compareValue); 26 | TC->CC[0].reg = compareValue; 27 | //Serial.print("COUNT.reg "); 28 | //Serial.println(TC->COUNT.reg); 29 | //Serial.print("CC[0].reg "); 30 | //Serial.println(TC->CC[0].reg); 31 | 32 | #ifdef __SAMD51__ 33 | while (TC->SYNCBUSY.bit.ENABLE == 1) 34 | ; // 35 | #else 36 | while (TC->STATUS.bit.SYNCBUSY == 1) 37 | ; // wait for sync 38 | #endif 39 | } 40 | 41 | static void startTimer() 42 | { 43 | #ifdef __SAMD51__ 44 | GCLK->PCHCTRL[TC3_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); 45 | #else 46 | REG_GCLK_CLKCTRL = (uint16_t)(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_TCC2_TC3); 47 | while (GCLK->STATUS.bit.SYNCBUSY == 1) 48 | ; // wait for sync 49 | #endif 50 | 51 | TcCount16 *TC = (TcCount16 *)TC3; 52 | 53 | // The TC should be disabled before the TC is reset in order to avoid undefined behavior. 54 | TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; 55 | // When write-synchronization is ongoing for a register, any subsequent write attempts to this register will be discarded, and an error will be reported. 56 | #ifdef __SAMD51__ 57 | while (TC->SYNCBUSY.bit.ENABLE == 1) 58 | ; // 59 | #else 60 | while (TC->STATUS.bit.SYNCBUSY == 1) 61 | ; // wait for sync 62 | #endif 63 | // Reset TCx 64 | TC->CTRLA.reg = TC_CTRLA_SWRST; 65 | // When writing a �1� to the CTRLA.SWRST bit it will immediately read as �1�. 66 | // CTRL.SWRST will be cleared by hardware when the peripheral has been reset. 67 | while (TC->CTRLA.bit.SWRST) 68 | ; 69 | 70 | // Use the 16-bit timer 71 | // Use match mode so that the timer counter resets when the count matches the compare register 72 | // Set prescaler to 64 73 | #ifdef __SAMD51__ 74 | TC->WAVE.reg = TC_WAVE_WAVEGEN_MFRQ; 75 | #else 76 | TC->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; 77 | #endif 78 | TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER_DIV64 | TC_CTRLA_ENABLE; 79 | 80 | setTimerFrequency(1000000 / MICROS_PER_TICK); 81 | 82 | // Enable the compare interrupt 83 | TC->INTENSET.reg = 0; 84 | TC->INTENSET.bit.MC0 = 1; 85 | 86 | NVIC_EnableIRQ(TC3_IRQn); 87 | } 88 | 89 | //+============================================================================= 90 | // initialization 91 | // 92 | 93 | void IRrecv::enableIRIn() 94 | { 95 | // Interrupt Service Routine - Fires every 50uS 96 | //Serial.println("Starting timer"); 97 | startTimer(); 98 | //Serial.println("Started timer"); 99 | 100 | // Initialize state machine variables 101 | irparams.rcvstate = IR_REC_STATE_IDLE; 102 | irparams.rawlen = 0; 103 | 104 | // Set pin modes 105 | pinMode(irparams.recvpin, INPUT); 106 | } 107 | 108 | void IRrecv::disableIRIn() 109 | { 110 | TC3->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE; 111 | } 112 | 113 | void irs(); // Defined in IRRemote as ISR(TIMER_INTR_NAME) 114 | 115 | void TC3_Handler(void) 116 | { 117 | TcCount16 *TC = (TcCount16 *)TC3; 118 | // If this interrupt is due to the compare register matching the timer count 119 | // we toggle the LED. 120 | if (TC->INTFLAG.bit.MC0 == 1) 121 | { 122 | TC->INTFLAG.bit.MC0 = 1; 123 | irs(); 124 | } 125 | } 126 | 127 | #endif // defined(ARDUINO_ARCH_SAMD) 128 | -------------------------------------------------------------------------------- /src/ir_Aiwa.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // AAA IIIII W W AAA 5 | // A A I W W A A 6 | // AAAAA I W W W AAAAA 7 | // A A I W W W A A 8 | // A A IIIII WWW A A 9 | //============================================================================== 10 | 11 | // Based off the RC-T501 RCU 12 | // Lirc file http://lirc.sourceforge.net/remotes/aiwa/RC-T501 13 | 14 | #define AIWA_RC_T501_HZ 38 15 | #define AIWA_RC_T501_BITS 15 16 | #define AIWA_RC_T501_PRE_BITS 26 17 | #define AIWA_RC_T501_POST_BITS 1 18 | #define AIWA_RC_T501_SUM_BITS (AIWA_RC_T501_PRE_BITS + AIWA_RC_T501_BITS + AIWA_RC_T501_POST_BITS) 19 | #define AIWA_RC_T501_HDR_MARK 8800 20 | #define AIWA_RC_T501_HDR_SPACE 4500 21 | #define AIWA_RC_T501_BIT_MARK 500 22 | #define AIWA_RC_T501_ONE_SPACE 600 23 | #define AIWA_RC_T501_ZERO_SPACE 1700 24 | 25 | //+============================================================================= 26 | #if SEND_AIWA_RC_T501 27 | void IRsend::sendAiwaRCT501(int code) { 28 | unsigned long pre = 0x0227EEC0; // 26-bits 29 | 30 | // Set IR carrier frequency 31 | enableIROut(AIWA_RC_T501_HZ); 32 | 33 | // Header 34 | mark(AIWA_RC_T501_HDR_MARK); 35 | space(AIWA_RC_T501_HDR_SPACE); 36 | 37 | // Send "pre" data 38 | for (unsigned long mask = 1UL << (26 - 1); mask; mask >>= 1) { 39 | mark(AIWA_RC_T501_BIT_MARK); 40 | if (pre & mask) 41 | space(AIWA_RC_T501_ONE_SPACE); 42 | else 43 | space(AIWA_RC_T501_ZERO_SPACE); 44 | } 45 | 46 | //-v- THIS CODE LOOKS LIKE IT MIGHT BE WRONG - CHECK! 47 | // it only send 15bits and ignores the top bit 48 | // then uses TOPBIT which is 0x80000000 to check the bit code 49 | // I suspect TOPBIT should be changed to 0x00008000 50 | 51 | // Skip first code bit 52 | code <<= 1; 53 | // Send code 54 | for (int i = 0; i < 15; i++) { 55 | mark(AIWA_RC_T501_BIT_MARK); 56 | if (code & 0x80000000) 57 | space(AIWA_RC_T501_ONE_SPACE); 58 | else 59 | space(AIWA_RC_T501_ZERO_SPACE); 60 | code <<= 1; 61 | } 62 | 63 | //-^- THIS CODE LOOKS LIKE IT MIGHT BE WRONG - CHECK! 64 | 65 | // POST-DATA, 1 bit, 0x0 66 | mark(AIWA_RC_T501_BIT_MARK); 67 | space(AIWA_RC_T501_ZERO_SPACE); 68 | 69 | mark(AIWA_RC_T501_BIT_MARK); 70 | space(0); 71 | } 72 | #endif 73 | 74 | //+============================================================================= 75 | #if DECODE_AIWA_RC_T501 76 | bool IRrecv::decodeAiwaRCT501(decode_results *results) { 77 | int data = 0; 78 | unsigned int offset = 1; 79 | 80 | // Check SIZE 81 | if (irparams.rawlen < 2 * (AIWA_RC_T501_SUM_BITS) + 4) { 82 | return false; 83 | } 84 | 85 | // Check HDR Mark/Space 86 | if (!MATCH_MARK(results->rawbuf[offset], AIWA_RC_T501_HDR_MARK)) { 87 | return false; 88 | } 89 | offset++; 90 | 91 | if (!MATCH_SPACE(results->rawbuf[offset], AIWA_RC_T501_HDR_SPACE)) { 92 | return false; 93 | } 94 | offset++; 95 | 96 | offset += 26; // skip pre-data - optional 97 | while (offset < irparams.rawlen - 4) { 98 | if (MATCH_MARK(results->rawbuf[offset], AIWA_RC_T501_BIT_MARK)) { 99 | offset++; 100 | } else { 101 | return false; 102 | } 103 | 104 | // ONE & ZERO 105 | if (MATCH_SPACE(results->rawbuf[offset], AIWA_RC_T501_ONE_SPACE)) { 106 | data = (data << 1) | 1; 107 | } else if (MATCH_SPACE(results->rawbuf[offset], AIWA_RC_T501_ZERO_SPACE)) { 108 | data = (data << 1) | 0; 109 | } else { 110 | break; // End of one & zero detected 111 | } 112 | offset++; 113 | } 114 | 115 | results->bits = (offset - 1) / 2; 116 | if (results->bits < 42) { 117 | return false; 118 | } 119 | 120 | results->value = data; 121 | results->decode_type = AIWA_RC_T501; 122 | return true; 123 | } 124 | #endif 125 | -------------------------------------------------------------------------------- /src/ir_Lego_PF_BitStreamEncoder.h: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // L EEEEEE EEEE OOOO 3 | // L E E O O 4 | // L EEEE E EEE O O 5 | // L E E E O O LEGO Power Functions 6 | // LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016, 2017 Philipp Henkel 7 | //============================================================================== 8 | 9 | //+============================================================================= 10 | // 11 | 12 | class LegoPfBitStreamEncoder { 13 | private: 14 | uint16_t data; 15 | bool repeatMessage; 16 | uint8_t messageBitIdx; 17 | uint8_t repeatCount; 18 | uint16_t messageLength; 19 | 20 | public: 21 | // HIGH data bit = IR mark + high pause 22 | // LOW data bit = IR mark + low pause 23 | static const uint16_t LOW_BIT_DURATION = 421; 24 | static const uint16_t HIGH_BIT_DURATION = 711; 25 | static const uint16_t START_BIT_DURATION = 1184; 26 | static const uint16_t STOP_BIT_DURATION = 1184; 27 | static const uint8_t IR_MARK_DURATION = 158; 28 | static const uint16_t HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION; 29 | static const uint16_t LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION; 30 | static const uint16_t START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION; 31 | static const uint16_t STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION; 32 | static const uint8_t MESSAGE_BITS = 18; 33 | static const uint16_t MAX_MESSAGE_LENGTH = 16000; 34 | 35 | void reset(uint16_t data, bool repeatMessage) { 36 | this->data = data; 37 | this->repeatMessage = repeatMessage; 38 | messageBitIdx = 0; 39 | repeatCount = 0; 40 | messageLength = getMessageLength(); 41 | } 42 | 43 | int getChannelId() const { 44 | return 1 + ((data >> 12) & 0x3); 45 | } 46 | 47 | uint16_t getMessageLength() const { 48 | // Sum up all marks 49 | uint16_t length = MESSAGE_BITS * IR_MARK_DURATION; 50 | 51 | // Sum up all pauses 52 | length += START_PAUSE_DURATION; 53 | for (unsigned long mask = 1UL << 15; mask; mask >>= 1) { 54 | if (data & mask) { 55 | length += HIGH_PAUSE_DURATION; 56 | } else { 57 | length += LOW_PAUSE_DURATION; 58 | } 59 | } 60 | length += STOP_PAUSE_DURATION; 61 | return length; 62 | } 63 | 64 | boolean next() { 65 | messageBitIdx++; 66 | if (messageBitIdx >= MESSAGE_BITS) { 67 | repeatCount++; 68 | messageBitIdx = 0; 69 | } 70 | if (repeatCount >= 1 && !repeatMessage) { 71 | return false; 72 | } else if (repeatCount >= 5) { 73 | return false; 74 | } else { 75 | return true; 76 | } 77 | } 78 | 79 | uint8_t getMarkDuration() const { 80 | return IR_MARK_DURATION; 81 | } 82 | 83 | uint32_t getPauseDuration() const { 84 | if (messageBitIdx == 0) 85 | return START_PAUSE_DURATION; 86 | else if (messageBitIdx < MESSAGE_BITS - 1) { 87 | return getDataBitPause(); 88 | } else { 89 | return getStopPause(); 90 | } 91 | } 92 | 93 | private: 94 | uint16_t getDataBitPause() const { 95 | const int pos = MESSAGE_BITS - 2 - messageBitIdx; 96 | const bool isHigh = data & (1 << pos); 97 | return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION; 98 | } 99 | 100 | uint32_t getStopPause() const { 101 | if (repeatMessage) { 102 | return getRepeatStopPause(); 103 | } else { 104 | return STOP_PAUSE_DURATION; 105 | } 106 | } 107 | 108 | uint32_t getRepeatStopPause() const { 109 | if (repeatCount == 0 || repeatCount == 1) { 110 | return STOP_PAUSE_DURATION + (uint32_t) 5 * MAX_MESSAGE_LENGTH - messageLength; 111 | } else if (repeatCount == 2 || repeatCount == 3) { 112 | return STOP_PAUSE_DURATION + (uint32_t) (6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength; 113 | } else { 114 | return STOP_PAUSE_DURATION; 115 | } 116 | } 117 | }; 118 | -------------------------------------------------------------------------------- /.github/workflows/LibraryBuild.yml: -------------------------------------------------------------------------------- 1 | # LibraryBuild.yml 2 | # Github workflow script to test compile all examples of an Arduino library repository. 3 | # 4 | # Copyright (C) 2020 Armin Joachimsmeyer 5 | # https://github.com/ArminJo/Github-Actions 6 | # 7 | # Before being able to push to my .github\workflows directories, 8 | # I had to create a new personal token with workflow enabled at https://github.com/settings/tokens 9 | 10 | # This is the name of the workflow, visible on GitHub UI. 11 | name: LibraryBuild 12 | on: 13 | push: # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request 14 | paths: 15 | - '**.ino' 16 | - '**.cpp' 17 | - '**.h' 18 | - '**LibraryBuild.yml' 19 | pull_request: 20 | paths: 21 | - '**.ino' 22 | - '**.cpp' 23 | - '**.h' 24 | - '**LibraryBuild.yml' 25 | 26 | jobs: 27 | build: 28 | name: ${{ matrix.arduino-boards-fqbn }} - test compiling examples 29 | 30 | runs-on: ubuntu-18.04 # I picked Ubuntu to use shell scripts. 31 | 32 | env: 33 | # Comma separated list without double quotes around the list. 34 | REQUIRED_LIBRARIES: 35 | 36 | strategy: 37 | matrix: 38 | # The matrix will produce one job for each configuration parameter of type `arduino-boards-fqbn` 39 | # In the Arduino IDE, the fqbn is printed in the first line of the verbose output for compilation as parameter -fqbn=... for the "arduino-builder -dump-prefs" command 40 | # 41 | # Examples: arduino:avr:uno, arduino:avr:leonardo, arduino:avr:nano, arduino:avr:mega 42 | # arduino:sam:arduino_due_x, arduino:samd:arduino_zero_native" 43 | # ATTinyCore:avr:attinyx5:chip=85,clock=1internal, digistump:avr:digispark-tiny, digistump:avr:digispark-pro 44 | # STM32:stm32:GenF1:pnum=BLUEPILL_F103C8 45 | # esp8266:esp8266:huzzah:eesz=4M3M,xtal=80, esp32:esp32:featheresp32:FlashFreq=80 46 | # You may add a suffix behind the fqbn with "|" to specify one board for e.g. different compile options like arduino:avr:uno|trace 47 | ############################################################################################################# 48 | arduino-boards-fqbn: 49 | - arduino:avr:uno 50 | - arduino:avr:leonardo 51 | - arduino:megaavr:nona4809:mode=off 52 | - arduino:samd:arduino_zero_native 53 | - esp32:esp32:featheresp32:FlashFreq=80 54 | - SparkFun:avr:promicro 55 | 56 | # Specify parameters for each board. 57 | # With examples-exclude you may exclude specific examples for a board. Use a comma separated list. 58 | ############################################################################################################# 59 | include: 60 | - arduino-boards-fqbn: esp32:esp32:featheresp32:FlashFreq=80 61 | platform-url: https://dl.espressif.com/dl/package_esp32_index.json 62 | examples-exclude: LGACSendDemo # undefined reference to `TwoWire::onReceive(void (*)(int))' 63 | 64 | - arduino-boards-fqbn: SparkFun:avr:promicro 65 | arduino-platform: arduino:avr,SparkFun:avr 66 | platform-url: https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json # Arduino URL is not required here 67 | 68 | 69 | # Do not cancel all jobs / architectures if one job fails 70 | fail-fast: false 71 | 72 | steps: 73 | - name: Checkout 74 | uses: actions/checkout@master 75 | 76 | # Use the arduino-test-compile script, because it is faster 77 | - name: Compile all examples using the bash script arduino-test-compile.sh 78 | env: 79 | # Passing parameters to the script by setting the appropriate ENV_* variables. 80 | ENV_ARDUINO_BOARD_FQBN: ${{ matrix.arduino-boards-fqbn }} 81 | ENV_ARDUINO_PLATFORM: ${{ matrix.arduino-platform }} 82 | ENV_PLATFORM_URL: ${{ matrix.platform-url }} 83 | ENV_REQUIRED_LIBRARIES: ${{ env.REQUIRED_LIBRARIES }} 84 | ENV_EXAMPLES_EXCLUDE: ${{ matrix.examples-exclude }} 85 | ENV_EXAMPLES_BUILD_PROPERTIES: ${{ toJson(matrix.examples-build-properties) }} 86 | # ENV_DEBUG_INSTALL: true 87 | 88 | run: | 89 | wget --quiet https://raw.githubusercontent.com/ArminJo/arduino-test-compile/master/arduino-test-compile.sh 90 | ls -l arduino-test-compile.sh 91 | chmod +x arduino-test-compile.sh 92 | ./arduino-test-compile.sh 93 | -------------------------------------------------------------------------------- /examples/BoseWaveSendDemo/BoseWaveSendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Based on IRremote: IRsendDemo by Ken Shirriff 3 | * 4 | * Prompt user for a code to send. Make sure your 940-950nm IR LED is 5 | * connected to the default digital output. Place your Bose Wave Radio 6 | * CD in the line of sight of your LED, and send commands! 7 | */ 8 | #include 9 | 10 | IRsend irsend; 11 | 12 | // On the Zero and others we switch explicitly to SerialUSB 13 | #if defined(ARDUINO_ARCH_SAMD) 14 | #define Serial SerialUSB 15 | #endif 16 | 17 | bool prompt; 18 | void menu(); 19 | 20 | void setup() { 21 | pinMode(LED_BUILTIN, OUTPUT); 22 | 23 | Serial.begin(115200); 24 | #if defined(__AVR_ATmega32U4__) 25 | while (!Serial) 26 | ; //delay for Leonardo, but this loops forever for Maple Serial 27 | #endif 28 | #if defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) 29 | delay(2000); // To be able to connect Serial monitor after reset and before first printout 30 | #endif 31 | // Just to know which program is running on my Arduino 32 | Serial.println(F("START " __FILE__ " from " __DATE__)); 33 | 34 | prompt = true; 35 | } 36 | 37 | void loop() { 38 | if (prompt) { 39 | menu(); 40 | } 41 | prompt = false; 42 | 43 | if (Serial.available()) { 44 | int answer = Serial.read(); 45 | if (answer == -1) { 46 | delay(300); 47 | } else if (answer == 48) { // 0 48 | irsend.sendBoseWave(0xFF); // On/Off 49 | prompt = true; 50 | } else if (answer == 49) { // 1 51 | irsend.sendBoseWave(0xFD); // Volume Up 52 | prompt = true; 53 | } else if (answer == 50) { // 2 54 | irsend.sendBoseWave(0xFC); // Volume Down 55 | prompt = true; 56 | } else if (answer == 51) { // 3 57 | irsend.sendBoseWave(0xF4); // Tune Up 58 | prompt = true; 59 | } else if (answer == 52) { // 4 60 | irsend.sendBoseWave(0xF3); // Tune Down 61 | prompt = true; 62 | } else if (answer == 53) { // 5 63 | irsend.sendBoseWave(0xF7); // AM 64 | prompt = true; 65 | } else if (answer == 54) { // 6 66 | irsend.sendBoseWave(0xF9); // FM 67 | prompt = true; 68 | } else if (answer == 55) { // 7 69 | irsend.sendBoseWave(0xF2); // Preset 1 70 | prompt = true; 71 | } else if (answer == 56) { // 8 72 | irsend.sendBoseWave(0xF1); // Preset 2 73 | prompt = true; 74 | } else if (answer == 57) { // 9 75 | irsend.sendBoseWave(0xF0); // Preset 3 76 | prompt = true; 77 | } else if (answer == 97) { // a 78 | irsend.sendBoseWave(0xEF); // Preset 4 79 | prompt = true; 80 | } else if (answer == 98) { // b 81 | irsend.sendBoseWave(0xEE); // Preset 5 82 | prompt = true; 83 | } else if (answer == 99) { // c 84 | irsend.sendBoseWave(0xFB); // Preset 6 85 | prompt = true; 86 | } else if (answer == 100) { // d 87 | irsend.sendBoseWave(0xFE); // Mute 88 | prompt = true; 89 | } else if (answer == 101) { // e 90 | irsend.sendBoseWave(0xF6); // Pause 91 | prompt = true; 92 | } else if (answer == 102) { // f 93 | irsend.sendBoseWave(0xF5); // Stop 94 | prompt = true; 95 | } else if (answer == 103) { // g 96 | irsend.sendBoseWave(0xF8); // Aux 97 | prompt = true; 98 | } else if (answer == 104) { // h 99 | irsend.sendBoseWave(0xFA); // Sleep 100 | prompt = true; 101 | } 102 | delay(300); 103 | } 104 | } 105 | 106 | void menu() { 107 | Serial.println("0: On / Off"); 108 | Serial.println("1: Volume Up"); 109 | Serial.println("2: Volume Down"); 110 | Serial.println("3: Tune Up"); 111 | Serial.println("4: Tune Down"); 112 | Serial.println("5: AM"); 113 | Serial.println("6: FM"); 114 | Serial.println("7: Preset 1"); 115 | Serial.println("8: Preset 2"); 116 | Serial.println("9: Preset 3"); 117 | Serial.println("a: Preset 4"); 118 | Serial.println("b: Preset 5"); 119 | Serial.println("c: Preset 6"); 120 | Serial.println("d: Mute"); 121 | Serial.println("e: Play/Pause"); 122 | Serial.println("f: Stop"); 123 | Serial.println("g: Aux"); 124 | Serial.println("h: Sleep"); 125 | } 126 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ## 2.6.1 2020/08 2 | - Adjusted JVC and LG timing. 3 | - Fixed 4809 bug. 4 | 5 | ## 2.6.0 2020/08 6 | - Added support for MagiQuest IR wands. 7 | - Corrected Samsung timing. 8 | - NEC repeat implementation. 9 | - Formatting and changing TIMER_CONFIG_KHZ and TIMER_CONFIG_NORMAL macros to static functions. 10 | - Added IRAM_ATTR for ESP32 ISR. 11 | - Removed #define HAS_AVR_INTERRUPT_H. 12 | - Changed Receiver States. Now starting with 0. 13 | - Changed switch to if / else if in IRRemote.cpp because of ESP32 compiler bug. 14 | - Changed DEBUG handling since compiler warns about empty "IF" or "ELSE" statements in IRRemote.cpp. 15 | 16 | ## 2.5.0 2020/06 17 | - corrected keywords.txt. 18 | - BoseWave protocol added PR #690. 19 | - Formatting comply to the new stylesheet. 20 | - Renamed "boarddefs.h" [ISSUE #375](https://github.com/z3t0/Arduino-IRremote/issues/375). 21 | - Renamed SEND_PIN to IR_SEND_PIN. 22 | - Renamed state macros. 23 | - Enabled DUTY_CYCLE for send signal. 24 | - Added sending for ESP32. 25 | - Changed rawlen from uint8_t to unsigned int allowing bigger receive buffer and renamed RAWBUF to RAW_BUFFER_LENGTH. 26 | - Introduced USE_NO_CARRIER for simulating an IR receiver. 27 | Changes from #283 by bengtmartensson 28 | - Added function sendRaw_P() for sending data from flash. 29 | Changes from #268 by adamlhumphreys 30 | - Optimized by reducing floating point operations as suggested by @madmalkav (#193) 31 | - Optimized with macros when using default MICROS_PER_TICK and TOLERANCE 32 | - Made decodeHash as a settable protocol defined by DECODE_HASH 33 | - Added Philips Extended RC-5 protocol support [PR #522] (https://github.com/z3t0/Arduino-IRremote/pull/522) 34 | 35 | ## 2.4.0 - 2017/08/10 36 | - Cleanup of hardware dependencies. Merge in SAM support [PR #437](https://github.com/z3t0/Arduino-IRremote/pull/437) 37 | 38 | ## 2.3.3 - 2017/03/31 39 | - Added ESP32 IR receive support [PR #427](https://github.com/z3t0/Arduino-IRremote/pull/425) 40 | 41 | ## 2.2.3 - 2017/03/27 42 | - Fix calculation of pause length in LEGO PF protocol [PR #427](https://github.com/z3t0/Arduino-IRremote/pull/427) 43 | 44 | ## 2.2.2 - 2017/01/20 45 | - Fixed naming bug [PR #398](https://github.com/z3t0/Arduino-IRremote/pull/398) 46 | 47 | ## 2.2.1 - 2016/07/27 48 | - Added tests for Lego Power Functions Protocol [PR #336](https://github.com/z3t0/Arduino-IRremote/pull/336) 49 | 50 | ## 2.2.0 - 2016/06/28 51 | - Added support for ATmega8535 52 | - Added support for ATmega16 53 | - Added support for ATmega32 54 | - Added support for ATmega164 55 | - Added support for ATmega324 56 | - Added support for ATmega644 57 | - Added support for ATmega1284 58 | - Added support for ATmega64 59 | - Added support for ATmega128 60 | 61 | [PR](https://github.com/z3t0/Arduino-IRremote/pull/324) 62 | 63 | ## 2.1.1 - 2016/05/04 64 | - Added Lego Power Functions Protocol [PR #309](https://github.com/z3t0/Arduino-IRremote/pull/309) 65 | 66 | ## 2.1.0 - 2016/02/20 67 | - Improved Debugging [PR #258](https://github.com/z3t0/Arduino-IRremote/pull/258) 68 | - Display TIME instead of TICKS [PR #258](https://github.com/z3t0/Arduino-IRremote/pull/258) 69 | 70 | ## 2.0.4 - 2016/02/20 71 | - Add Panasonic and JVC to IRrecord example [PR](https://github.com/z3t0/Arduino-IRremote/pull/54) 72 | 73 | ## 2.0.3 - 2016/02/20 74 | - Change IRSend Raw parameter to const [PR](https://github.com/z3t0/Arduino-IRremote/pull/227) 75 | 76 | ## 2.0.2 - 2015/12/02 77 | - Added IRremoteInfo Sketch - [PR](https://github.com/z3t0/Arduino-IRremote/pull/241) 78 | - Enforcing changelog.md 79 | 80 | ## 2.0.1 - 2015/07/26 - [Release](https://github.com/shirriff/Arduino-IRremote/releases/tag/BETA) 81 | ### Changes 82 | - Updated README 83 | - Updated Contributors 84 | - Fixed #110 Mess 85 | - Created Gitter Room 86 | - Added Gitter Badge 87 | - Standardised Code Base 88 | - Clean Debug Output 89 | - Optimized Send Loops 90 | - Modularized Design 91 | - Optimized and Updated Examples 92 | - Improved Documentation 93 | - Fixed and Improved many coding errors 94 | - Fixed Aiwa RC-T501 Decoding 95 | - Fixed Interrupt on ATmega8 96 | - Switched to Stable Release of @PlatformIO 97 | 98 | ### Additions 99 | - Added Aiwa RC-T501 Protocol 100 | - Added Denon Protocol 101 | - Added Pronto Support 102 | - Added Library Properties 103 | - Added Template For New Protocols 104 | - Added this changelog 105 | - Added Teensy LC Support 106 | - Added ATtiny84 Support 107 | - Added ATtiny85 Support 108 | - Added isIdle method 109 | 110 | ### Deletions 111 | - Removed (Fixed) #110 112 | - Broke Teensy 3 / 3.1 Support 113 | 114 | ### Not Working 115 | - Teensy 3 / 3.1 Support is in Development 116 | -------------------------------------------------------------------------------- /examples/LGACSendDemo/LGACSendDemo.md: -------------------------------------------------------------------------------- 1 | === decoding for LG A/C ==== 2 | - 1) remote of LG AC has two type of HDR mark/space, 8000/4000 and 3100/10000 3 | - 2) HDR 8000/4000 is decoded using decodeLG(IRrecvDumpV2) without problem 4 | - 3) for HDR 3100/10000, use AnalysIR's code : http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/ 5 | - 4) for bin output based on AnalysIR's code : https://gist.github.com/chaeplin/a3a4b4b6b887c663bfe8 6 | - 5) remove first two byte(11) 7 | - 6) sample rawcode with bin output : https://gist.github.com/chaeplin/134d232e0b8cfb898860 8 | 9 | 10 | === *** === 11 | - 1) Sample raw code : https://gist.github.com/chaeplin/ab2a7ad1533c41260f0d 12 | - 2) send raw code : https://gist.github.com/chaeplin/7c800d3166463bb51be4 13 | 14 | 15 | === *** === 16 | - (0) : Cooling or Heating 17 | - (1) : fixed 18 | - (2) : fixed 19 | - (3) : special(power, swing, air clean) 20 | - (4) : change air flow, temperature, cooling(0)/heating(4) 21 | - (5) : temperature ( 15 + (5) = ) 22 | - (6) : air flow 23 | - (7) : crc ( 3 + 4 + 5 + 6 ) & B00001111 24 | 25 | 26 | °F = °C × 1.8 + 32 27 | °C = (°F − 32) / 1.8 28 | 29 | 30 | === *** === 31 | * remote / Korea / without heating 32 | 33 | | status |(0)| (1)| (2)| (3)| (4)| (5)| (6)| (7) 34 | |----------------|---|----|----|----|----|----|----|---- 35 | | on / 25 / mid | C |1000|1000|0000|0000|1010|0010|1100 36 | | on / 26 / mid | C |1000|1000|0000|0000|1011|0010|1101 37 | | on / 27 / mid | C |1000|1000|0000|0000|1100|0010|1110 38 | | on / 28 / mid | C |1000|1000|0000|0000|1101|0010|1111 39 | | on / 25 / high | C |1000|1000|0000|0000|1010|0100|1110 40 | | on / 26 / high | C |1000|1000|0000|0000|1011|0100|1111 41 | | on / 27 / high | C |1000|1000|0000|0000|1100|0100|0000 42 | | on / 28 / high | C |1000|1000|0000|0000|1101|0100|0001 43 | |----------------|---|----|----|----|----|----|----|---- 44 | | 1 up | C |1000|1000|0000|1000|1101|0100|1001 45 | |----------------|---|----|----|----|----|----|----|---- 46 | | Cool power | C |1000|1000|0001|0000|0000|1100|1101 47 | | energy saving | C |1000|1000|0001|0000|0000|0100|0101 48 | | power | C |1000|1000|0001|0000|0000|1000|1001 49 | | flow/up/down | C |1000|1000|0001|0011|0001|0100|1001 50 | | up/down off | C |1000|1000|0001|0011|0001|0101|1010 51 | | flow/left/right| C |1000|1000|0001|0011|0001|0110|1011 52 | | left/right off | C |1000|1000|0001|0011|0001|0111|1100 53 | |----------------|---|----|----|----|----|----|----|---- 54 | | Air clean | C |1000|1000|1100|0000|0000|0000|1100 55 | |----------------|---|----|----|----|----|----|----|---- 56 | | off | C |1000|1000|1100|0000|0000|0101|0001 57 | 58 | 59 | 60 | * remote / with heating 61 | * converted using raw code at https://github.com/chaeplin/RaspAC/blob/master/lircd.conf 62 | 63 | | status |(0)| (1)| (2)| (3)| (4)| (5)| (6)| (7) 64 | |----------------|---|----|----|----|----|----|----|---- 65 | | on | C |1000|1000|0000|0000|1011|0010|1101 66 | |----------------|---|----|----|----|----|----|----|---- 67 | | off | C |1000|1000|1100|0000|0000|0101|0001 68 | |----------------|---|----|----|----|----|----|----|---- 69 | | 64 / 18 | C |1000|1000|0000|0000|0011|0100|0111 70 | | 66 / 19 | C |1000|1000|0000|0000|0100|0100|1000 71 | | 68 / 20 | C |1000|1000|0000|0000|0101|0100|1001 72 | | 70 / 21 | C |1000|1000|0000|0000|0110|0100|1010 73 | | 72 / 22 | C |1000|1000|0000|0000|0111|0100|1011 74 | | 74 / 23 | C |1000|1000|0000|0000|1000|0100|1100 75 | | 76 / 25 | C |1000|1000|0000|0000|1010|0100|1110 76 | | 78 / 26 | C |1000|1000|0000|0000|1011|0100|1111 77 | | 80 / 27 | C |1000|1000|0000|0000|1100|0100|0000 78 | | 82 / 28 | C |1000|1000|0000|0000|1101|0100|0001 79 | | 84 / 29 | C |1000|1000|0000|0000|1110|0100|0010 80 | | 86 / 30 | C |1000|1000|0000|0000|1111|0100|0011 81 | |----------------|---|----|----|----|----|----|----|---- 82 | | heat64 | H |1000|1000|0000|0100|0011|0100|1011 83 | | heat66 | H |1000|1000|0000|0100|0100|0100|1100 84 | | heat68 | H |1000|1000|0000|0100|0101|0100|1101 85 | | heat70 | H |1000|1000|0000|0100|0110|0100|1110 86 | | heat72 | H |1000|1000|0000|0100|0111|0100|1111 87 | | heat74 | H |1000|1000|0000|0100|1000|0100|0000 88 | | heat76 | H |1000|1000|0000|0100|1001|0100|0001 89 | | heat78 | H |1000|1000|0000|0100|1011|0100|0011 90 | | heat80 | H |1000|1000|0000|0100|1100|0100|0100 91 | | heat82 | H |1000|1000|0000|0100|1101|0100|0101 92 | | heat84 | H |1000|1000|0000|0100|1110|0100|0110 93 | | heat86 | H |1000|1000|0000|0100|1111|0100|0111 94 | -------------------------------------------------------------------------------- /src/ir_MagiQuest.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | // Based off the Magiquest fork of Arduino-IRremote by mpflaga 4 | // https://github.com/mpflaga/Arduino-IRremote/ 5 | 6 | //============================================================================== 7 | // 8 | // 9 | // M A G I Q U E S T 10 | // 11 | // 12 | //============================================================================== 13 | 14 | // MagiQuest packet is both Wand ID and magnitude of swish and flick 15 | union magiquest_t { 16 | unsigned long long llword; 17 | struct { 18 | unsigned int magnitude; 19 | unsigned long wand_id; 20 | char padding; 21 | char scrap; // just to pad the struct out to 64 bits so we can union with llword 22 | } cmd; 23 | }; 24 | 25 | #define MAGIQUEST_BITS 50 // The number of bits in the command itself 26 | #define MAGIQUEST_PERIOD 1150 // Length of time a full MQ "bit" consumes (1100 - 1200 usec) 27 | /* 28 | * 0 = 25% mark & 75% space across 1 period 29 | * 1150 * 0.25 = 288 usec mark 30 | * 1150 - 288 = 862 usec space 31 | * 1 = 50% mark & 50% space across 1 period 32 | * 1150 * 0.5 = 575 usec mark 33 | * 1150 - 575 = 575 usec space 34 | */ 35 | #define MAGIQUEST_ONE_MARK 575 36 | #define MAGIQUEST_ONE_SPACE 575 37 | #define MAGIQUEST_ZERO_MARK 288 38 | #define MAGIQUEST_ZERO_SPACE 862 39 | 40 | #define MAGIQUEST_MASK (1ULL << (MAGIQUEST_BITS-1)) 41 | 42 | //+============================================================================= 43 | // 44 | #if SEND_MAGIQUEST 45 | void IRsend::sendMagiQuest(unsigned long wand_id, unsigned int magnitude) { 46 | magiquest_t data; 47 | 48 | data.llword = 0; 49 | data.cmd.wand_id = wand_id; 50 | data.cmd.magnitude = magnitude; 51 | 52 | // Set IR carrier frequency 53 | enableIROut(38); 54 | 55 | // Data 56 | for (unsigned long long mask = MAGIQUEST_MASK; mask > 0; mask >>= 1) { 57 | if (data.llword & mask) { 58 | DBG_PRINT("1"); 59 | mark(MAGIQUEST_ONE_MARK); 60 | space(MAGIQUEST_ONE_SPACE); 61 | } else { 62 | DBG_PRINT("0"); 63 | mark(MAGIQUEST_ZERO_MARK); 64 | space(MAGIQUEST_ZERO_SPACE); 65 | } 66 | } 67 | DBG_PRINTLN(""); 68 | 69 | // Footer 70 | mark(MAGIQUEST_ZERO_MARK); 71 | space(0); // Always end with the LED off 72 | } 73 | #endif 74 | 75 | //+============================================================================= 76 | // 77 | #if DECODE_MAGIQUEST 78 | bool IRrecv::decodeMagiQuest(decode_results *results) { 79 | magiquest_t data; // Somewhere to build our code 80 | unsigned int offset = 1; // Skip the Gap reading 81 | 82 | unsigned int mark_; 83 | unsigned int space_; 84 | unsigned int ratio_; 85 | 86 | #if DEBUG 87 | char bitstring[MAGIQUEST_BITS*2]; 88 | memset(bitstring, 0, sizeof(bitstring)); 89 | #endif 90 | 91 | // Check we have enough data 92 | if (irparams.rawlen < 2 * MAGIQUEST_BITS) { 93 | DBG_PRINT("Not enough bits to be a MagiQuest packet ("); 94 | DBG_PRINT(irparams.rawlen); 95 | DBG_PRINT(" < "); 96 | DBG_PRINT(MAGIQUEST_BITS*2); 97 | DBG_PRINTLN(")"); 98 | return false; 99 | } 100 | 101 | // Read the bits in 102 | data.llword = 0; 103 | while (offset + 1 < irparams.rawlen) { 104 | mark_ = results->rawbuf[offset++]; 105 | space_ = results->rawbuf[offset++]; 106 | ratio_ = space_ / mark_; 107 | 108 | DBG_PRINT("mark="); 109 | DBG_PRINT(mark_ * MICROS_PER_TICK); 110 | DBG_PRINT(" space="); 111 | DBG_PRINT(space_ * MICROS_PER_TICK); 112 | DBG_PRINT(" ratio="); 113 | DBG_PRINTLN(ratio_); 114 | 115 | if (MATCH_MARK(space_ + mark_, MAGIQUEST_PERIOD)) { 116 | if (ratio_ > 1) { 117 | // It's a 0 118 | data.llword <<= 1; 119 | #if DEBUG 120 | bitstring[(offset/2)-1] = '0'; 121 | #endif 122 | } else { 123 | // It's a 1 124 | data.llword = (data.llword << 1) | 1; 125 | #if DEBUG 126 | bitstring[(offset/2)-1] = '1'; 127 | #endif 128 | } 129 | } else { 130 | DBG_PRINTLN("MATCH_MARK failed"); 131 | return false; 132 | } 133 | } 134 | #if DEBUG 135 | DBG_PRINTLN(bitstring); 136 | #endif 137 | 138 | // Success 139 | results->decode_type = MAGIQUEST; 140 | results->bits = offset / 2; 141 | results->value = data.cmd.wand_id; 142 | results->magnitude = data.cmd.magnitude; 143 | 144 | DBG_PRINT("MQ: bits="); 145 | DBG_PRINT(results->bits); 146 | DBG_PRINT(" value="); 147 | DBG_PRINT(results->value); 148 | DBG_PRINT(" magnitude="); 149 | DBG_PRINTLN(results->magnitude); 150 | 151 | return true; 152 | } 153 | #endif 154 | -------------------------------------------------------------------------------- /src/ir_Sharp_alt.cpp: -------------------------------------------------------------------------------- 1 | //-*- mode: C; c-basic-offset: 8; tab-width: 8; indent-tabs-mode: t; -*- 2 | #include "IRremote.h" 3 | 4 | //============================================================================== 5 | // SSSS H H AAA RRRR PPPP AAA L TTTTT 6 | // S H H A A R R P P A A L T 7 | // SSS HHHHH AAAAA RRRR PPPP AAAAA L T 8 | // S H H A A R R P A A L T 9 | // SSSS H H A A R R P A A LLLLL T 10 | //============================================================================== 11 | 12 | // This is an alternative protocol to that in ir_Sharp.cpp. It was tested with 13 | // the original Sharp GA538WJSA remote control. LIRC file with codes for this 14 | // remote control: http://lirc.sourceforge.net/remotes/sharp/GA538WJSA 15 | // 16 | // Author: Sergiy Kolesnikov 17 | // 18 | 19 | #define SHARP_ALT_RAWLEN 32 20 | #define SHARP_ALT_ADDRESS_BITS 5 21 | #define SHARP_ALT_COMMAND_BITS 8 22 | #define SHARP_ALT_BIT_MARK 150 23 | #define SHARP_ALT_SEND_BIT_MARK 300 24 | #define SHARP_ALT_ONE_SPACE 1750 25 | #define SHARP_ALT_ZERO_SPACE 700 26 | #define SHARP_ALT_RPT_SPACE 50000 27 | #define SHARP_ALT_SEND_RPT_SPACE 44000 28 | #define SHARP_ALT_TOGGLE_MASK 0x3FF 29 | #define SHARP_ALT_SEND_INVERT_MASK 0x7FE0 30 | 31 | //+============================================================================= 32 | #if SEND_SHARP_ALT 33 | void IRsend::sendSharpAltRaw(unsigned long data, int nbits) { 34 | enableIROut(38); 35 | 36 | for (int n = 0; n < 3; n++) { 37 | unsigned long mask = 1UL; 38 | for (int i = 0; i < nbits; i++) { 39 | if (data & mask) { 40 | mark(SHARP_ALT_SEND_BIT_MARK); 41 | space(SHARP_ALT_ONE_SPACE); 42 | } else { 43 | mark(SHARP_ALT_SEND_BIT_MARK); 44 | space(SHARP_ALT_ZERO_SPACE); 45 | } 46 | mask <<= 1; 47 | } 48 | mark(SHARP_ALT_BIT_MARK); 49 | space(SHARP_ALT_SEND_RPT_SPACE); 50 | data = data ^ SHARP_ALT_SEND_INVERT_MASK; 51 | } 52 | } 53 | 54 | void IRsend::sendSharpAlt(unsigned int address, unsigned long command) { 55 | unsigned long data = 1; // The expansion and the check bits (01). 56 | data = (data << SHARP_ALT_COMMAND_BITS) | command; 57 | data = (data << SHARP_ALT_ADDRESS_BITS) | address; 58 | 59 | // (+2) is for the expansion and the check bits. 60 | sendSharpAltRaw(data, SHARP_ALT_ADDRESS_BITS + SHARP_ALT_COMMAND_BITS + 2); 61 | } 62 | #endif 63 | 64 | //+============================================================================= 65 | #if DECODE_SHARP_ALT 66 | bool IRrecv::decodeSharpAlt(decode_results *results) { 67 | 68 | // Check we have enough data. 69 | if (irparams.rawlen < (SHARP_ALT_RAWLEN)) 70 | return false; 71 | 72 | // Check stop mark. 73 | if (!MATCH_MARK(results->rawbuf[SHARP_ALT_RAWLEN - 1], SHARP_ALT_BIT_MARK)) 74 | return false; 75 | 76 | // Check the "check bit." If this bit is not 0 than it is an inverted 77 | // frame, which we ignore. 78 | if (!MATCH_SPACE(results->rawbuf[SHARP_ALT_RAWLEN - 2], SHARP_ALT_ZERO_SPACE)) 79 | return false; 80 | 81 | // Check for repeat. 82 | static boolean is_first_repeat = true; 83 | long initial_space = ((long) results->rawbuf[0]) * MICROS_PER_TICK; 84 | if (initial_space <= SHARP_ALT_RPT_SPACE) { 85 | if (!is_first_repeat) { 86 | results->bits = 0; 87 | results->value = REPEAT; 88 | results->decode_type = SHARP; 89 | return true; 90 | } else { 91 | 92 | // Ignore the first repeat that always comes after the 93 | // inverted frame (even if the button was pressed only 94 | // once). 95 | is_first_repeat = false; 96 | return false; 97 | } 98 | } 99 | 100 | // Decode bits. SHARP_ALT_RAWLEN-6 because index starts with 0 (-1) and we 101 | // omit the timings for the stop mark (-1), the check bit (-2), and the 102 | // expansion bit (-2). 103 | uint16_t bits = 0; 104 | for (int i = SHARP_ALT_RAWLEN - 6; i > 1; i -= 2) { 105 | if (MATCH_SPACE(results->rawbuf[i], SHARP_ALT_ONE_SPACE)) { 106 | bits = (bits << 1) | 1; 107 | } else if (MATCH_SPACE(results->rawbuf[i], SHARP_ALT_ZERO_SPACE)) { 108 | bits = (bits << 1) | 0; 109 | } else { 110 | return false; 111 | } 112 | } 113 | 114 | results->bits = SHARP_ALT_ADDRESS_BITS + SHARP_ALT_COMMAND_BITS; 115 | results->address = (bits & (1 << (SHARP_ALT_ADDRESS_BITS))) - 1; 116 | results->value = bits >> SHARP_ALT_ADDRESS_BITS; // command 117 | results->decode_type = SHARP_ALT; 118 | is_first_repeat = true; 119 | return true; 120 | } 121 | #endif 122 | -------------------------------------------------------------------------------- /src/private/IRremoteInt.h: -------------------------------------------------------------------------------- 1 | //****************************************************************************** 2 | // IRremoteint.h 3 | // IRremote 4 | // Version 2.0.1 June, 2015 5 | // Copyright 2009 Ken Shirriff 6 | // For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html 7 | // 8 | // Modified by Paul Stoffregen to support other boards and timers 9 | // 10 | // Interrupt code based on NECIRrcv by Joe Knapp 11 | // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 12 | // Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ 13 | // 14 | // JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 15 | // Whynter A/C ARC-110WD added by Francesco Meschia 16 | //****************************************************************************** 17 | 18 | #ifndef IRremoteint_h 19 | #define IRremoteint_h 20 | 21 | //------------------------------------------------------------------------------ 22 | // Include the Arduino header 23 | // 24 | #include 25 | 26 | // All board specific stuff have been moved to its own file, included here. 27 | #include "IRremoteBoardDefs.h" 28 | 29 | //------------------------------------------------------------------------------ 30 | // Information for the Interrupt Service Routine 31 | // 32 | #if ! defined(RAW_BUFFER_LENGTH) 33 | #define RAW_BUFFER_LENGTH 101 ///< Maximum length of raw duration buffer. Must be odd. 34 | #endif 35 | 36 | /** 37 | * This struct is used to communicate with the ISR (interrupt service routine). 38 | */ 39 | typedef struct { 40 | // The fields are ordered to reduce memory over caused by struct-padding 41 | uint8_t rcvstate; ///< State Machine state 42 | uint8_t recvpin; ///< Pin connected to IR data from detector 43 | uint8_t blinkpin; 44 | uint8_t blinkflag; ///< true -> enable blinking of pin on IR processing 45 | unsigned int rawlen; ///< counter of entries in rawbuf 46 | unsigned int timer; ///< State timer, counts 50uS ticks. 47 | unsigned int rawbuf[RAW_BUFFER_LENGTH]; ///< raw data 48 | uint8_t overflow; ///< Raw buffer overflow occurred 49 | } irparams_t; 50 | 51 | // ISR State-Machine : Receiver States 52 | #define IR_REC_STATE_IDLE 0 53 | #define IR_REC_STATE_MARK 1 54 | #define IR_REC_STATE_SPACE 2 55 | #define IR_REC_STATE_STOP 3 56 | #define IR_REC_STATE_OVERFLOW 4 57 | 58 | /** 59 | * Allow all parts of the code access to the ISR data 60 | * NB. The data can be changed by the ISR at any time, even mid-function 61 | * Therefore we declare it as "volatile" to stop the compiler/CPU caching it 62 | */ 63 | #ifdef IR_GLOBAL 64 | volatile irparams_t irparams; 65 | #else 66 | extern volatile irparams_t irparams; 67 | #endif 68 | 69 | //------------------------------------------------------------------------------ 70 | // Defines for setting and clearing register bits 71 | // 72 | #ifndef cbi 73 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 74 | #endif 75 | 76 | #ifndef sbi 77 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 78 | #endif 79 | 80 | //------------------------------------------------------------------------------ 81 | // Pulse parms are ((X*50)-100) for the Mark and ((X*50)+100) for the Space. 82 | // First MARK is the one after the long gap 83 | // Pulse parameters in uSec 84 | // 85 | 86 | /** 87 | * When received, marks tend to be too long and 88 | * spaces tend to be too short. 89 | * To compensate for this, MARK_EXCESS_MICROS is subtracted from all marks, 90 | * and added to all spaces. 91 | */ 92 | #define MARK_EXCESS_MICROS 100 93 | 94 | /** Relative tolerance (in percent) for some comparisons on measured data. */ 95 | #define TOLERANCE 25 96 | 97 | /** Lower tolerance for comparison of measured data */ 98 | //#define LTOL (1.0 - (TOLERANCE/100.)) 99 | #define LTOL (100 - TOLERANCE) 100 | /** Upper tolerance for comparison of measured data */ 101 | //#define UTOL (1.0 + (TOLERANCE/100.)) 102 | #define UTOL (100 + TOLERANCE) 103 | 104 | /** Minimum gap between IR transmissions, in microseconds */ 105 | #define _GAP 5000 106 | 107 | /** Minimum gap between IR transmissions, in MICROS_PER_TICK */ 108 | #define GAP_TICKS (_GAP/MICROS_PER_TICK) 109 | 110 | //#define TICKS_LOW(us) ((int)(((us)*LTOL/MICROS_PER_TICK))) 111 | //#define TICKS_HIGH(us) ((int)(((us)*UTOL/MICROS_PER_TICK + 1))) 112 | #if MICROS_PER_TICK == 50 && TOLERANCE == 25 // Defaults 113 | #define TICKS_LOW(us) ((int) ((us)/67 )) // (us) / ((MICROS_PER_TICK:50 / LTOL:75 ) * 100) 114 | #define TICKS_HIGH(us) ((int) ((us)/40 + 1)) // (us) / ((MICROS_PER_TICK:50 / UTOL:125) * 100) + 1 115 | #else 116 | #define TICKS_LOW(us) ((int) ((long) (us) * LTOL / (MICROS_PER_TICK * 100) )) 117 | #define TICKS_HIGH(us) ((int) ((long) (us) * UTOL / (MICROS_PER_TICK * 100) + 1)) 118 | #endif 119 | 120 | //------------------------------------------------------------------------------ 121 | // IR detector output is active low 122 | // 123 | #define MARK 0 ///< Sensor output for a mark ("flash") 124 | #define SPACE 1 ///< Sensor output for a space ("gap") 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /examples/IRtest/IRtest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRtest unittest 3 | * Version 0.1 July, 2009 4 | * Copyright 2009 Ken Shirriff 5 | * http://arcfn.com 6 | * 7 | * Note: to run these tests, edit IRremote/IRremote.h to add "#define TEST" 8 | * You must then recompile the library by removing IRremote.o and restarting 9 | * the arduino IDE. 10 | */ 11 | 12 | #include 13 | 14 | // Dumps out the decode_results structure. 15 | // Call this after IRrecv::decode() 16 | // void * to work around compiler issue 17 | //void dump(void *v) { 18 | // decode_results *results = (decode_results *)v 19 | void dump(decode_results *results) { 20 | int count = results->rawlen; 21 | if (results->decode_type == UNKNOWN) { 22 | Serial.println("Could not decode message"); 23 | } 24 | else { 25 | if (results->decode_type == NEC) { 26 | Serial.print("Decoded NEC: "); 27 | } 28 | else if (results->decode_type == SONY) { 29 | Serial.print("Decoded SONY: "); 30 | } 31 | else if (results->decode_type == RC5) { 32 | Serial.print("Decoded RC5: "); 33 | } 34 | else if (results->decode_type == RC6) { 35 | Serial.print("Decoded RC6: "); 36 | } 37 | Serial.print(results->value, HEX); 38 | Serial.print(" ("); 39 | Serial.print(results->bits, DEC); 40 | Serial.println(" bits)"); 41 | } 42 | Serial.print("Raw ("); 43 | Serial.print(count, DEC); 44 | Serial.print("): "); 45 | 46 | for (int i = 0; i < count; i++) { 47 | if ((i % 2) == 1) { 48 | Serial.print(results->rawbuf[i]*MICROS_PER_TICK, DEC); 49 | } 50 | else { 51 | Serial.print(-(int)results->rawbuf[i]*MICROS_PER_TICK, DEC); 52 | } 53 | Serial.print(" "); 54 | } 55 | Serial.println(""); 56 | } 57 | 58 | IRrecv irrecv(0); 59 | decode_results results; 60 | 61 | class IRsendDummy : 62 | public IRsend 63 | { 64 | public: 65 | // For testing, just log the marks/spaces 66 | #define SENDLOG_LEN 128 67 | int sendlog[SENDLOG_LEN]; 68 | int sendlogcnt; 69 | IRsendDummy() : 70 | IRsend() { 71 | } 72 | void reset() { 73 | sendlogcnt = 0; 74 | } 75 | void mark(int time) { 76 | sendlog[sendlogcnt] = time; 77 | if (sendlogcnt < SENDLOG_LEN) sendlogcnt++; 78 | } 79 | void space(int time) { 80 | sendlog[sendlogcnt] = -time; 81 | if (sendlogcnt < SENDLOG_LEN) sendlogcnt++; 82 | } 83 | // Copies the dummy buf into the interrupt buf 84 | void useDummyBuf() { 85 | int last = SPACE; 86 | irparams.rcvstate = IR_REC_STATE_STOP; 87 | irparams.rawlen = 1; // Skip the gap 88 | for (int i = 0 ; i < sendlogcnt; i++) { 89 | if (sendlog[i] < 0) { 90 | if (last == MARK) { 91 | // New space 92 | irparams.rawbuf[irparams.rawlen++] = (-sendlog[i] - MARK_EXCESS_MICROS) / MICROS_PER_TICK; 93 | last = SPACE; 94 | } 95 | else { 96 | // More space 97 | irparams.rawbuf[irparams.rawlen - 1] += -sendlog[i] / MICROS_PER_TICK; 98 | } 99 | } 100 | else if (sendlog[i] > 0) { 101 | if (last == SPACE) { 102 | // New mark 103 | irparams.rawbuf[irparams.rawlen++] = (sendlog[i] + MARK_EXCESS_MICROS) / MICROS_PER_TICK; 104 | last = MARK; 105 | } 106 | else { 107 | // More mark 108 | irparams.rawbuf[irparams.rawlen - 1] += sendlog[i] / MICROS_PER_TICK; 109 | } 110 | } 111 | } 112 | if (irparams.rawlen % 2) { 113 | irparams.rawlen--; // Remove trailing space 114 | } 115 | } 116 | }; 117 | 118 | IRsendDummy irsenddummy; 119 | 120 | void verify(unsigned long val, int bits, int type) { 121 | irsenddummy.useDummyBuf(); 122 | irrecv.decode(&results); 123 | Serial.print("Testing "); 124 | Serial.print(val, HEX); 125 | if (results.value == val && results.bits == bits && results.decode_type == type) { 126 | Serial.println(": OK"); 127 | } 128 | else { 129 | Serial.println(": Error"); 130 | dump(&results); 131 | } 132 | } 133 | 134 | void testNEC(unsigned long val, int bits) { 135 | irsenddummy.reset(); 136 | irsenddummy.sendNEC(val, bits); 137 | verify(val, bits, NEC); 138 | } 139 | void testSony(unsigned long val, int bits) { 140 | irsenddummy.reset(); 141 | irsenddummy.sendSony(val, bits); 142 | verify(val, bits, SONY); 143 | } 144 | void testRC5(unsigned long val, int bits) { 145 | irsenddummy.reset(); 146 | irsenddummy.sendRC5(val, bits); 147 | verify(val, bits, RC5); 148 | } 149 | void testRC6(unsigned long val, int bits) { 150 | irsenddummy.reset(); 151 | irsenddummy.sendRC6(val, bits); 152 | verify(val, bits, RC6); 153 | } 154 | 155 | void test() { 156 | Serial.println("NEC tests"); 157 | testNEC(0x00000000, 32); 158 | testNEC(0xffffffff, 32); 159 | testNEC(0xaaaaaaaa, 32); 160 | testNEC(0x55555555, 32); 161 | testNEC(0x12345678, 32); 162 | Serial.println("Sony tests"); 163 | testSony(0xfff, 12); 164 | testSony(0x000, 12); 165 | testSony(0xaaa, 12); 166 | testSony(0x555, 12); 167 | testSony(0x123, 12); 168 | Serial.println("RC5 tests"); 169 | testRC5(0xfff, 12); 170 | testRC5(0x000, 12); 171 | testRC5(0xaaa, 12); 172 | testRC5(0x555, 12); 173 | testRC5(0x123, 12); 174 | Serial.println("RC6 tests"); 175 | testRC6(0xfffff, 20); 176 | testRC6(0x00000, 20); 177 | testRC6(0xaaaaa, 20); 178 | testRC6(0x55555, 20); 179 | testRC6(0x12345, 20); 180 | } 181 | 182 | void setup() 183 | { 184 | Serial.begin(115200); 185 | test(); 186 | } 187 | 188 | void loop() { 189 | } 190 | -------------------------------------------------------------------------------- /readmdFrench.md: -------------------------------------------------------------------------------- 1 | ## IRremote Library 2 | 3 | 4 | Cette bibliothèque vous permet d'envoyer et de recevoir des signaux infrarouges sur un Arduino. 5 | Des tutoriels et plus d'informations seront disponibles sur la page d'accueil officielle. 6 | 7 | ## Version - 2.2.3 8 | 9 | ## Installation 10 | 1. Allez à la [Releases](https://github.com/z3t0/Arduino-IRremote/releases) page. 11 | 2. Téléchargez la dernière version. 12 | 3. Extraire le fichier zip 13 | 4. Déplacez le dossier "IRremote" vers vos bibliothèques. 14 | 5. Assurez-vous de supprimer Arduino_Root / libraries / RobotIRremote. Où Arduino_Root fait référence au répertoire d'installation d'Arduino. La bibliothèque RobotIRremote a des définitions similaires à IRremote et provoque des erreurs. 15 | 16 | 17 | ## FAQ 18 | Je ne travaille pas correctement en utilisant Neopixels (aka WS2811 / WS2812 / WS2812B) 19 | Que vous utilisiez la librairie Adafruit Neopixel ou FastLED, les interruptions sont désactivées sur de nombreux processeurs bas de gamme comme les arduinos de base. À son tour, cela empêche le gestionnaire IR de s'exécuter quand il le faut. Il y a quelques solutions à ce processus, voir cette page de Marc MERLIN 20 | [cette page de Marc MERLIN](http://marc.merlins.org/perso/arduino/post_2017-04-03_Arduino-328P-Uno-Teensy3_1-ESP8266-ESP32-IR-and-Neopixels.html) 21 | 22 | 23 | ## Conseils pris en charge 24 | 25 | - Teensy 1.0 / 1.0++ / 2.0 / 2++ / 3.0 / 3.1 / Teensy-LC; Crédits: @PaulStoffregen (Teensy Team) 26 | - Sanguino 27 | - ATmega8, 48, 88, 168, 328 28 | - ATmega8535, 16, 32, 164, 324, 644, 1284, 29 | - ATmega64, 128 30 | - ATtiny 84 / 85 31 | - ESP32 (recevoir seulement) 32 | - ESP8266 est basé sur un ancien code qui n'est pas très récent, mais cela fonctionne raisonnablement bien. Voir https://github.com/markszabo/IRremoteESP8266 33 | Sparkfun Pro Micro 34 | 35 | 36 | 37 | 38 | Nous sommes ouverts aux suggestions d'ajout de support pour les nouveaux tableaux, cependant, nous vous recommandons fortement de contacter votre fournisseur et de fournir un soutien de leur côté. 39 | 40 | 41 | ## Spécifications matérielles 42 | 43 | 44 | | Carte/CPU | Envoyer Pin | Compteurs | 45 | |--------------------------------------------------------------------------|---------------------|-------------------| 46 | | [ATtiny84](https://github.com/SpenceKonde/ATTinyCore) | **6** | **1** | 47 | | [ATtiny85](https://github.com/SpenceKonde/ATTinyCore) | **1** | **TINY0** | 48 | | [ATmega8](https://github.com/MCUdude/MiniCore) | **9** | **1** | 49 | | Atmega32u4 | 5, 9, **13** | 1, 3, **4** | 50 | | [ATmega48, ATmega88, ATmega168, ATmega328](https://github.com/MCUdude/MiniCore) | **3**, 9 | 1, **2** | 51 | | [ATmega1284](https://github.com/MCUdude/MightyCore) | 13, 14, 6 | 1, **2**, 3 | 52 | | [ATmega164, ATmega324, ATmega644](https://github.com/MCUdude/MightyCore) | 13, **14** | 1, **2** | 53 | | [ATmega8535 ATmega16, ATmega32](https://github.com/MCUdude/MightyCore) | **13** | **1** | 54 | | [ATmega64, ATmega128](https://github.com/MCUdude/MegaCore) | **13** | **1** | 55 | | ATmega1280, ATmega2560 | 5, 6, **9**, 11, 46 | 1, **2**, 3, 4, 5 | 56 | | [ESP32](http://esp32.net/) | N/A (insupporté) | **1** | 57 | | [Sparkfun Pro Micro](https://www.sparkfun.com/products/12640) | 9, **5**, 5 | 1, **3**, 4_HS | 58 | | [Teensy 1.0](https://www.pjrc.com/teensy/) | **17** | **1** | 59 | | [Teensy 2.0](https://www.pjrc.com/teensy/) | 9, **10**, 14 | 1, 3, **4_HS** | 60 | | [Teensy++ 1.0 / 2.0](https://www.pjrc.com/teensy/) | **1**, 16, 25 | 1, **2**, 3 | 61 | | [Teensy 3.0 / 3.1](https://www.pjrc.com/teensy/) | **5** | **CMT** | 62 | | [Teensy-LC](https://www.pjrc.com/teensy/) | **16** | **TPM1** | 63 | 64 | 65 | ## Patchs expérimentaux 66 | 67 | Voici les correctifs strictement pris en charge qui n'ont pas encore été intégrés. Si vous avez des questions, n'hésitez pas à demander ici. Si cela fonctionne, faites le nous savoir! 68 | 69 | [Arduino 101](https://github.com/z3t0/Arduino-IRremote/pull/481#issuecomment-311243146) 70 | 71 | Le tableau ci-dessus répertorie les temporisations actuellement supportées et les broches d'envoi correspondantes, beaucoup de ces broches supplémentaires sont ouvertes. 72 | 73 | 74 | ## Utilisation 75 | - À faire TODO (Vérifier les exemples pour l'instant) 76 | 77 | 78 | ## Contribution 79 | Si vous voulez contribuer à ce projet: 80 | - Signaler les bogues et les erreurs 81 | - Demander des améliorations 82 | - Créer des problèmes et tirer des requêtes 83 | - Parlez de cette bibliothèque à d'autres personnes 84 | - Contribuer de nouveaux protocoles 85 | Vérifiez ici [ici](Contributing.md) pour quelques guidelines 86 | 87 | 88 | ## Contact 89 | Email: zetoslab@gmail.com 90 | Please only email me if it is more appropriate than creating an Issue / PR. I **will** not respond to requests for adding support for particular boards, unless of course you are the creator of the board and would like to cooperate on the project. I will also **ignore** any emails asking me to tell you how to implement your ideas. However, if you have a private inquiry that you would only apply to you and you would prefer it to be via email, by all means. 91 | 92 | ## Contributeurs 93 | Check [here](Contributors.md) 94 | @Lsuperman735 French translation 95 | 96 | ## Copyright 97 | Copyright 2009-2012 Ken Shirriff 98 | -------------------------------------------------------------------------------- /src/irPronto.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file irPronto.cpp 3 | * @brief In this file, the functions IRrecv::dumpPronto and 4 | * IRsend::sendPronto are defined. 5 | */ 6 | 7 | #include "IRremote.h" 8 | 9 | // DO NOT EXPORT from this file 10 | static const uint16_t MICROSECONDS_T_MAX = 0xFFFFU; 11 | static const uint16_t learnedToken = 0x0000U; 12 | static const uint16_t learnedNonModulatedToken = 0x0100U; 13 | static const unsigned int bitsInHexadecimal = 4U; 14 | static const unsigned int digitsInProntoNumber = 4U; 15 | static const unsigned int numbersInPreamble = 4U; 16 | static const unsigned int hexMask = 0xFU; 17 | static const uint32_t referenceFrequency = 4145146UL; 18 | static const uint16_t fallbackFrequency = 64767U; // To use with frequency = 0; 19 | static const uint32_t microsecondsInSeconds = 1000000UL; 20 | static const unsigned int RESULT_JUNK_COUNT = 1U; 21 | 22 | static unsigned int toFrequencyKHz(uint16_t code) { 23 | return ((referenceFrequency / code) + 500) / 1000; 24 | } 25 | 26 | void IRsend::sendPronto(const uint16_t *data, unsigned int size, unsigned int times) { 27 | unsigned int timebase = (microsecondsInSeconds * data[1] + referenceFrequency / 2) / referenceFrequency; 28 | unsigned int khz; 29 | switch (data[0]) { 30 | case learnedToken: // normal, "learned" 31 | khz = toFrequencyKHz(data[1]); 32 | break; 33 | case learnedNonModulatedToken: // non-demodulated, "learned" 34 | khz = 0U; 35 | break; 36 | default: 37 | return; // There are other types, but they are not handled yet. 38 | } 39 | unsigned int intros = 2*data[2]; 40 | unsigned int repeats = 2*data[3]; 41 | if (numbersInPreamble + intros + repeats != size) // inconsistent sizes 42 | return; 43 | 44 | unsigned int durations[intros + repeats]; 45 | for (unsigned int i = 0; i < intros + repeats; i++) { 46 | uint32_t duration = ((uint32_t) data[i + numbersInPreamble]) * timebase; 47 | durations[i] = (unsigned int) ((duration <= MICROSECONDS_T_MAX) ? duration : MICROSECONDS_T_MAX); 48 | } 49 | 50 | unsigned int numberRepeats = intros > 0 ? times - 1 : times; 51 | if (intros > 0) { 52 | sendRaw(durations, intros - 1, khz); 53 | } 54 | 55 | if (numberRepeats == 0) 56 | return; 57 | 58 | delay(durations[intros - 1] / 1000U); 59 | for (unsigned int i = 0; i < numberRepeats; i++) { 60 | sendRaw(durations + intros, repeats - 1, khz); 61 | if (i < numberRepeats - 1) { // skip last wait 62 | delay(durations[intros + repeats - 1] / 1000U); 63 | } 64 | } 65 | } 66 | 67 | 68 | void IRsend::sendPronto(const char *str, unsigned int times) { 69 | size_t len = strlen(str)/(digitsInProntoNumber + 1) + 1; 70 | uint16_t data[len]; 71 | const char *p = str; 72 | char *endptr[1]; 73 | for (unsigned int i = 0; i < len; i++) { 74 | long x = strtol(p, endptr, 16); 75 | if (x == 0 && i >= numbersInPreamble) { 76 | // Alignment error?, bail immediately (often right result). 77 | len = i; 78 | break; 79 | } 80 | data[i] = static_cast(x); // If input is conforming, there can be no overflow! 81 | p = *endptr; 82 | } 83 | sendPronto(data, len, times); 84 | } 85 | 86 | #if HAS_FLASH_READ 87 | void IRsend::sendPronto_PF(uint_farptr_t str, unsigned int times) { 88 | size_t len = strlen_PF(STRCPY_PF_CAST(str)); 89 | char work[len + 1]; 90 | strncpy_PF(work, STRCPY_PF_CAST(str), len); 91 | sendPronto(work, times); 92 | } 93 | 94 | void IRsend::sendPronto_PF(const char *str, unsigned int times) { 95 | sendPronto_PF(reinterpret_cast(str), times); // to avoid infinite recursion 96 | }; 97 | 98 | void IRsend::sendPronto(const __FlashStringHelper *str, unsigned int times) { 99 | return sendPronto_PF(reinterpret_cast(str), times); 100 | } 101 | #endif 102 | 103 | static uint16_t effectiveFrequency(uint16_t frequency) { 104 | return frequency > 0 ? frequency : fallbackFrequency; 105 | } 106 | 107 | static uint16_t toTimebase(uint16_t frequency) { 108 | return microsecondsInSeconds / effectiveFrequency(frequency); 109 | } 110 | 111 | static uint16_t toFrequencyCode(uint16_t frequency) { 112 | return referenceFrequency / effectiveFrequency(frequency); 113 | } 114 | 115 | static char hexDigit(unsigned int x) { 116 | return (char) (x <= 9 ? ('0' + x) : ('A' + (x - 10))); 117 | } 118 | 119 | static void dumpDigit(Stream& stream, unsigned int number) { 120 | stream.print(hexDigit(number)); 121 | } 122 | 123 | static void dumpNumber(Stream& stream, uint16_t number) { 124 | for (unsigned int i = 0; i < digitsInProntoNumber; i++) { 125 | unsigned int shifts = bitsInHexadecimal * (digitsInProntoNumber - 1 - i); 126 | dumpDigit(stream, (number >> shifts) & hexMask); 127 | } 128 | stream.print(' '); 129 | } 130 | 131 | static void dumpDuration(Stream& stream, uint16_t duration, uint16_t timebase) { 132 | dumpNumber(stream, (duration * MICROS_PER_TICK + timebase / 2) / timebase); 133 | } 134 | 135 | static void dumpSequence(Stream& stream, const volatile unsigned int *data, size_t length, uint16_t timebase) { 136 | for (unsigned int i = 0; i < length; i++) 137 | dumpDuration(stream, data[i], timebase); 138 | 139 | dumpDuration(stream, _GAP, timebase); 140 | } 141 | 142 | void IRrecv::dumpPronto(Stream& stream, decode_results *results, unsigned int frequency) { 143 | dumpNumber(stream, frequency > 0 ? learnedToken : learnedNonModulatedToken); 144 | dumpNumber(stream, toFrequencyCode(frequency)); 145 | dumpNumber(stream, (results->rawlen + 1) / 2); 146 | dumpNumber(stream, 0); 147 | unsigned int timebase = toTimebase(frequency); 148 | dumpSequence(stream, results->rawbuf + RESULT_JUNK_COUNT, results->rawlen - RESULT_JUNK_COUNT, timebase); 149 | } 150 | -------------------------------------------------------------------------------- /src/irSend.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | #ifdef SENDING_SUPPORTED 4 | //+============================================================================= 5 | void IRsend::sendRaw(const unsigned int buf[], unsigned int len, unsigned int hz) { 6 | // Set IR carrier frequency 7 | enableIROut(hz); 8 | 9 | for (unsigned int i = 0; i < len; i++) { 10 | if (i & 1) { 11 | space(buf[i]); 12 | } else { 13 | mark(buf[i]); 14 | } 15 | } 16 | 17 | space(0); // Always end with the LED off 18 | } 19 | 20 | void IRsend::sendRaw_P(const unsigned int buf[], unsigned int len, unsigned int hz) { 21 | #if !defined(__AVR__) 22 | sendRaw(buf,len,hz); // Let the function work for non AVR platforms 23 | #else 24 | // Set IR carrier frequency 25 | enableIROut(hz); 26 | 27 | for (unsigned int i = 0; i < len; i++) { 28 | uint16_t duration = pgm_read_word_near(buf + sizeof(uint16_t) * i); 29 | if (i & 1) { 30 | space(duration); 31 | } else { 32 | mark(duration); 33 | } 34 | } 35 | space(0); // Always end with the LED off 36 | #endif 37 | 38 | } 39 | 40 | #ifdef USE_SOFT_CARRIER 41 | void inline IRsend::sleepMicros(unsigned long us) { 42 | #ifdef USE_SPIN_WAIT 43 | sleepUntilMicros(micros() + us); 44 | #else 45 | if (us > 0U) { // Is this necessary? (Official docu https://www.arduino.cc/en/Reference/DelayMicroseconds does not tell.) 46 | delayMicroseconds((unsigned int) us); 47 | } 48 | #endif 49 | } 50 | 51 | void inline IRsend::sleepUntilMicros(unsigned long targetTime) { 52 | #ifdef USE_SPIN_WAIT 53 | while (micros() < targetTime) 54 | ; 55 | #else 56 | unsigned long now = micros(); 57 | if (now < targetTime) { 58 | sleepMicros(targetTime - now); 59 | } 60 | #endif 61 | } 62 | #endif // USE_SOFT_CARRIER 63 | 64 | //+============================================================================= 65 | // Sends an IR mark for the specified number of microseconds. 66 | // The mark output is modulated at the PWM frequency. 67 | // 68 | 69 | void IRsend::mark(unsigned int time) { 70 | #ifdef USE_SOFT_CARRIER 71 | unsigned long start = micros(); 72 | unsigned long stop = start + time; 73 | if (stop + periodTime < start) { 74 | // Counter wrap-around, happens very seldomly, but CAN happen. 75 | // Just give up instead of possibly damaging the hardware. 76 | return; 77 | } 78 | unsigned long nextPeriodEnding = start; 79 | unsigned long now = micros(); 80 | while (now < stop) { 81 | SENDPIN_ON(sendPin); 82 | sleepMicros (periodOnTime); 83 | SENDPIN_OFF(sendPin); 84 | nextPeriodEnding += periodTime; 85 | sleepUntilMicros(nextPeriodEnding); 86 | now = micros(); 87 | } 88 | #elif defined(USE_NO_CARRIER) 89 | digitalWrite(sendPin, LOW); // Set output to active low. 90 | #else 91 | TIMER_ENABLE_PWM; // Enable pin 3 PWM output 92 | #endif 93 | // ! This is a bug, no need to delay here 94 | // if (time > 0) { 95 | // custom_delay_usec(time); 96 | // } 97 | } 98 | 99 | //+============================================================================= 100 | // Leave pin off for time (given in microseconds) 101 | // Sends an IR space for the specified number of microseconds. 102 | // A space is no output, so the PWM output is disabled. 103 | // 104 | void IRsend::space(unsigned int time) { 105 | #if defined(USE_NO_CARRIER) 106 | digitalWrite(sendPin, HIGH); // Set output to inactive high. 107 | #else 108 | TIMER_DISABLE_PWM; // Disable pin 3 PWM output 109 | #endif 110 | if (time > 0) { 111 | IRsend::custom_delay_usec(time); 112 | } 113 | } 114 | 115 | #ifdef USE_DEFAULT_ENABLE_IR_OUT 116 | //+============================================================================= 117 | // Enables IR output. The khz value controls the modulation frequency in kilohertz. 118 | // The IR output will be on pin 3 (OC2B). 119 | // This routine is designed for 36-40KHz; if you use it for other values, it's up to you 120 | // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.) 121 | // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B 122 | // controlling the duty cycle. 123 | // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A) 124 | // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin. 125 | // A few hours staring at the ATmega documentation and this will all make sense. 126 | // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details. 127 | // 128 | void IRsend::enableIROut(int khz) { 129 | #ifdef USE_SOFT_CARRIER 130 | periodTime = (1000U + khz / 2) / khz; // = 1000/khz + 1/2 = round(1000.0/khz) 131 | periodOnTime = periodTime * DUTY_CYCLE / 100U - PULSE_CORRECTION; 132 | #endif 133 | 134 | #if defined(USE_NO_CARRIER) 135 | pinMode(sendPin, OUTPUT); 136 | digitalWrite(sendPin, HIGH); // Set output to inactive high. 137 | #else 138 | // Disable the Timer2 Interrupt (which is used for receiving IR) 139 | TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt 140 | 141 | pinMode(sendPin, OUTPUT); 142 | 143 | SENDPIN_OFF(sendPin); // When not sending, we want it low 144 | 145 | timerConfigkHz(khz); 146 | #endif 147 | } 148 | #endif 149 | 150 | //+============================================================================= 151 | // Custom delay function that circumvents Arduino's delayMicroseconds limit 152 | 153 | void IRsend::custom_delay_usec(unsigned long uSecs) { 154 | if (uSecs > 4) { 155 | unsigned long start = micros(); 156 | unsigned long endMicros = start + uSecs - 4; 157 | if (endMicros < start) { // Check if overflow 158 | while (micros() > start) { 159 | } // wait until overflow 160 | } 161 | while (micros() < endMicros) { 162 | } // normal wait 163 | } 164 | //else { 165 | // __asm__("nop\n\t"); // must have or compiler optimizes out 166 | //} 167 | } 168 | 169 | #endif // SENDING_SUPPORTED 170 | -------------------------------------------------------------------------------- /examples/LGACSendDemo/LGACSendDemo.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | IRsend irsend; 6 | // not used 7 | int RECV_PIN = 11; 8 | IRrecv irrecv (RECV_PIN); 9 | 10 | const int AC_TYPE = 0; 11 | // 0 : TOWER 12 | // 1 : WALL 13 | // 14 | 15 | int AC_HEAT = 0; 16 | // 0 : cooling 17 | // 1 : heating 18 | 19 | int AC_POWER_ON = 0; 20 | // 0 : off 21 | // 1 : on 22 | 23 | int AC_AIR_ACLEAN = 0; 24 | // 0 : off 25 | // 1 : on --> power on 26 | 27 | int AC_TEMPERATURE = 27; 28 | // temperature : 18 ~ 30 29 | 30 | int AC_FLOW = 1; 31 | // 0 : low 32 | // 1 : mid 33 | // 2 : high 34 | // if AC_TYPE =1, 3 : change 35 | // 36 | 37 | 38 | const int AC_FLOW_TOWER[3] = {0, 4, 6}; 39 | const int AC_FLOW_WALL[4] = {0, 2, 4, 5}; 40 | 41 | unsigned long AC_CODE_TO_SEND; 42 | 43 | int r = LOW; 44 | int o_r = LOW; 45 | 46 | byte a, b; 47 | 48 | void ac_send_code(unsigned long code) 49 | { 50 | Serial.print("code to send : "); 51 | Serial.print(code, BIN); 52 | Serial.print(" : "); 53 | Serial.println(code, HEX); 54 | 55 | irsend.sendLG(code, 28); 56 | } 57 | 58 | void ac_activate(int temperature, int air_flow) 59 | { 60 | 61 | int AC_MSBITS1 = 8; 62 | int AC_MSBITS2 = 8; 63 | int AC_MSBITS3 = 0; 64 | int AC_MSBITS4 ; 65 | if ( AC_HEAT == 1 ) { 66 | // heating 67 | AC_MSBITS4 = 4; 68 | } else { 69 | // cooling 70 | AC_MSBITS4 = 0; 71 | } 72 | int AC_MSBITS5 = temperature - 15; 73 | int AC_MSBITS6 ; 74 | 75 | if ( AC_TYPE == 0) { 76 | AC_MSBITS6 = AC_FLOW_TOWER[air_flow]; 77 | } else { 78 | AC_MSBITS6 = AC_FLOW_WALL[air_flow]; 79 | } 80 | 81 | int AC_MSBITS7 = (AC_MSBITS3 + AC_MSBITS4 + AC_MSBITS5 + AC_MSBITS6) & B00001111; 82 | 83 | AC_CODE_TO_SEND = AC_MSBITS1 << 4 ; 84 | AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS2) << 4; 85 | AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS3) << 4; 86 | AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS4) << 4; 87 | AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS5) << 4; 88 | AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS6) << 4; 89 | AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS7); 90 | 91 | ac_send_code(AC_CODE_TO_SEND); 92 | 93 | AC_POWER_ON = 1; 94 | AC_TEMPERATURE = temperature; 95 | AC_FLOW = air_flow; 96 | } 97 | 98 | void ac_change_air_swing(int air_swing) 99 | { 100 | if ( AC_TYPE == 0) { 101 | if ( air_swing == 1) { 102 | AC_CODE_TO_SEND = 0x881316B; 103 | } else { 104 | AC_CODE_TO_SEND = 0x881317C; 105 | } 106 | } else { 107 | if ( air_swing == 1) { 108 | AC_CODE_TO_SEND = 0x8813149; 109 | } else { 110 | AC_CODE_TO_SEND = 0x881315A; 111 | } 112 | } 113 | 114 | ac_send_code(AC_CODE_TO_SEND); 115 | } 116 | 117 | void ac_power_down() 118 | { 119 | AC_CODE_TO_SEND = 0x88C0051; 120 | 121 | ac_send_code(AC_CODE_TO_SEND); 122 | 123 | AC_POWER_ON = 0; 124 | } 125 | 126 | void ac_air_clean(int air_clean) 127 | { 128 | if ( air_clean == 1) { 129 | AC_CODE_TO_SEND = 0x88C000C; 130 | } else { 131 | AC_CODE_TO_SEND = 0x88C0084; 132 | } 133 | 134 | ac_send_code(AC_CODE_TO_SEND); 135 | 136 | AC_AIR_ACLEAN = air_clean; 137 | } 138 | 139 | void setup() 140 | { 141 | Serial.begin(115200); 142 | delay(1000); 143 | Wire.begin(7); 144 | Wire.onReceive(receiveEvent); 145 | 146 | Serial.println(" - - - T E S T - - - "); 147 | 148 | /* test 149 | ac_activate(25, 1); 150 | delay(5000); 151 | ac_activate(27, 2); 152 | delay(5000); 153 | 154 | */ 155 | } 156 | 157 | void loop() 158 | { 159 | 160 | 161 | ac_activate(25, 1); 162 | delay(5000); 163 | ac_activate(27, 0); 164 | delay(5000); 165 | 166 | 167 | if ( r != o_r) { 168 | 169 | /* 170 | # a : mode or temp b : air_flow, temp, swing, clean, cooling/heating 171 | # 18 ~ 30 : temp 0 ~ 2 : flow // on 172 | # 0 : off 0 173 | # 1 : on 0 174 | # 2 : air_swing 0 or 1 175 | # 3 : air_clean 0 or 1 176 | # 4 : air_flow 0 ~ 2 : flow 177 | # 5 : temp 18 ~ 30 178 | # + : temp + 1 179 | # - : temp - 1 180 | # m : change cooling to air clean, air clean to cooling 181 | */ 182 | Serial.print("a : "); 183 | Serial.print(a); 184 | Serial.print(" b : "); 185 | Serial.println(b); 186 | 187 | switch (a) { 188 | case 0: // off 189 | ac_power_down(); 190 | break; 191 | case 1: // on 192 | ac_activate(AC_TEMPERATURE, AC_FLOW); 193 | break; 194 | case 2: 195 | if ( b == 0 || b == 1 ) { 196 | ac_change_air_swing(b); 197 | } 198 | break; 199 | case 3: // 1 : clean on, power on 200 | if ( b == 0 || b == 1 ) { 201 | ac_air_clean(b); 202 | } 203 | break; 204 | case 4: 205 | if ( 0 <= b && b <= 2 ) { 206 | ac_activate(AC_TEMPERATURE, b); 207 | } 208 | break; 209 | case 5: 210 | if (18 <= b && b <= 30 ) { 211 | ac_activate(b, AC_FLOW); 212 | } 213 | break; 214 | case '+': 215 | if ( 18 <= AC_TEMPERATURE && AC_TEMPERATURE <= 29 ) { 216 | ac_activate((AC_TEMPERATURE + 1), AC_FLOW); 217 | } 218 | break; 219 | case '-': 220 | if ( 19 <= AC_TEMPERATURE && AC_TEMPERATURE <= 30 ) { 221 | ac_activate((AC_TEMPERATURE - 1), AC_FLOW); 222 | } 223 | break; 224 | case 'm': 225 | /* 226 | if ac is on, 1) turn off, 2) turn on ac_air_clean(1) 227 | if ac is off, 1) turn on, 2) turn off ac_air_clean(0) 228 | */ 229 | if ( AC_POWER_ON == 1 ) { 230 | ac_power_down(); 231 | delay(100); 232 | ac_air_clean(1); 233 | } else { 234 | if ( AC_AIR_ACLEAN == 1) { 235 | ac_air_clean(0); 236 | delay(100); 237 | } 238 | ac_activate(AC_TEMPERATURE, AC_FLOW); 239 | } 240 | break; 241 | default: 242 | if ( 18 <= a && a <= 30 ) { 243 | if ( 0 <= b && b <= 2 ) { 244 | ac_activate(a, b); 245 | } 246 | } 247 | } 248 | 249 | o_r = r ; 250 | } 251 | delay(100); 252 | } 253 | 254 | 255 | 256 | void receiveEvent(int howMany) 257 | { 258 | a = Wire.read(); 259 | b = Wire.read(); 260 | r = !r ; 261 | } 262 | 263 | 264 | -------------------------------------------------------------------------------- /src/ir_Template.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Assuming the protocol we are adding is for the (imaginary) manufacturer: Shuzu 3 | 4 | Our fantasy protocol is a standard protocol, so we can use this standard 5 | template without too much work. Some protocols are quite unique and will require 6 | considerably more work in this file! It is way beyond the scope of this text to 7 | explain how to reverse engineer "unusual" IR protocols. But, unless you own an 8 | oscilloscope, the starting point is probably to use the rawDump.ino sketch and 9 | try to spot the pattern! 10 | 11 | Before you start, make sure the IR library is working OK: 12 | # Open up the Arduino IDE 13 | # Load up the rawDump.ino example sketch 14 | # Run it 15 | 16 | Now we can start to add our new protocol... 17 | 18 | 1. Copy this file to : ir_Shuzu.cpp 19 | 20 | 2. Replace all occurrences of "Shuzu" with the name of your protocol. 21 | 22 | 3. Tweak the #defines to suit your protocol. 23 | 24 | 4. If you're lucky, tweaking the #defines will make the default send() function 25 | work. 26 | 27 | 5. Again, if you're lucky, tweaking the #defines will have made the default 28 | decode() function work. 29 | 30 | You have written the code to support your new protocol! 31 | 32 | Now you must do a few things to add it to the IRremote system: 33 | 34 | 1. Open IRremote.h and make the following changes: 35 | REMEMEBER to change occurences of "SHUZU" with the name of your protocol 36 | 37 | A. At the top, in the section "Supported Protocols", add: 38 | #define DECODE_SHUZU 1 39 | #define SEND_SHUZU 1 40 | 41 | B. In the section "enumerated list of all supported formats", add: 42 | SHUZU, 43 | to the end of the list (notice there is a comma after the protocol name) 44 | 45 | C. Further down in "Main class for receiving IR", add: 46 | //...................................................................... 47 | #if DECODE_SHUZU 48 | bool decodeShuzu (decode_results *results) ; 49 | #endif 50 | 51 | D. Further down in "Main class for sending IR", add: 52 | //...................................................................... 53 | #if SEND_SHUZU 54 | void sendShuzu (unsigned long data, int nbits) ; 55 | #endif 56 | 57 | E. Save your changes and close the file 58 | 59 | 2. Now open irRecv.cpp and make the following change: 60 | 61 | A. In the function IRrecv::decode(), add: 62 | #ifdef DECODE_NEC 63 | DBG_PRINTLN("Attempting Shuzu decode"); 64 | if (decodeShuzu(results)) return true ; 65 | #endif 66 | 67 | B. Save your changes and close the file 68 | 69 | You will probably want to add your new protocol to the example sketch 70 | 71 | 3. Open MyDocuments\Arduino\libraries\IRremote\examples\IRrecvDumpV2.ino 72 | 73 | A. In the encoding() function, add: 74 | case SHUZU: Serial.print("SHUZU"); break ; 75 | 76 | Now open the Arduino IDE, load up the rawDump.ino sketch, and run it. 77 | Hopefully it will compile and upload. 78 | If it doesn't, you've done something wrong. Check your work. 79 | If you can't get it to work - seek help from somewhere. 80 | 81 | If you get this far, I will assume you have successfully added your new protocol 82 | There is one last thing to do. 83 | 84 | 1. Delete this giant instructional comment. 85 | 86 | 2. Send a copy of your work to us so we can include it in the library and 87 | others may benefit from your hard work and maybe even write a song about how 88 | great you are for helping them! :) 89 | 90 | Regards, 91 | BlueChip 92 | */ 93 | 94 | #include "IRremote.h" 95 | 96 | //============================================================================== 97 | // 98 | // 99 | // S H U Z U 100 | // 101 | // 102 | //============================================================================== 103 | 104 | #define SHUZU_BITS 32 // The number of bits in the command 105 | 106 | #define SHUZU_HDR_MARK 1000 // The length of the Header:Mark 107 | #define SHUZU_HDR_SPACE 2000 // The lenght of the Header:Space 108 | 109 | #define SHUZU_BIT_MARK 3000 // The length of a Bit:Mark 110 | #define SHUZU_ONE_SPACE 4000 // The length of a Bit:Space for 1's 111 | #define SHUZU_ZERO_SPACE 5000 // The length of a Bit:Space for 0's 112 | 113 | #define SHUZU_OTHER 1234 // Other things you may need to define 114 | 115 | //+============================================================================= 116 | // 117 | #if SEND_SHUZU 118 | void IRsend::sendShuzu(unsigned long data, int nbits) { 119 | // Set IR carrier frequency 120 | enableIROut(38); 121 | 122 | // Header 123 | mark(SHUZU_HDR_MARK); 124 | space(SHUZU_HDR_SPACE); 125 | 126 | // Data 127 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 128 | if (data & mask) { 129 | mark(SHUZU_BIT_MARK); 130 | space(SHUZU_ONE_SPACE); 131 | } else { 132 | mark(SHUZU_BIT_MARK); 133 | space(SHUZU_ZERO_SPACE); 134 | } 135 | } 136 | 137 | // Footer 138 | mark(SHUZU_BIT_MARK); 139 | space(0); // Always end with the LED off 140 | } 141 | #endif 142 | 143 | //+============================================================================= 144 | // 145 | #if DECODE_SHUZU 146 | bool IRrecv::decodeShuzu(decode_results *results) { 147 | unsigned long data = 0; // Somewhere to build our code 148 | int offset = 1; // Skip the Gap reading 149 | 150 | // Check we have the right amount of data 151 | if (irparams.rawlen != 1 + 2 + (2 * SHUZU_BITS) + 1) { 152 | return false; 153 | } 154 | 155 | // Check initial Mark+Space match 156 | if (!MATCH_MARK(results->rawbuf[offset], SHUZU_HDR_MARK)) { 157 | return false; 158 | } 159 | offset++; 160 | 161 | if (!MATCH_SPACE(results->rawbuf[offset], SHUZU_HDR_SPACE)) { 162 | return false; 163 | } 164 | offset++; 165 | 166 | // Read the bits in 167 | for (int i = 0; i < SHUZU_BITS; i++) { 168 | // Each bit looks like: MARK + SPACE_1 -> 1 169 | // or : MARK + SPACE_0 -> 0 170 | if (!MATCH_MARK(results->rawbuf[offset], SHUZU_BIT_MARK)) { 171 | return false; 172 | } 173 | offset++; 174 | 175 | // IR data is big-endian, so we shuffle it in from the right: 176 | if (MATCH_SPACE(results->rawbuf[offset], SHUZU_ONE_SPACE)) { 177 | data = (data << 1) | 1; 178 | } else if (MATCH_SPACE(results->rawbuf[offset], SHUZU_ZERO_SPACE)) { 179 | data = (data << 1) | 0; 180 | } else { 181 | return false; 182 | } 183 | offset++; 184 | } 185 | 186 | // Success 187 | results->bits = SHUZU_BITS; 188 | results->value = data; 189 | results->decode_type = SHUZU; 190 | return true; 191 | } 192 | #endif 193 | -------------------------------------------------------------------------------- /examples/IRrecord/IRrecord.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRrecord: record and play back IR signals as a minimal 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * An IR LED must be connected to the output PWM pin 3. 5 | * A button must be connected between the input SEND_BUTTON_PIN and ground. 6 | * A visible LED can be connected to STATUS_PIN to provide status. 7 | * 8 | * The logic is: 9 | * If the button is pressed, send the IR code. 10 | * If an IR code is received, record it. 11 | * 12 | * Version 0.11 September, 2009 13 | * Copyright 2009 Ken Shirriff 14 | * http://arcfn.com 15 | */ 16 | 17 | #include 18 | 19 | #if defined(ESP32) 20 | int IR_RECEIVE_PIN = 15; 21 | int SEND_BUTTON_PIN = 16; // RX2 pin 22 | #else 23 | int IR_RECEIVE_PIN = 11; 24 | int SEND_BUTTON_PIN = 12; 25 | #endif 26 | int STATUS_PIN = LED_BUILTIN; 27 | 28 | IRrecv irrecv(IR_RECEIVE_PIN); 29 | IRsend irsend; 30 | decode_results results; 31 | 32 | // On the Zero and others we switch explicitly to SerialUSB 33 | #if defined(ARDUINO_ARCH_SAMD) 34 | #define Serial SerialUSB 35 | #endif 36 | 37 | void setup() { 38 | Serial.begin(115200); 39 | #if defined(__AVR_ATmega32U4__) 40 | while (!Serial); //delay for Leonardo, but this loops forever for Maple Serial 41 | #endif 42 | // Just to know which program is running on my Arduino 43 | Serial.println(F("START " __FILE__ " from " __DATE__)); 44 | 45 | irrecv.enableIRIn(); // Start the receiver 46 | pinMode(SEND_BUTTON_PIN, INPUT_PULLUP); 47 | pinMode(STATUS_PIN, OUTPUT); 48 | 49 | Serial.print(F("Ready to receive IR signals at pin ")); 50 | Serial.println(IR_RECEIVE_PIN); 51 | Serial.print(F("Ready to send IR signals at pin ")); 52 | Serial.println(IR_SEND_PIN); 53 | } 54 | 55 | // Storage for the recorded code 56 | int codeType = -1; // The type of code 57 | unsigned long codeValue; // The code value if not raw 58 | unsigned int rawCodes[RAW_BUFFER_LENGTH]; // The durations if raw 59 | int codeLen; // The length of the code 60 | int toggle = 0; // The RC5/6 toggle state 61 | 62 | // Stores the code for later playback 63 | // Most of this code is just logging 64 | void storeCode(decode_results *results) { 65 | codeType = results->decode_type; 66 | // int count = results->rawlen; 67 | if (codeType == UNKNOWN) { 68 | Serial.println("Received unknown code, saving as raw"); 69 | codeLen = results->rawlen - 1; 70 | // To store raw codes: 71 | // Drop first value (gap) 72 | // Convert from ticks to microseconds 73 | // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion 74 | for (int i = 1; i <= codeLen; i++) { 75 | if (i % 2) { 76 | // Mark 77 | rawCodes[i - 1] = results->rawbuf[i] * MICROS_PER_TICK - MARK_EXCESS_MICROS; 78 | Serial.print(" m"); 79 | } else { 80 | // Space 81 | rawCodes[i - 1] = results->rawbuf[i] * MICROS_PER_TICK + MARK_EXCESS_MICROS; 82 | Serial.print(" s"); 83 | } 84 | Serial.print(rawCodes[i - 1], DEC); 85 | } 86 | Serial.println(""); 87 | } else { 88 | if (codeType == NEC) { 89 | Serial.print("Received NEC: "); 90 | if (results->value == REPEAT) { 91 | // Don't record a NEC repeat value as that's useless. 92 | Serial.println("repeat; ignoring."); 93 | return; 94 | } 95 | } else if (codeType == SONY) { 96 | Serial.print("Received SONY: "); 97 | } else if (codeType == SAMSUNG) { 98 | Serial.print("Received SAMSUNG: "); 99 | } else if (codeType == PANASONIC) { 100 | Serial.print("Received PANASONIC: "); 101 | } else if (codeType == JVC) { 102 | Serial.print("Received JVC: "); 103 | } else if (codeType == RC5) { 104 | Serial.print("Received RC5: "); 105 | } else if (codeType == RC6) { 106 | Serial.print("Received RC6: "); 107 | } else { 108 | Serial.print("Unexpected codeType "); 109 | Serial.print(codeType, DEC); 110 | Serial.println(""); 111 | } 112 | Serial.println(results->value, HEX); 113 | codeValue = results->value; 114 | codeLen = results->bits; 115 | } 116 | } 117 | 118 | void sendCode(int repeat) { 119 | if (codeType == NEC) { 120 | if (repeat) { 121 | irsend.sendNEC(REPEAT, codeLen); 122 | Serial.println("Sent NEC repeat"); 123 | } else { 124 | irsend.sendNEC(codeValue, codeLen); 125 | Serial.print("Sent NEC "); 126 | Serial.println(codeValue, HEX); 127 | } 128 | } else if (codeType == SONY) { 129 | irsend.sendSony(codeValue, codeLen); 130 | Serial.print("Sent Sony "); 131 | Serial.println(codeValue, HEX); 132 | } else if (codeType == PANASONIC) { 133 | irsend.sendPanasonic(codeValue, codeLen); 134 | Serial.print("Sent Panasonic"); 135 | Serial.println(codeValue, HEX); 136 | } else if (codeType == JVC) { 137 | irsend.sendJVC(codeValue, codeLen, false); 138 | Serial.print("Sent JVC"); 139 | Serial.println(codeValue, HEX); 140 | } else if (codeType == RC5 || codeType == RC6) { 141 | if (!repeat) { 142 | // Flip the toggle bit for a new button press 143 | toggle = 1 - toggle; 144 | } 145 | // Put the toggle bit into the code to send 146 | codeValue = codeValue & ~(1 << (codeLen - 1)); 147 | codeValue = codeValue | (toggle << (codeLen - 1)); 148 | if (codeType == RC5) { 149 | Serial.print("Sent RC5 "); 150 | Serial.println(codeValue, HEX); 151 | irsend.sendRC5(codeValue, codeLen); 152 | } else { 153 | irsend.sendRC6(codeValue, codeLen); 154 | Serial.print("Sent RC6 "); 155 | Serial.println(codeValue, HEX); 156 | } 157 | } else if (codeType == UNKNOWN /* i.e. raw */) { 158 | // Assume 38 KHz 159 | irsend.sendRaw(rawCodes, codeLen, 38); 160 | Serial.println("Sent raw"); 161 | } 162 | } 163 | 164 | int lastButtonState; 165 | 166 | void loop() { 167 | // If button pressed, send the code. 168 | int buttonState = digitalRead(SEND_BUTTON_PIN); // Button pin is active LOW 169 | if (lastButtonState == LOW && buttonState == HIGH) { 170 | Serial.println("Released"); 171 | irrecv.enableIRIn(); // Re-enable receiver 172 | } 173 | 174 | if (buttonState == LOW) { 175 | Serial.println("Pressed, sending"); 176 | digitalWrite(STATUS_PIN, HIGH); 177 | sendCode(lastButtonState == buttonState); 178 | digitalWrite(STATUS_PIN, LOW); 179 | delay(50); // Wait a bit between retransmissions 180 | } else if (irrecv.decode(&results)) { 181 | digitalWrite(STATUS_PIN, HIGH); 182 | storeCode(&results); 183 | irrecv.resume(); // resume receiver 184 | digitalWrite(STATUS_PIN, LOW); 185 | } 186 | lastButtonState = buttonState; 187 | } 188 | -------------------------------------------------------------------------------- /src/ir_Sharp.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // SSSS H H AAA RRRR PPPP 5 | // S H H A A R R P P 6 | // SSS HHHHH AAAAA RRRR PPPP 7 | // S H H A A R R P 8 | // SSSS H H A A R R P 9 | //============================================================================== 10 | 11 | // Sharp and DISH support by Todd Treece: http://unionbridge.org/design/ircommand 12 | // 13 | // The send function has the necessary repeat built in because of the need to 14 | // invert the signal. 15 | // 16 | // Sharp protocol documentation: 17 | // http://www.sbprojects.com/knowledge/ir/sharp.htm 18 | // 19 | // Here is the LIRC file I found that seems to match the remote codes from the 20 | // oscilloscope: 21 | // Sharp LCD TV: 22 | // http://lirc.sourceforge.net/remotes/sharp/GA538WJSA 23 | 24 | #define SHARP_BITS 15 25 | #define SHARP_ONE_SPACE 1805 26 | //#define SHARP_ONE_SPACE 1850 27 | 28 | #define SHARP_ADDR_BITS 5 29 | #define SHARP_DATA_BITS 8 30 | #define SHARP_BIT_MARK_SEND 250 31 | #define SHARP_BIT_MARK_RECV 150 32 | 33 | #define SHARP_ZERO_SPACE 795 34 | #define SHARP_GAP 600000 35 | #define SHARP_RPT_SPACE 3000 36 | 37 | #define SHARP_TOGGLE_MASK 0x3FF 38 | 39 | //+============================================================================= 40 | #if SEND_SHARP 41 | void IRsend::sendSharpRaw(unsigned long data, int nbits) { 42 | enableIROut(38); 43 | 44 | // Sending codes in bursts of 3 (normal, inverted, normal) makes transmission 45 | // much more reliable. That's the exact behavior of CD-S6470 remote control. 46 | for (int n = 0; n < 3; n++) { 47 | for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { 48 | if (data & mask) { 49 | mark (SHARP_BIT_MARK_SEND); 50 | space(SHARP_ONE_SPACE); 51 | } else { 52 | mark (SHARP_BIT_MARK_SEND); 53 | space(SHARP_ZERO_SPACE); 54 | } 55 | } 56 | 57 | mark (SHARP_BIT_MARK_SEND); 58 | space(SHARP_ZERO_SPACE); 59 | delay(40); 60 | 61 | data = data ^ SHARP_TOGGLE_MASK; 62 | } 63 | } 64 | #endif 65 | 66 | //+============================================================================= 67 | // Sharp send compatible with data obtained through decodeSharp() 68 | // ^^^^^^^^^^^^^ FUNCTION MISSING! 69 | // 70 | #if SEND_SHARP 71 | void IRsend::sendSharp(unsigned int address, unsigned int command) { 72 | sendSharpRaw((address << 10) | (command << 2) | 2, SHARP_BITS); 73 | /* 74 | * Use this code instead of the line above to be code compatible to the decoded values from decodeSharp 75 | */ 76 | // //Change address to big-endian (five bits swap place) 77 | // address = (address & 0x10) >> 4 | (address & 0x01) << 4 | (address & 0x08) >> 2 | (address & 0x02) << 2 | (address & 0x04) ; 78 | // //Change command to big-endian (eight bit swap place) 79 | // command = (command & 0xF0) >> 4 | (command & 0x0F) << 4; 80 | // command = (command & 0xCC) >> 2 | (command & 0x33) << 2; 81 | // command = (command & 0xAA) >> 1 | (command & 0x55) << 1; 82 | // sendSharpRaw((address << 10) | (command << 2) | 0, SHARP_BITS); 83 | } 84 | 85 | #endif // SEND_SHARP 86 | 87 | //+============================================================================= 88 | // Sharp decode function written based on Sharp protocol documentation: 89 | // http://www.sbprojects.com/knowledge/ir/sharp.htm 90 | // Tesded on a DENON AVR-1804 reciever 91 | 92 | #if DECODE_SHARP 93 | bool IRrecv::decodeSharp(decode_results *results) { 94 | unsigned long addr = 0; // Somewhere to build our address 95 | unsigned long data = 0; // Somewhere to build our data 96 | unsigned long lastData = 0; // Somewhere to store last data 97 | int offset = 1; //skip long space 98 | int loops = 1; //number of bursts 99 | 100 | // Check we have the right amount of data 101 | // Either one burst or three where second is inverted 102 | // The setting #define _GAP 5000 in IRremoteInt.h will give one burst and possibly three calls to this function 103 | if (irparams.rawlen == (SHARP_BITS + 1) * 2) 104 | loops = 1; 105 | else if (irparams.rawlen == (SHARP_BITS + 1) * 2 * 3) 106 | loops = 3; 107 | else 108 | return false; 109 | 110 | // Check the first mark to see if it fits the SHARP_BIT_MARK_RECV length 111 | if (!MATCH_MARK(results->rawbuf[offset], SHARP_BIT_MARK_RECV)) 112 | return false; 113 | //check the first pause and see if it fits the SHARP_ONE_SPACE or SHARP_ZERO_SPACE length 114 | if (!(MATCH_SPACE(results->rawbuf[offset + 1], SHARP_ONE_SPACE) || MATCH_SPACE(results->rawbuf[offset + 1], SHARP_ZERO_SPACE))) 115 | return false; 116 | 117 | // Read the bits in 118 | for (int j = 0; j < loops; j++) { 119 | data = 0; 120 | addr = 0; 121 | for (int i = 0; i < SHARP_ADDR_BITS; i++) { 122 | // Each bit looks like: SHARP_BIT_MARK_RECV + SHARP_ONE_SPACE -> 1 123 | // or : SHARP_BIT_MARK_RECV + SHARP_ZERO_SPACE -> 0 124 | if (!MATCH_MARK(results->rawbuf[offset++], SHARP_BIT_MARK_RECV)) 125 | return false; 126 | // IR data is big-endian, so we shuffle it in from the right: 127 | if (MATCH_SPACE(results->rawbuf[offset], SHARP_ONE_SPACE)) 128 | addr += 1 << i; 129 | else if (MATCH_SPACE(results->rawbuf[offset], SHARP_ZERO_SPACE)) 130 | addr = addr; 131 | else 132 | return false; 133 | offset++; 134 | } 135 | for (int i = 0; i < SHARP_DATA_BITS; i++) { 136 | // Each bit looks like: SHARP_BIT_MARK_RECV + SHARP_ONE_SPACE -> 1 137 | // or : SHARP_BIT_MARK_RECV + SHARP_ZERO_SPACE -> 0 138 | if (!MATCH_MARK(results->rawbuf[offset++], SHARP_BIT_MARK_RECV)) 139 | return false; 140 | // IR data is big-endian, so we shuffle it in from the right: 141 | if (MATCH_SPACE(results->rawbuf[offset], SHARP_ONE_SPACE)) 142 | data += 1 << i; 143 | else if (MATCH_SPACE(results->rawbuf[offset], SHARP_ZERO_SPACE)) 144 | data = data; 145 | else 146 | return false; 147 | offset++; 148 | //Serial.print(i); 149 | //Serial.print(":"); 150 | //Serial.println(data, HEX); 151 | } 152 | //skip exp bit (mark+pause), chk bit (mark+pause), mark and long pause before next burst 153 | offset += 6; 154 | 155 | //Check if last burst data is equal to this burst (lastData already inverted) 156 | if (lastData != 0 && data != lastData) 157 | return false; 158 | //save current burst of data but invert (XOR) the last 10 bits (8 data bits + exp bit + chk bit) 159 | lastData = data ^ 0xFF; 160 | } 161 | 162 | // Success 163 | results->bits = SHARP_BITS; 164 | results->value = data; 165 | results->address = addr; 166 | results->decode_type = SHARP; 167 | return true; 168 | } 169 | #endif 170 | -------------------------------------------------------------------------------- /examples/IRrecvDumpV2/IRrecvDumpV2.ino: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // Include the IRremote library header 3 | // 4 | #include 5 | 6 | //------------------------------------------------------------------------------ 7 | // Tell IRremote which Arduino pin is connected to the IR Receiver (TSOP4838) 8 | // 9 | #if defined(ESP32) 10 | int IR_RECEIVE_PIN = 15; 11 | #else 12 | int IR_RECEIVE_PIN = 11; 13 | #endif 14 | IRrecv irrecv(IR_RECEIVE_PIN); 15 | 16 | //+============================================================================= 17 | // Configure the Arduino 18 | // 19 | void setup() { 20 | pinMode(LED_BUILTIN, OUTPUT); 21 | 22 | Serial.begin(115200); // Status message will be sent to PC at 9600 baud 23 | #if defined(__AVR_ATmega32U4__) 24 | while (!Serial); //delay for Leonardo, but this loops forever for Maple Serial 25 | #endif 26 | // Just to know which program is running on my Arduino 27 | Serial.println(F("START " __FILE__ " from " __DATE__)); 28 | 29 | irrecv.enableIRIn(); // Start the receiver 30 | 31 | Serial.print(F("Ready to receive IR signals at pin ")); 32 | Serial.println(IR_RECEIVE_PIN); 33 | } 34 | 35 | //+============================================================================= 36 | // Display IR code 37 | // 38 | void ircode(decode_results *results) { 39 | // Panasonic has an Address 40 | if (results->decode_type == PANASONIC) { 41 | Serial.print(results->address, HEX); 42 | Serial.print(":"); 43 | } 44 | 45 | // Print Code 46 | Serial.print(results->value, HEX); 47 | } 48 | 49 | //+============================================================================= 50 | // Display encoding type 51 | // 52 | void encoding(decode_results *results) { 53 | switch (results->decode_type) { 54 | default: 55 | case UNKNOWN: 56 | Serial.print("UNKNOWN"); 57 | break; 58 | case NEC: 59 | Serial.print("NEC"); 60 | break; 61 | case SONY: 62 | Serial.print("SONY"); 63 | break; 64 | case RC5: 65 | Serial.print("RC5"); 66 | break; 67 | case RC6: 68 | Serial.print("RC6"); 69 | break; 70 | case DISH: 71 | Serial.print("DISH"); 72 | break; 73 | case SHARP: 74 | Serial.print("SHARP"); 75 | break; 76 | case SHARP_ALT: 77 | Serial.print("SHARP_ALT"); 78 | break; 79 | case JVC: 80 | Serial.print("JVC"); 81 | break; 82 | case SANYO: 83 | Serial.print("SANYO"); 84 | break; 85 | case MITSUBISHI: 86 | Serial.print("MITSUBISHI"); 87 | break; 88 | case SAMSUNG: 89 | Serial.print("SAMSUNG"); 90 | break; 91 | case LG: 92 | Serial.print("LG"); 93 | break; 94 | case WHYNTER: 95 | Serial.print("WHYNTER"); 96 | break; 97 | case AIWA_RC_T501: 98 | Serial.print("AIWA_RC_T501"); 99 | break; 100 | case PANASONIC: 101 | Serial.print("PANASONIC"); 102 | break; 103 | case DENON: 104 | Serial.print("Denon"); 105 | break; 106 | case BOSEWAVE: 107 | Serial.print("BOSEWAVE"); 108 | break; 109 | } 110 | } 111 | 112 | //+============================================================================= 113 | // Dump out the decode_results structure. 114 | // 115 | void dumpInfo(decode_results *results) { 116 | // Check if the buffer overflowed 117 | if (results->overflow) { 118 | Serial.println("IR code too long. Edit IRremoteInt.h and increase RAW_BUFFER_LENGTH"); 119 | return; 120 | } 121 | 122 | // Show Encoding standard 123 | Serial.print("Encoding : "); 124 | encoding(results); 125 | Serial.println(""); 126 | 127 | // Show Code & length 128 | Serial.print("Code : 0x"); 129 | ircode(results); 130 | Serial.print(" ("); 131 | Serial.print(results->bits, DEC); 132 | Serial.println(" bits)"); 133 | } 134 | 135 | //+============================================================================= 136 | // Dump out the decode_results structure. 137 | // 138 | void dumpRaw(decode_results *results) { 139 | // Print Raw data 140 | Serial.print("Timing["); 141 | Serial.print(results->rawlen - 1, DEC); 142 | Serial.println("]: "); 143 | 144 | for (unsigned int i = 1; i < results->rawlen; i++) { 145 | unsigned long x = results->rawbuf[i] * MICROS_PER_TICK; 146 | if (!(i & 1)) { // even 147 | Serial.print("-"); 148 | if (x < 1000) 149 | Serial.print(" "); 150 | if (x < 100) 151 | Serial.print(" "); 152 | Serial.print(x, DEC); 153 | } else { // odd 154 | Serial.print(" "); 155 | Serial.print("+"); 156 | if (x < 1000) 157 | Serial.print(" "); 158 | if (x < 100) 159 | Serial.print(" "); 160 | Serial.print(x, DEC); 161 | if (i < results->rawlen - 1) 162 | Serial.print(", "); //',' not needed for last one 163 | } 164 | if (!(i % 8)) 165 | Serial.println(""); 166 | } 167 | Serial.println(""); // Newline 168 | } 169 | 170 | //+============================================================================= 171 | // Dump out the decode_results structure. 172 | // 173 | void dumpCode(decode_results *results) { 174 | // Start declaration 175 | Serial.print("unsigned int "); // variable type 176 | Serial.print("rawData["); // array name 177 | Serial.print(results->rawlen - 1, DEC); // array size 178 | Serial.print("] = {"); // Start declaration 179 | 180 | // Dump data 181 | for (unsigned int i = 1; i < results->rawlen; i++) { 182 | Serial.print(results->rawbuf[i] * MICROS_PER_TICK, DEC); 183 | if (i < results->rawlen - 1) 184 | Serial.print(","); // ',' not needed on last one 185 | if (!(i & 1)) 186 | Serial.print(" "); 187 | } 188 | 189 | // End declaration 190 | Serial.print("};"); // 191 | 192 | // Comment 193 | Serial.print(" // "); 194 | encoding(results); 195 | Serial.print(" "); 196 | ircode(results); 197 | 198 | // Newline 199 | Serial.println(""); 200 | 201 | // Now dump "known" codes 202 | if (results->decode_type != UNKNOWN) { 203 | 204 | // Some protocols have an address 205 | if (results->decode_type == PANASONIC) { 206 | Serial.print("unsigned int addr = 0x"); 207 | Serial.print(results->address, HEX); 208 | Serial.println(";"); 209 | } 210 | 211 | // All protocols have data 212 | Serial.print("unsigned int data = 0x"); 213 | Serial.print(results->value, HEX); 214 | Serial.println(";"); 215 | } 216 | } 217 | 218 | //+============================================================================= 219 | // Dump out the raw data as Pronto Hex. 220 | // 221 | void dumpPronto(decode_results *results) { 222 | Serial.print("Pronto Hex: "); 223 | irrecv.dumpPronto(Serial, results); 224 | Serial.println(); 225 | } 226 | 227 | //+============================================================================= 228 | // The repeating section of the code 229 | // 230 | void loop() { 231 | decode_results results; // Somewhere to store the results 232 | 233 | if (irrecv.decode(&results)) { // Grab an IR code 234 | dumpInfo(&results); // Output the results 235 | dumpRaw(&results); // Output the results in RAW format 236 | dumpPronto(&results); 237 | dumpCode(&results); // Output the results as source code 238 | Serial.println(""); // Blank line between entries 239 | irrecv.resume(); // Prepare for the next value 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/ir_BoseWave.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //============================================================================== 4 | // BBBB OOO SSSS EEEEE 5 | // B B O O S E 6 | // BB B O O SSS EEEE 7 | // B B O O S E 8 | // BBBB OOO SSSS EEEEE 9 | //============================================================================== 10 | // 11 | // Bose Wave Radio CD Remote Control 12 | // |-------------------------------------| 13 | // | On/Off Sleep VolUp | 14 | // | Play/Pause Stop VolDown | 15 | // | FM AM Aux | 16 | // | Tune Down Tune Up Mute | 17 | // | 1 2 3 | 18 | // | 4 5 6 | 19 | // |-------------------------------------| 20 | // 21 | // Support for Bose Wave Radio CD provided by https://github.com/uvotguy. 22 | // 23 | // This protocol was reverse engineered by capturing IR signals from a working 24 | // remote. Multiple signals were captured on my oscilloscope, and the timing 25 | // values were averaged. 26 | // 27 | // IR codes are 8 bits. Transmission starts with a header: a mark and a space. 28 | // The header is followed by an 8-bit command, where a bit is a mark and a short 29 | // space (1) or a long space (0). The command is followed by the complement of 30 | // the command (8 bits). A transmission ends with a short mark. 31 | // 32 | // As seen on my trusty oscilloscope, there is no repeat code. Instead, when I 33 | // press and hold a button on my remote, it sends a command, makes a 51.2ms space, 34 | // and resends the command, etc, etc. 35 | // 36 | // It may be worth noting that these values do NOT match those in the LIRC 37 | // remote database (http://lirc.sourceforge.net/remotes/bose/). 38 | 39 | #define CMD_ON_OFF 0xff 40 | #define CMD_MUTE 0xfe 41 | #define CMD_VOL_UP 0xfd 42 | #define CMD_VOL_DOWN 0xfc 43 | #define CMD_PRESET_6 0xfb 44 | #define CMD_SLEEP 0xfa 45 | #define CMD_FM 0xf9 46 | #define CMD_AUX 0xf8 47 | #define CMD_AM 0xf7 48 | #define CMD_PLAY_PAUSE 0xf6 49 | #define CMD_STOP 0xf5 50 | #define CMD_TUNE_UP 0xf4 51 | #define CMD_TUNE_DOWN 0xf3 52 | #define CMD_PRESET_1 0xf2 53 | #define CMD_PRESET_2 0xf1 54 | #define CMD_PRESET_3 0xf0 55 | #define CMD_PRESET_4 0xef 56 | #define CMD_PRESET_5 0xee 57 | 58 | #define BOSEWAVE_BITS 8 59 | #define BOSEWAVE_HDR_MARK 1061 60 | #define BOSEWAVE_HDR_SPACE 1456 61 | #define BOSEWAVE_BIT_MARK 534 62 | #define BOSEWAVE_ONE_SPACE 468 63 | #define BOSEWAVE_ZERO_SPACE 1447 64 | #define BOSEWAVE_END_MARK 614 65 | #define BOSEWAVE_RPT_SPACE 51200 66 | 67 | //+============================================================================= 68 | #if SEND_BOSEWAVE 69 | unsigned int rawSignal[35]; 70 | void IRsend::sendBoseWave(unsigned char code) { 71 | 72 | int index = 0; 73 | // Header 74 | rawSignal[index++] = BOSEWAVE_HDR_MARK; 75 | rawSignal[index++] = BOSEWAVE_HDR_SPACE; 76 | 77 | // 8 bit command 78 | for (unsigned char mask = 0x80; mask; mask >>= 1) { 79 | rawSignal[index++] = BOSEWAVE_BIT_MARK; 80 | if (code & mask) { 81 | rawSignal[index++] = BOSEWAVE_ONE_SPACE; 82 | } else { 83 | rawSignal[index++] = BOSEWAVE_ZERO_SPACE; 84 | } 85 | } 86 | 87 | // 8 bit command complement 88 | for (unsigned char mask = 0x80; mask; mask >>= 1) { 89 | rawSignal[index++] = BOSEWAVE_BIT_MARK; 90 | if (code & mask) { 91 | rawSignal[index++] = BOSEWAVE_ZERO_SPACE; 92 | } else { 93 | rawSignal[index++] = BOSEWAVE_ONE_SPACE; 94 | } 95 | } 96 | // End transmission 97 | rawSignal[index++] = BOSEWAVE_END_MARK; 98 | 99 | // Transmit 100 | this->sendRaw(rawSignal, 35, 38); 101 | } 102 | #endif 103 | 104 | //+============================================================================= 105 | #if DECODE_BOSEWAVE 106 | bool IRrecv::decodeBoseWave(decode_results *results) { 107 | unsigned char command = 0; // Decoded command 108 | unsigned char complement = 0; // Decoded command complement 109 | 110 | int index = 0; // Index in to results array 111 | 112 | DBG_PRINTLN("Decoding Bose Wave ..."); 113 | 114 | // Check we have enough data 115 | if (irparams.rawlen < (2 * BOSEWAVE_BITS * 2) + 3) { 116 | DBG_PRINT("\tInvalid data length found: "); 117 | DBG_PRINTLN(results->rawlen); 118 | return false; 119 | } 120 | 121 | // Check header "mark" 122 | index = 1; 123 | if (!MATCH_MARK(results->rawbuf[index], BOSEWAVE_HDR_MARK)) { 124 | DBG_PRINT("\tInvalid Header Mark. Expecting "); 125 | DBG_PRINT(BOSEWAVE_HDR_MARK); 126 | DBG_PRINT(". Got "); 127 | DBG_PRINTLN(results->rawbuf[index] * MICROS_PER_TICK); 128 | return false; 129 | } 130 | index++; 131 | 132 | // Check header "space" 133 | if (!MATCH_SPACE(results->rawbuf[index], BOSEWAVE_HDR_SPACE)) { 134 | DBG_PRINT("\tInvalid Header Space. Expecting "); 135 | DBG_PRINT(BOSEWAVE_HDR_SPACE); 136 | DBG_PRINT(". Got "); 137 | DBG_PRINTLN(results->rawbuf[index] * MICROS_PER_TICK); 138 | return false; 139 | } 140 | index++; 141 | 142 | // Decode the data bits 143 | for (int ii = 7; ii >= 0; ii--) { 144 | // Check bit "mark". Mark is always the same length. 145 | if (!MATCH_MARK(results->rawbuf[index], BOSEWAVE_BIT_MARK)) { 146 | DBG_PRINT("\tInvalid command Mark. Expecting "); 147 | DBG_PRINT(BOSEWAVE_BIT_MARK); 148 | DBG_PRINT(". Got "); 149 | DBG_PRINTLN(results->rawbuf[index] * MICROS_PER_TICK); 150 | return false; 151 | } 152 | index++; 153 | 154 | // Check bit "space" 155 | if (MATCH_SPACE(results->rawbuf[index], BOSEWAVE_ONE_SPACE)) { 156 | command |= (0x01 << ii); 157 | } else if (MATCH_SPACE(results->rawbuf[index], BOSEWAVE_ZERO_SPACE)) { 158 | // Nothing to do for zeroes. 159 | } else { 160 | DBG_PRINT("\tInvalid command Space. Got "); 161 | DBG_PRINTLN(results->rawbuf[index] * MICROS_PER_TICK); 162 | return false; 163 | } 164 | index++; 165 | } 166 | 167 | // Decode the command complement bits. We decode it here as the complement 168 | // of the complement (0=1 and 1=0) so we can easily compare it to the command. 169 | for (int ii = 7; ii >= 0; ii--) { 170 | // Check bit "mark". Mark is always the same length. 171 | if (!MATCH_MARK(results->rawbuf[index], BOSEWAVE_BIT_MARK)) { 172 | DBG_PRINT("\tInvalid complement Mark. Expecting "); 173 | DBG_PRINT(BOSEWAVE_BIT_MARK); 174 | DBG_PRINT(". Got "); 175 | DBG_PRINTLN(results->rawbuf[index] * MICROS_PER_TICK); 176 | return false; 177 | } 178 | index++; 179 | 180 | // Check bit "space" 181 | if (MATCH_SPACE(results->rawbuf[index], BOSEWAVE_ONE_SPACE)) { 182 | // Nothing to do. 183 | } else if (MATCH_SPACE(results->rawbuf[index], BOSEWAVE_ZERO_SPACE)) { 184 | complement |= (0x01 << ii); 185 | } else { 186 | DBG_PRINT("\tInvalid complement Space. Got "); 187 | DBG_PRINTLN(results->rawbuf[index] * MICROS_PER_TICK); 188 | return false; 189 | } 190 | index++; 191 | } 192 | 193 | if (command != complement) { 194 | DBG_PRINT("\tComplement is not correct. Command=0x"); 195 | DBG_PRINT(command, HEX); 196 | DBG_PRINT(" Complement=0x"); 197 | DBG_PRINTLN(complement, HEX); 198 | return false; 199 | } else { 200 | DBG_PRINTLN("\tValid command"); 201 | } 202 | 203 | // Check end "mark" 204 | if (MATCH_MARK(results->rawbuf[index], BOSEWAVE_END_MARK) == 0) { 205 | DBG_PRINT("\tInvalid end Mark. Got "); 206 | DBG_PRINTLN(results->rawbuf[index] * MICROS_PER_TICK); 207 | return false; 208 | } 209 | 210 | // Success 211 | results->bits = BOSEWAVE_BITS; 212 | results->value = command; 213 | results->decode_type = BOSEWAVE; 214 | 215 | return true; 216 | } 217 | #endif 218 | -------------------------------------------------------------------------------- /src/irRecv.cpp: -------------------------------------------------------------------------------- 1 | #include "IRremote.h" 2 | 3 | //+============================================================================= 4 | // Decodes the received IR message 5 | // Returns 0 if no data ready, 1 if data ready. 6 | // Results of decoding are stored in results 7 | // 8 | int IRrecv::decode(decode_results *results) { 9 | results->rawbuf = irparams.rawbuf; 10 | results->rawlen = irparams.rawlen; 11 | 12 | results->overflow = irparams.overflow; 13 | 14 | if (irparams.rcvstate != IR_REC_STATE_STOP) { 15 | return false; 16 | } 17 | 18 | #if DECODE_NEC 19 | DBG_PRINTLN("Attempting NEC decode"); 20 | if (decodeNEC(results)) { 21 | return true; 22 | } 23 | #endif 24 | 25 | #if DECODE_SHARP 26 | DBG_PRINTLN("Attempting Sharp decode"); 27 | if (decodeSharp(results)) { 28 | return true; 29 | } 30 | #endif 31 | 32 | #if DECODE_SHARP_ALT 33 | DBG_PRINTLN("Attempting SharpAlt decode"); 34 | if (decodeSharpAlt(results)) { 35 | return true; 36 | } 37 | #endif 38 | 39 | #if DECODE_SONY 40 | DBG_PRINTLN("Attempting Sony decode"); 41 | if (decodeSony(results)) { 42 | return true; 43 | } 44 | #endif 45 | 46 | #if DECODE_SANYO 47 | DBG_PRINTLN("Attempting Sanyo decode"); 48 | if (decodeSanyo(results)) { 49 | return true; 50 | } 51 | #endif 52 | 53 | #if DECODE_MITSUBISHI 54 | DBG_PRINTLN("Attempting Mitsubishi decode"); 55 | if (decodeMitsubishi(results)) { 56 | return true; 57 | } 58 | #endif 59 | 60 | #if DECODE_RC5 61 | DBG_PRINTLN("Attempting RC5 decode"); 62 | if (decodeRC5(results)) { 63 | return true; 64 | } 65 | #endif 66 | 67 | #if DECODE_RC6 68 | DBG_PRINTLN("Attempting RC6 decode"); 69 | if (decodeRC6(results)) { 70 | return true; 71 | } 72 | #endif 73 | 74 | #if DECODE_PANASONIC 75 | DBG_PRINTLN("Attempting Panasonic decode"); 76 | if (decodePanasonic(results)) { 77 | return true; 78 | } 79 | #endif 80 | 81 | #if DECODE_LG 82 | DBG_PRINTLN("Attempting LG decode"); 83 | if (decodeLG(results)) { 84 | return true; 85 | } 86 | #endif 87 | 88 | #if DECODE_JVC 89 | DBG_PRINTLN("Attempting JVC decode"); 90 | if (decodeJVC(results)) { 91 | return true; 92 | } 93 | #endif 94 | 95 | #if DECODE_SAMSUNG 96 | DBG_PRINTLN("Attempting SAMSUNG decode"); 97 | if (decodeSAMSUNG(results)) { 98 | return true; 99 | } 100 | #endif 101 | 102 | #if DECODE_WHYNTER 103 | DBG_PRINTLN("Attempting Whynter decode"); 104 | if (decodeWhynter(results)) { 105 | return true; 106 | } 107 | #endif 108 | 109 | #if DECODE_AIWA_RC_T501 110 | DBG_PRINTLN("Attempting Aiwa RC-T501 decode"); 111 | if (decodeAiwaRCT501(results)) { 112 | return true; 113 | } 114 | #endif 115 | 116 | #if DECODE_DENON 117 | DBG_PRINTLN("Attempting Denon decode"); 118 | if (decodeDenon(results)) { 119 | return true; 120 | } 121 | #endif 122 | 123 | #if DECODE_LEGO_PF 124 | DBG_PRINTLN("Attempting Lego Power Functions"); 125 | if (decodeLegoPowerFunctions(results)) { 126 | return true; 127 | } 128 | #endif 129 | 130 | #if DECODE_MAGIQUEST 131 | DBG_PRINTLN("Attempting MagiQuest decode"); 132 | if (decodeMagiQuest(results)) { 133 | return true; 134 | } 135 | #endif 136 | 137 | #if DECODE_HASH 138 | DBG_PRINTLN("Hash decode"); 139 | // decodeHash returns a hash on any input. 140 | // Thus, it needs to be last in the list. 141 | // If you add any decodes, add them before this. 142 | if (decodeHash(results)) { 143 | return true; 144 | } 145 | #endif 146 | 147 | // Throw away and start over 148 | resume(); 149 | return false; 150 | } 151 | 152 | //+============================================================================= 153 | IRrecv::IRrecv(int recvpin) { 154 | irparams.recvpin = recvpin; 155 | irparams.blinkflag = 0; 156 | } 157 | 158 | IRrecv::IRrecv(int recvpin, int blinkpin) { 159 | irparams.recvpin = recvpin; 160 | irparams.blinkpin = blinkpin; 161 | pinMode(blinkpin, OUTPUT); 162 | irparams.blinkflag = 0; 163 | } 164 | 165 | //+============================================================================= 166 | // initialization 167 | // 168 | #ifdef USE_DEFAULT_ENABLE_IR_IN 169 | void IRrecv::enableIRIn() { 170 | // Interrupt Service Routine - Fires every 50uS 171 | cli(); 172 | // Setup pulse clock timer interrupt 173 | // Prescale /8 (16M/8 = 0.5 microseconds per tick) 174 | // Therefore, the timer interval can range from 0.5 to 128 microseconds 175 | // Depending on the reset value (255 to 0) 176 | timerConfigNormal(); 177 | 178 | // Timer2 Overflow Interrupt Enable 179 | TIMER_ENABLE_INTR; 180 | 181 | TIMER_RESET; 182 | 183 | sei(); 184 | // enable interrupts 185 | 186 | // Initialize state machine variables 187 | irparams.rcvstate = IR_REC_STATE_IDLE; 188 | irparams.rawlen = 0; 189 | 190 | // Set pin modes 191 | pinMode(irparams.recvpin, INPUT); 192 | } 193 | 194 | void IRrecv::disableIRIn() { 195 | cli(); 196 | TIMER_DISABLE_INTR; 197 | sei(); 198 | // enable interrupts 199 | } 200 | 201 | #endif // USE_DEFAULT_ENABLE_IR_IN 202 | 203 | //+============================================================================= 204 | // Enable/disable blinking of pin 13 on IR processing 205 | // 206 | void IRrecv::blink13(int blinkflag) { 207 | #ifdef BLINKLED 208 | irparams.blinkflag = blinkflag; 209 | if (blinkflag) { 210 | pinMode(BLINKLED, OUTPUT); 211 | } 212 | #endif 213 | } 214 | 215 | //+============================================================================= 216 | // Return if receiving new IR signals 217 | // 218 | bool IRrecv::isIdle() { 219 | return (irparams.rcvstate == IR_REC_STATE_IDLE || irparams.rcvstate == IR_REC_STATE_STOP) ? true : false; 220 | } 221 | //+============================================================================= 222 | // Restart the ISR state machine 223 | // 224 | void IRrecv::resume() { 225 | irparams.rcvstate = IR_REC_STATE_IDLE; 226 | irparams.rawlen = 0; 227 | } 228 | 229 | # if DECODE_HASH 230 | //+============================================================================= 231 | // hashdecode - decode an arbitrary IR code. 232 | // Instead of decoding using a standard encoding scheme 233 | // (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value. 234 | // 235 | // The algorithm: look at the sequence of MARK signals, and see if each one 236 | // is shorter (0), the same length (1), or longer (2) than the previous. 237 | // Do the same with the SPACE signals. Hash the resulting sequence of 0's, 238 | // 1's, and 2's to a 32-bit value. This will give a unique value for each 239 | // different code (probably), for most code systems. 240 | // 241 | // http://arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html 242 | // 243 | // Compare two tick values, returning 0 if newval is shorter, 244 | // 1 if newval is equal, and 2 if newval is longer 245 | // Use a tolerance of 20% 246 | // 247 | int IRrecv::compare(unsigned int oldval, unsigned int newval) { 248 | // @formatter:off 249 | if (newval * 10 < oldval * 8) { 250 | return 0; 251 | } 252 | if (oldval * 10 < newval * 8) { 253 | return 2; 254 | } 255 | return 1; 256 | 257 | // @formatter:on 258 | } //+============================================================================= 259 | // Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param 260 | // Converts the raw code values into a 32-bit hash code. 261 | // Hopefully this code is unique for each button. 262 | // This isn't a "real" decoding, just an arbitrary value. 263 | // 264 | #define FNV_PRIME_32 16777619 265 | #define FNV_BASIS_32 2166136261 266 | 267 | long IRrecv::decodeHash(decode_results *results) { 268 | long hash = FNV_BASIS_32; 269 | 270 | // Require at least 6 samples to prevent triggering on noise 271 | if (results->rawlen < 6) { 272 | return false; 273 | } 274 | 275 | for (unsigned int i = 1; (i + 2) < results->rawlen; i++) { 276 | int value = compare(results->rawbuf[i], results->rawbuf[i + 2]); 277 | // Add value into the hash 278 | hash = (hash * FNV_PRIME_32) ^ value; 279 | } 280 | 281 | results->value = hash; 282 | results->bits = 32; 283 | results->decode_type = UNKNOWN; 284 | 285 | return true; 286 | } 287 | #endif // defined(DECODE_HASH) 288 | -------------------------------------------------------------------------------- /examples/LegoPowerFunctionsTests/LegoPowerFunctionsTests.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * LegoPowerFunctionsTest: LEGO Power Functions Tests 3 | * Copyright (c) 2016, 2017 Philipp Henkel 4 | */ 5 | 6 | #include 7 | #include "ir_Lego_PF_BitStreamEncoder.h" 8 | 9 | void runBitStreamEncoderTests(); 10 | 11 | void setup() { 12 | pinMode(LED_BUILTIN, OUTPUT); 13 | 14 | Serial.begin(115200); 15 | #if defined(__AVR_ATmega32U4__) 16 | while (!Serial) 17 | ; //delay for Leonardo, but this loops forever for Maple Serial 18 | #endif 19 | #if defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL) 20 | delay(2000); // To be able to connect Serial monitor after reset and before first printout 21 | #endif 22 | // Just to know which program is running on my Arduino 23 | Serial.println(F("START " __FILE__ " from " __DATE__)); 24 | delay(1000); // wait for reset triggered by serial connection 25 | runBitStreamEncoderTests(); 26 | } 27 | 28 | void loop() { 29 | } 30 | 31 | void runBitStreamEncoderTests() { 32 | Serial.println(); 33 | Serial.println("BitStreamEncoder Tests"); 34 | static LegoPfBitStreamEncoder bitStreamEncoder; 35 | testStartBit(bitStreamEncoder); 36 | testLowBit(bitStreamEncoder); 37 | testHighBit(bitStreamEncoder); 38 | testMessageBitCount(bitStreamEncoder); 39 | testMessageBitCountRepeat(bitStreamEncoder); 40 | testMessage407(bitStreamEncoder); 41 | testMessage407Repeated(bitStreamEncoder); 42 | testGetChannelId1(bitStreamEncoder); 43 | testGetChannelId2(bitStreamEncoder); 44 | testGetChannelId3(bitStreamEncoder); 45 | testGetChannelId4(bitStreamEncoder); 46 | testGetMessageLengthAllHigh(bitStreamEncoder); 47 | testGetMessageLengthAllLow(bitStreamEncoder); 48 | } 49 | 50 | void logTestResult(bool testPassed) { 51 | if (testPassed) { 52 | Serial.println("OK"); 53 | } else { 54 | Serial.println("FAIL ############"); 55 | } 56 | } 57 | 58 | void testStartBit(LegoPfBitStreamEncoder& bitStreamEncoder) { 59 | Serial.print(" testStartBit "); 60 | bitStreamEncoder.reset(0, false); 61 | int startMark = bitStreamEncoder.getMarkDuration(); 62 | int startPause = bitStreamEncoder.getPauseDuration(); 63 | logTestResult(startMark == 158 && startPause == 1184 - 158); 64 | } 65 | 66 | void testLowBit(LegoPfBitStreamEncoder& bitStreamEncoder) { 67 | Serial.print(" testLowBit "); 68 | bitStreamEncoder.reset(0, false); 69 | bitStreamEncoder.next(); 70 | int lowMark = bitStreamEncoder.getMarkDuration(); 71 | int lowPause = bitStreamEncoder.getPauseDuration(); 72 | logTestResult(lowMark == 158 && lowPause == 421 - 158); 73 | } 74 | 75 | void testHighBit(LegoPfBitStreamEncoder& bitStreamEncoder) { 76 | Serial.print(" testHighBit "); 77 | bitStreamEncoder.reset(0xFFFF, false); 78 | bitStreamEncoder.next(); 79 | int highMark = bitStreamEncoder.getMarkDuration(); 80 | int highPause = bitStreamEncoder.getPauseDuration(); 81 | logTestResult(highMark == 158 && highPause == 711 - 158); 82 | } 83 | 84 | void testMessageBitCount(LegoPfBitStreamEncoder& bitStreamEncoder) { 85 | Serial.print(" testMessageBitCount "); 86 | bitStreamEncoder.reset(0xFFFF, false); 87 | int bitCount = 1; 88 | while (bitStreamEncoder.next()) { 89 | bitCount++; 90 | } 91 | logTestResult(bitCount == 18); 92 | } 93 | 94 | boolean check(LegoPfBitStreamEncoder& bitStreamEncoder, unsigned long markDuration, unsigned long pauseDuration) { 95 | bool result = true; 96 | result = result && bitStreamEncoder.getMarkDuration() == markDuration; 97 | result = result && bitStreamEncoder.getPauseDuration() == pauseDuration; 98 | return result; 99 | } 100 | 101 | boolean checkNext(LegoPfBitStreamEncoder& bitStreamEncoder, unsigned long markDuration, unsigned long pauseDuration) { 102 | bool result = bitStreamEncoder.next(); 103 | result = result && check(bitStreamEncoder, markDuration, pauseDuration); 104 | return result; 105 | } 106 | 107 | boolean checkDataBitsOfMessage407(LegoPfBitStreamEncoder& bitStreamEncoder) { 108 | bool result = true; 109 | result = result && checkNext(bitStreamEncoder, 158, 263); 110 | result = result && checkNext(bitStreamEncoder, 158, 263); 111 | result = result && checkNext(bitStreamEncoder, 158, 263); 112 | result = result && checkNext(bitStreamEncoder, 158, 263); 113 | result = result && checkNext(bitStreamEncoder, 158, 263); 114 | result = result && checkNext(bitStreamEncoder, 158, 263); 115 | result = result && checkNext(bitStreamEncoder, 158, 263); 116 | result = result && checkNext(bitStreamEncoder, 158, 553); 117 | result = result && checkNext(bitStreamEncoder, 158, 553); 118 | result = result && checkNext(bitStreamEncoder, 158, 263); 119 | result = result && checkNext(bitStreamEncoder, 158, 263); 120 | result = result && checkNext(bitStreamEncoder, 158, 553); 121 | result = result && checkNext(bitStreamEncoder, 158, 263); 122 | result = result && checkNext(bitStreamEncoder, 158, 553); 123 | result = result && checkNext(bitStreamEncoder, 158, 553); 124 | result = result && checkNext(bitStreamEncoder, 158, 553); 125 | return result; 126 | } 127 | 128 | void testMessage407(LegoPfBitStreamEncoder& bitStreamEncoder) { 129 | Serial.print(" testMessage407 "); 130 | bitStreamEncoder.reset(407, false); 131 | bool result = true; 132 | result = result && check(bitStreamEncoder, 158, 1026); 133 | result = result && checkDataBitsOfMessage407(bitStreamEncoder); 134 | result = result && checkNext(bitStreamEncoder, 158, 1026); 135 | result = result && !bitStreamEncoder.next(); 136 | logTestResult(result); 137 | } 138 | 139 | void testMessage407Repeated(LegoPfBitStreamEncoder& bitStreamEncoder) { 140 | Serial.print(" testMessage407Repeated "); 141 | bitStreamEncoder.reset(407, true); 142 | bool result = true; 143 | result = result && check(bitStreamEncoder, 158, 1026); 144 | result = result && checkDataBitsOfMessage407(bitStreamEncoder); 145 | result = result && checkNext(bitStreamEncoder, 158, 1026L + 5L * 16000L - 10844L); 146 | result = result && checkNext(bitStreamEncoder, 158, 1026); 147 | result = result && checkDataBitsOfMessage407(bitStreamEncoder); 148 | result = result && checkNext(bitStreamEncoder, 158, 1026L + 5L * 16000L - 10844L); 149 | result = result && checkNext(bitStreamEncoder, 158, 1026); 150 | result = result && checkDataBitsOfMessage407(bitStreamEncoder); 151 | result = result && checkNext(bitStreamEncoder, 158, 1026L + 8L * 16000L - 10844L); 152 | result = result && checkNext(bitStreamEncoder, 158, 1026); 153 | result = result && checkDataBitsOfMessage407(bitStreamEncoder); 154 | result = result && checkNext(bitStreamEncoder, 158, 1026L + 8L * 16000L - 10844L); 155 | result = result && checkNext(bitStreamEncoder, 158, 1026); 156 | result = result && checkDataBitsOfMessage407(bitStreamEncoder); 157 | result = result && checkNext(bitStreamEncoder, 158, 1026); 158 | result = result && !bitStreamEncoder.next(); 159 | logTestResult(result); 160 | } 161 | 162 | void testMessageBitCountRepeat(LegoPfBitStreamEncoder& bitStreamEncoder) { 163 | Serial.print(" testMessageBitCountRepeat "); 164 | bitStreamEncoder.reset(0xFFFF, true); 165 | int bitCount = 1; 166 | while (bitStreamEncoder.next()) { 167 | bitCount++; 168 | } 169 | logTestResult(bitCount == 5 * 18); 170 | } 171 | 172 | void testGetChannelId1(LegoPfBitStreamEncoder& bitStreamEncoder) { 173 | Serial.print(" testGetChannelId1 "); 174 | bitStreamEncoder.reset(407, false); 175 | logTestResult(bitStreamEncoder.getChannelId() == 1); 176 | } 177 | 178 | void testGetChannelId2(LegoPfBitStreamEncoder& bitStreamEncoder) { 179 | Serial.print(" testGetChannelId2 "); 180 | bitStreamEncoder.reset(4502, false); 181 | logTestResult(bitStreamEncoder.getChannelId() == 2); 182 | } 183 | 184 | void testGetChannelId3(LegoPfBitStreamEncoder& bitStreamEncoder) { 185 | Serial.print(" testGetChannelId3 "); 186 | bitStreamEncoder.reset(8597, false); 187 | logTestResult(bitStreamEncoder.getChannelId() == 3); 188 | } 189 | 190 | void testGetChannelId4(LegoPfBitStreamEncoder& bitStreamEncoder) { 191 | Serial.print(" testGetChannelId4 "); 192 | bitStreamEncoder.reset(12692, false); 193 | logTestResult(bitStreamEncoder.getChannelId() == 4); 194 | } 195 | 196 | void testGetMessageLengthAllHigh(LegoPfBitStreamEncoder& bitStreamEncoder) { 197 | Serial.print(" testGetMessageLengthAllHigh "); 198 | bitStreamEncoder.reset(0xFFFF, false); 199 | logTestResult(bitStreamEncoder.getMessageLength() == 13744); 200 | } 201 | 202 | void testGetMessageLengthAllLow(LegoPfBitStreamEncoder& bitStreamEncoder) { 203 | Serial.print(" testGetMessageLengthAllLow "); 204 | bitStreamEncoder.reset(0x0, false); 205 | logTestResult(bitStreamEncoder.getMessageLength() == 9104); 206 | } 207 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IRremote Arduino Library 2 | Available as Arduino library "IRremote" 3 | 4 | ### [Version 2.6.0](https://github.com/z3t0/Arduino-IRremote/releases) 5 | 6 | [![License: GPL v2](https://img.shields.io/badge/License-GPLv2-blue.svg)](https://www.gnu.org/licenses/gpl-2.0) 7 | [![Installation instructions](https://www.ardu-badge.com/badge/IRremote.svg?)](https://www.ardu-badge.com/IRremote) 8 | [![Join the chat at https://gitter.im/z3t0/Arduino-IRremote](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/z3t0/Arduino-IRremote?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 9 | [![LibraryBuild](https://github.com/z3t0/Arduino-IRremote/workflows/LibraryBuild/badge.svg)](https://github.com/z3t0/Arduino-IRremote/actions) 10 | 11 | This library enables you to send and receive using infra-red signals on an Arduino. 12 | 13 | Tutorials and more information will be made available on [the official homepage](http://z3t0.github.io/Arduino-IRremote/). 14 | 15 | # Installation 16 | Click on the LibraryManager badge above to see the instructions. 17 | 18 | # FAQ 19 | - IR does not work right when I use Neopixels (aka WS2811/WS2812/WS2812B) 20 | Whether you use the Adafruit Neopixel lib, or FastLED, interrupts get disabled on many lower end CPUs like the basic arduinos. In turn, this stops the IR interrupt handler from running when it needs to. There are some solutions to this on some processors, [see this page from Marc MERLIN](http://marc.merlins.org/perso/arduino/post_2017-04-03_Arduino-328P-Uno-Teensy3_1-ESP8266-ESP32-IR-and-Neopixels.html) 21 | - The default IR timer on AVR's is timer 2. Since the Arduino Tone library as well as analogWrite() for pin 3 and pin 11 requires timer 2, this functionality cannot be used simultaneously. 22 | - You can use **multiple IR receiver** by just connecting the output pins of several IR receivers together. The IR receivers use an NPN transistor as output device with just a 30k resistor to VCC. This is almost "open collector" and allows connecting of several output pins. 23 | 24 | # Supported IR Protocols 25 | Aiwa, BoseWave, Denon, Dish, JVC, Lego, LG, MagiQuest, Mitsubishi, Panasonic, RC5, RC6, Samsung, Sanyo, Sharp, Sony, Whynter, (Pronto). 26 | 27 | ## Handling unknown Protocols 28 | ### Disclaimer 29 | This library was never designed to handle long codes like the ones used by air conditioners. See [Recording long Infrared Remote control signals with Arduino](https://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino).
30 | The main reason is, that it was designed to fit inside MCUs with relatively low levels of resources and was intended to work as a library together with other applications which also require some resources of the MCU to operate. 31 | 32 | If you do not know which protocol your IR transmitter uses, you have several choices. 33 | - Use the [IRrecvDumpV2 example](examples/IRrecvDumpV2) to dump out the IR timing. You can then reproduce/send this timing with the [IRsendRawDemo example](examples/IRsendRawDemo). For **long codes** like from air conditioners, you can **change the length of the input buffer** in [IRremoteInt.h](src/private/IRremoteInt.h#L30). 34 | - If you have a bigger Arduino board at hand (> 100 kByte program space) you can try the [IRremoteDecode example](https://github.com/bengtmartensson/Arduino-DecodeIR/blob/master/examples/IRremoteDecode/IRremoteDecode.ino) of the Arduino library DecodeIR. 35 | - Use [IrScrutinizer](http://www.harctoolbox.org/IrScrutinizer.html). It can automatically generate a send sketch for your protocol by exporting as "Arduino Raw". It supports IRremote, the old [IRLib](https://github.com/cyborg5/IRLib) and [Infrared4Arduino](https://github.com/bengtmartensson/Infrared4Arduino). 36 | - Use the [IRMP AllProtocol example](https://github.com/ukw100/IRMP#allprotocol-example) and check the serial output if the protocol is one of the 40 supported protocols. 37 | 38 | # Supported Boards 39 | - Arduino Uno / Mega / Leonardo / Duemilanove / Diecimila / LilyPad / Mini / Fio / Nano etc. 40 | - Teensy 1.0 / 1.0++ / 2.0 / 2++ / 3.0 / 3.1 / Teensy-LC; Credits: @PaulStoffregen (Teensy Team) 41 | - Sanguino 42 | - ATmega8, 48, 88, 168, 328 43 | - ATmega8535, 16, 32, 164, 324, 644, 1284, 44 | - ATmega64, 128 45 | - ATmega4809 (Nano every) 46 | - ATtiny84, 85 47 | - SAMD21 (receive only) 48 | - ESP32 49 | - ESP8266 is supported in a fork based on an old codebase that isn't as recent, but it works reasonably well given that perfectly timed sub millisecond interrupts are different on that chip. See https://github.com/markszabo/IRremoteESP8266 50 | - Sparkfun Pro Micro 51 | 52 | We are open to suggestions for adding support to new boards, however we highly recommend you contact your supplier first and ask them to provide support from their side. 53 | 54 | ## Hardware specifications 55 | The timer and the pin usage can be adjusted in [IRremoteBoardDefs.h](src/private/IRremoteBoardDefs.h) 56 | 57 | | Board/CPU | IR-Receive Pin | Timers | 58 | |--------------------------------------------------------------------------|---------------------|-------------------| 59 | | [ATtiny84](https://github.com/SpenceKonde/ATTinyCore) | **6** | **1** | 60 | | [ATtiny85](https://github.com/SpenceKonde/ATTinyCore) | **1** | **TINY0** | 61 | | [ATmega8](https://github.com/MCUdude/MiniCore) | **9** | **1** | 62 | | [ATmega48, ATmega88, ATmega168, ATmega328](https://github.com/MCUdude/MiniCore) | **3**, 9 | 1, **2** | 63 | | [ATmega1284](https://github.com/MCUdude/MightyCore) | 13, 14, 6 | 1, **2**, 3 | 64 | | [ATmega164, ATmega324, ATmega644](https://github.com/MCUdude/MightyCore) | 13, **14** | 1, **2** | 65 | | [ATmega8535 ATmega16, ATmega32](https://github.com/MCUdude/MightyCore) | **13** | **1** | 66 | | [ATmega64, ATmega128, ATmega1281, ATmega2561](https://github.com/MCUdude/MegaCore) | **13** | **1** | 67 | | [ATmega8515, ATmega162](https://github.com/MCUdude/MajorCore) | **13** | **1** | 68 | | ATmega1280, ATmega2560 | 5, 6, **9**, 11, 46 | 1, **2**, 3, 4, 5 | 69 | | ATmega4809 | 5, 6, **9**, 11, 46 | **TCB0** | 70 | | Leonardo (Atmega32u4) | 5, **9**, 13 | 1, 3, **4_HS** | 71 | | [ESP32](http://esp32.net/) | **4**, all pins | **1** | 72 | | [Sparkfun Pro Micro](https://www.sparkfun.com/products/12640) | **5**, 9, 13 | 1, **3**, 4_HS | 73 | | [Teensy 1.0](https://www.pjrc.com/teensy/) | **17** | **1** | 74 | | [Teensy 2.0](https://www.pjrc.com/teensy/) | **9**, 10, 14 | 1, **3**, 4_HS | 75 | | [Teensy++ 1.0 / 2.0](https://www.pjrc.com/teensy/) | **1**, 16, 25 | 1, **2**, 3 | 76 | | [Teensy 3.0 / 3.1](https://www.pjrc.com/teensy/) | **5** | **CMT** | 77 | | [Teensy-LC](https://www.pjrc.com/teensy/) | **16** | **TPM1** | 78 | 79 | ## Usage 80 | - TODO (Check examples for now) 81 | 82 | ## Revision History 83 | Please see [changelog.md](https://github.com/z3t0/Arduino-IRremote/blob/master/changelog.md). 84 | 85 | ## API documentation 86 | This project documents the library API using [Doxygen](http://www.doxygen.org). 87 | It is planned to make generated and up-to-date API documentation available online. 88 | 89 | To generate the API documentation, 90 | Doxygen, as well as [Graphviz](http://www.graphviz.org/) should be installed. 91 | (Note that on Windows, it may be necessary to add the Graphviz binary directory 92 | (something like `C:\Program Files\Graphviz2.38\bin`) 93 | to the `PATH` variable manually.) 94 | With Doxygen and Graphviz installed, issue the command 95 | `doxygen` from the command line in the main project directory, which will 96 | generate the API documentation in HTML format. 97 | The just generated `api-doc/index.html` can now be opened in a browser. 98 | 99 | ## Contributing 100 | If you want to contribute to this project: 101 | - Report bugs and errors 102 | - Ask for enhancements 103 | - Create issues and pull requests 104 | - Tell other people about this library 105 | - Contribute new protocols 106 | 107 | Check [here](https://github.com/z3t0/Arduino-IRremote/blob/master/Contributing.md) for some guidelines. 108 | 109 | ## Contact 110 | Email: zetoslab@gmail.com 111 | Please only email me if it is more appropriate than creating an Issue / PR. I **will** not respond to requests for adding support for particular boards, unless of course you are the creator of the board and would like to cooperate on the project. I will also **ignore** any emails asking me to tell you how to implement your ideas. However, if you have a private inquiry that you would only apply to you and you would prefer it to be via email, by all means. 112 | 113 | ## Contributors 114 | Check [here](https://github.com/z3t0/Arduino-IRremote/blob/master/Contributors.md) 115 | 116 | ## Copyright 117 | Copyright 2009-2012 Ken Shirriff 118 | Copyright (c) 2016 Rafi Khan -------------------------------------------------------------------------------- /src/IRremote.cpp: -------------------------------------------------------------------------------- 1 | //****************************************************************************** 2 | // IRremote 3 | // Version 2.0.1 June, 2015 4 | // Copyright 2009 Ken Shirriff 5 | // For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html 6 | // 7 | // Modified by Paul Stoffregen to support other boards and timers 8 | // Modified by Mitra Ardron 9 | // Added Sanyo and Mitsubishi controllers 10 | // Modified Sony to spot the repeat codes that some Sony's send 11 | // 12 | // Interrupt code based on NECIRrcv by Joe Knapp 13 | // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 14 | // Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ 15 | // 16 | // JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 17 | // LG added by Darryl Smith (based on the JVC protocol) 18 | // Whynter A/C ARC-110WD added by Francesco Meschia 19 | //****************************************************************************** 20 | 21 | // Defining IR_GLOBAL here allows us to declare the instantiation of global variables 22 | #define IR_GLOBAL 23 | #include "IRremote.h" 24 | #undef IR_GLOBAL 25 | 26 | //+============================================================================= 27 | // The match functions were (apparently) originally MACROs to improve code speed 28 | // (although this would have bloated the code) hence the names being CAPS 29 | // A later release implemented debug output and so they needed to be converted 30 | // to functions. 31 | // I tried to implement a dual-compile mode (DEBUG/non-DEBUG) but for some 32 | // reason, no matter what I did I could not get them to function as macros again. 33 | // I have found a *lot* of bugs in the Arduino compiler over the last few weeks, 34 | // and I am currently assuming that one of these bugs is my problem. 35 | // I may revisit this code at a later date and look at the assembler produced 36 | // in a hope of finding out what is going on, but for now they will remain as 37 | // functions even in non-DEBUG mode 38 | // 39 | int MATCH(int measured, int desired) { 40 | #if DEBUG 41 | Serial.print(F("Testing: ")); 42 | Serial.print(TICKS_LOW(desired), DEC); 43 | Serial.print(F(" <= ")); 44 | Serial.print(measured, DEC); 45 | Serial.print(F(" <= ")); 46 | Serial.print(TICKS_HIGH(desired), DEC); 47 | #endif 48 | bool passed = ((measured >= TICKS_LOW(desired)) && (measured <= TICKS_HIGH(desired))); 49 | #if DEBUG 50 | if (passed) { 51 | Serial.println(F("?; passed")); 52 | } else { 53 | Serial.println(F("?; FAILED")); 54 | } 55 | #endif 56 | return passed; 57 | } 58 | 59 | //+======================================================== 60 | // Due to sensor lag, when received, Marks tend to be 100us too long 61 | // 62 | int MATCH_MARK(int measured_ticks, int desired_us) { 63 | #if DEBUG 64 | Serial.print(F("Testing mark (actual vs desired): ")); 65 | Serial.print(measured_ticks * MICROS_PER_TICK, DEC); 66 | Serial.print(F("us vs ")); 67 | Serial.print(desired_us, DEC); 68 | Serial.print(F("us: ")); 69 | Serial.print(TICKS_LOW(desired_us + MARK_EXCESS_MICROS) * MICROS_PER_TICK, DEC); 70 | Serial.print(F(" <= ")); 71 | Serial.print(measured_ticks * MICROS_PER_TICK, DEC); 72 | Serial.print(F(" <= ")); 73 | Serial.print(TICKS_HIGH(desired_us + MARK_EXCESS_MICROS) * MICROS_PER_TICK, DEC); 74 | #endif 75 | // compensate for marks exceeded by demodulator hardware 76 | bool passed = ((measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS_MICROS)) 77 | && (measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS_MICROS))); 78 | #if DEBUG 79 | if (passed) { 80 | Serial.println(F("?; passed")); 81 | } else { 82 | Serial.println(F("?; FAILED")); 83 | } 84 | #endif 85 | return passed; 86 | } 87 | 88 | //+======================================================== 89 | // Due to sensor lag, when received, Spaces tend to be 100us too short 90 | // 91 | int MATCH_SPACE(int measured_ticks, int desired_us) { 92 | #if DEBUG 93 | Serial.print(F("Testing space (actual vs desired): ")); 94 | Serial.print(measured_ticks * MICROS_PER_TICK, DEC); 95 | Serial.print(F("us vs ")); 96 | Serial.print(desired_us, DEC); 97 | Serial.print(F("us: ")); 98 | Serial.print(TICKS_LOW(desired_us - MARK_EXCESS_MICROS) * MICROS_PER_TICK, DEC); 99 | Serial.print(F(" <= ")); 100 | Serial.print(measured_ticks * MICROS_PER_TICK, DEC); 101 | Serial.print(F(" <= ")); 102 | Serial.print(TICKS_HIGH(desired_us - MARK_EXCESS_MICROS) * MICROS_PER_TICK, DEC); 103 | #endif 104 | // compensate for marks exceeded and spaces shortened by demodulator hardware 105 | bool passed = ((measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS_MICROS)) 106 | && (measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS_MICROS))); 107 | #if DEBUG 108 | if (passed) { 109 | Serial.println(F("?; passed")); 110 | } else { 111 | Serial.println(F("?; FAILED")); 112 | } 113 | #endif 114 | return passed; 115 | } 116 | 117 | //+============================================================================= 118 | // Interrupt Service Routine - Fires every 50uS 119 | // TIMER2 interrupt code to collect raw data. 120 | // Widths of alternating SPACE, MARK are recorded in rawbuf. 121 | // Recorded in ticks of 50uS [microseconds, 0.000050 seconds] 122 | // 'rawlen' counts the number of entries recorded so far. 123 | // First entry is the SPACE between transmissions. 124 | // As soon as a the first [SPACE] entry gets long: 125 | // Ready is set; State switches to IDLE; Timing of SPACE continues. 126 | // As soon as first MARK arrives: 127 | // Gap width is recorded; Ready is cleared; New logging starts 128 | // 129 | ISR (TIMER_INTR_NAME) { 130 | TIMER_RESET; // reset timer interrupt flag if required (currently only for Teensy and ATmega4809) 131 | 132 | // Read if IR Receiver -> SPACE [xmt LED off] or a MARK [xmt LED on] 133 | // digitalRead() is very slow. Optimisation is possible, but makes the code unportable 134 | uint8_t irdata = (uint8_t) digitalRead(irparams.recvpin); 135 | 136 | irparams.timer++; // One more 50uS tick 137 | if (irparams.rawlen >= RAW_BUFFER_LENGTH) { 138 | irparams.rcvstate = IR_REC_STATE_OVERFLOW; // Buffer overflow 139 | } 140 | 141 | /* 142 | * Due to a ESP32 compiler bug https://github.com/espressif/esp-idf/issues/1552 no switch statements are possible for ESP32 143 | * So we change the code to if / else if 144 | */ 145 | // switch (irparams.rcvstate) { 146 | //...................................................................... 147 | if (irparams.rcvstate == IR_REC_STATE_IDLE) { // In the middle of a gap 148 | if (irdata == MARK) { 149 | if (irparams.timer < GAP_TICKS) { // Not big enough to be a gap. 150 | irparams.timer = 0; 151 | } else { 152 | // Gap just ended; Record duration; Start recording transmission 153 | irparams.overflow = false; 154 | irparams.rawlen = 0; 155 | irparams.rawbuf[irparams.rawlen++] = irparams.timer; 156 | irparams.timer = 0; 157 | irparams.rcvstate = IR_REC_STATE_MARK; 158 | } 159 | } 160 | } else if (irparams.rcvstate == IR_REC_STATE_MARK) { // Timing Mark 161 | if (irdata == SPACE) { // Mark ended; Record time 162 | irparams.rawbuf[irparams.rawlen++] = irparams.timer; 163 | irparams.timer = 0; 164 | irparams.rcvstate = IR_REC_STATE_SPACE; 165 | } 166 | } else if (irparams.rcvstate == IR_REC_STATE_SPACE) { // Timing Space 167 | if (irdata == MARK) { // Space just ended; Record time 168 | irparams.rawbuf[irparams.rawlen++] = irparams.timer; 169 | irparams.timer = 0; 170 | irparams.rcvstate = IR_REC_STATE_MARK; 171 | 172 | } else if (irparams.timer > GAP_TICKS) { // Space 173 | // A long Space, indicates gap between codes 174 | // Flag the current code as ready for processing 175 | // Switch to STOP 176 | // Don't reset timer; keep counting Space width 177 | irparams.rcvstate = IR_REC_STATE_STOP; 178 | } 179 | } else if (irparams.rcvstate == IR_REC_STATE_STOP) { // Waiting; Measuring Gap 180 | if (irdata == MARK) { 181 | irparams.timer = 0; // Reset gap timer 182 | } 183 | } else if (irparams.rcvstate == IR_REC_STATE_OVERFLOW) { // Flag up a read overflow; Stop the State Machine 184 | irparams.overflow = true; 185 | irparams.rcvstate = IR_REC_STATE_STOP; 186 | } 187 | 188 | #ifdef BLINKLED 189 | // If requested, flash LED while receiving IR data 190 | if (irparams.blinkflag) { 191 | if (irdata == MARK) { 192 | if (irparams.blinkpin) { 193 | digitalWrite(irparams.blinkpin, HIGH); // Turn user defined pin LED on 194 | } else { 195 | BLINKLED_ON(); // if no user defined LED pin, turn default LED pin for the hardware on 196 | } 197 | } else { 198 | if (irparams.blinkpin) { 199 | digitalWrite(irparams.blinkpin, LOW); // Turn user defined pin LED on 200 | } else { 201 | BLINKLED_OFF(); // if no user defined LED pin, turn default LED pin for the hardware on 202 | } 203 | } 204 | } 205 | #endif // BLINKLED 206 | } 207 | --------------------------------------------------------------------------------