/* * ReceiveAndSend.cpp * * Record and play back last received IR signal at button press. * The logic is: * If the button is pressed, send the IR code. * If an IR code is received, record it. * If the protocol is unknown or not enabled, store it as raw data for later sending. * * An example for simultaneous receiving and sending is in the UnitTest example. * * An IR detector/demodulator must be connected to the input IR_RECEIVE_PIN. * * A button must be connected between the input SEND_BUTTON_PIN and ground. * A visible LED can be connected to STATUS_PIN to provide status. * * * Initially coded 2009 Ken Shirriff http://www.righto.com * * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote. * ************************************************************************************ * MIT License * * Copyright (c) 2009-2023 Ken Shirriff, Armin Joachimsmeyer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished * to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ************************************************************************************ */ #include #include "PinDefinitionsAndMore.h" // Define macros for input and output pin etc. /* * Specify which protocol(s) should be used for decoding. * If no protocol is defined, all protocols (except Bang&Olufsen) are active. * This must be done before the #include */ //#define DECODE_DENON // Includes Sharp //#define DECODE_JVC //#define DECODE_KASEIKYO //#define DECODE_PANASONIC // alias for DECODE_KASEIKYO //#define DECODE_LG #define DECODE_NEC // Includes Apple and Onkyo //#define DECODE_SAMSUNG //#define DECODE_SONY //#define DECODE_RC5 //#define DECODE_RC6 //#define DECODE_BOSEWAVE //#define DECODE_LEGO_PF //#define DECODE_MAGIQUEST //#define DECODE_WHYNTER //#define DECODE_FAST // #if !defined(RAW_BUFFER_LENGTH) # if RAMEND <= 0x4FF || RAMSIZE < 0x4FF #define RAW_BUFFER_LENGTH 120 # elif RAMEND <= 0xAFF || RAMSIZE < 0xAFF // 0xAFF for LEONARDO #define RAW_BUFFER_LENGTH 400 // 600 is too much here, because we have additional uint8_t rawCode[RAW_BUFFER_LENGTH]; # else #define RAW_BUFFER_LENGTH 750 # endif #endif //#define EXCLUDE_UNIVERSAL_PROTOCOLS // Saves up to 1000 bytes program memory. //#define EXCLUDE_EXOTIC_PROTOCOLS // saves around 650 bytes program memory if all other protocols are active //#define NO_LED_FEEDBACK_CODE // saves 92 bytes program memory //#define RECORD_GAP_MICROS 12000 // Default is 8000. Activate it for some LG air conditioner protocols //#define SEND_PWM_BY_TIMER // Disable carrier PWM generation in software and use (restricted) hardware PWM. //#define USE_NO_SEND_PWM // Use no carrier PWM, just simulate an active low receiver signal. Overrides SEND_PWM_BY_TIMER definition // MARK_EXCESS_MICROS is subtracted from all marks and added to all spaces before decoding, // to compensate for the signal forming of different IR receiver modules. See also IRremote.hpp line 142. #define MARK_EXCESS_MICROS 20 // Adapt it to your IR receiver module. 20 is recommended for the cheap VS1838 modules. //#define DEBUG // Activate this for lots of lovely debug output from the decoders. #include int SEND_BUTTON_PIN = APPLICATION_PIN; int DELAY_BETWEEN_REPEAT = 50; // Storage for the recorded code struct storedIRDataStruct { IRData receivedIRData; // extensions for sendRaw uint8_t rawCode[RAW_BUFFER_LENGTH]; // The durations if raw uint8_t rawCodeLength; // The length of the code } sStoredIRData; bool sSendButtonWasActive; void storeCode(); void sendCode(storedIRDataStruct *aIRDataToSend); void setup() { pinMode(SEND_BUTTON_PIN, INPUT_PULLUP); Serial.begin(115200); #if defined(__AVR_ATmega32U4__) || defined(SERIAL_PORT_USBVIRTUAL) || defined(SERIAL_USB) /*stm32duino*/|| defined(USBCON) /*STM32_stm32*/|| defined(SERIALUSB_PID) || defined(ARDUINO_attiny3217) delay(4000); // To be able to connect Serial monitor after reset or power up and before first print out. Do not wait for an attached Serial Monitor! #endif // Just to know which program is running on my Arduino Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE)); // Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK); Serial.print(F("Ready to receive IR signals of protocols: ")); printActiveIRProtocols(&Serial); Serial.println(F("at pin " STR(IR_RECEIVE_PIN))); IrSender.begin(); // Start with IR_SEND_PIN -which is defined in PinDefinitionsAndMore.h- as send pin and enable feedback LED at default feedback LED pin Serial.print(F("Ready to send IR signals at pin " STR(IR_SEND_PIN) " on press of button at pin ")); Serial.println(SEND_BUTTON_PIN); } void loop() { // If button pressed, send the code. bool tSendButtonIsActive = (digitalRead(SEND_BUTTON_PIN) == LOW); // Button pin is active LOW /* * Check for current button state */ if (tSendButtonIsActive) { if (!sSendButtonWasActive) { Serial.println(F("Stop receiving")); IrReceiver.stop(); } /* * Button pressed -> send stored data */ Serial.print(F("Button pressed, now sending ")); if (sSendButtonWasActive == tSendButtonIsActive) { Serial.print(F("repeat ")); sStoredIRData.receivedIRData.flags = IRDATA_FLAGS_IS_REPEAT; } else { sStoredIRData.receivedIRData.flags = IRDATA_FLAGS_EMPTY; } Serial.flush(); // To avoid disturbing the software PWM generation by serial output interrupts sendCode(&sStoredIRData); delay(DELAY_BETWEEN_REPEAT); // Wait a bit between retransmissions } else if (sSendButtonWasActive) { /* * Button is just released -> activate receiving */ // Restart receiver Serial.println(F("Button released -> start receiving")); IrReceiver.start(); } else if (IrReceiver.decode()) { /* * Button is not pressed and data available -> store received data and resume */ storeCode(); IrReceiver.resume(); // resume receiver } sSendButtonWasActive = tSendButtonIsActive; delay(100); } // Stores the code for later playback in sStoredIRData // Most of this code is just logging void storeCode() { if (IrReceiver.decodedIRData.rawDataPtr->rawlen < 4) { Serial.print(F("Ignore data with rawlen=")); Serial.println(IrReceiver.decodedIRData.rawDataPtr->rawlen); return; } if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT) { Serial.println(F("Ignore repeat")); return; } if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_AUTO_REPEAT) { Serial.println(F("Ignore autorepeat")); return; } if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_PARITY_FAILED) { Serial.println(F("Ignore parity error")); return; } /* * Copy decoded data */ sStoredIRData.receivedIRData = IrReceiver.decodedIRData; if (sStoredIRData.receivedIRData.protocol == UNKNOWN) { Serial.print(F("Received unknown code and store ")); Serial.print(IrReceiver.decodedIRData.rawDataPtr->rawlen - 1); Serial.println(F(" timing entries as raw ")); IrReceiver.printIRResultRawFormatted(&Serial, true); // Output the results in RAW format sStoredIRData.rawCodeLength = IrReceiver.decodedIRData.rawDataPtr->rawlen - 1; /* * Store the current raw data in a dedicated array for later usage */ IrReceiver.compensateAndStoreIRResultInArray(sStoredIRData.rawCode); } else { IrReceiver.printIRResultShort(&Serial); IrReceiver.printIRSendUsage(&Serial); sStoredIRData.receivedIRData.flags = 0; // clear flags -esp. repeat- for later sending Serial.println(); } } void sendCode(storedIRDataStruct *aIRDataToSend) { if (aIRDataToSend->receivedIRData.protocol == UNKNOWN /* i.e. raw */) { // Assume 38 KHz IrSender.sendRaw(aIRDataToSend->rawCode, aIRDataToSend->rawCodeLength, 38); Serial.print(F("raw ")); Serial.print(aIRDataToSend->rawCodeLength); Serial.println(F(" marks or spaces")); } else { /* * Use the write function, which does the switch for different protocols */ IrSender.write(&aIRDataToSend->receivedIRData); printIRResultShort(&Serial, &aIRDataToSend->receivedIRData, false); } }