//from https://iot-kmutnb.github.io/blogs/sensors/ir_receiver/
#if defined(__AVR__)
#define IR_PIN (2) // use Arduino D2 pin
#else if defined(ESP32)
#define IR_PIN (18) // use GPIO-18 pin
#endif
#define BUF_SIZE (128)
#define HEADER_MARK_MIN (8000)
#define TIMEOUT_MS (70)
#define HEADER_MARK_MAX (HEADER_MARK_MIN+2000)
#define HEADER_SPACE_MIN (4000)
#define HEADER_SPACE_MAX (HEADER_SPACE_MIN+1000)
#define REPEAT_SPACE_MIN (2000)
#define REPEAT_SPACE_MAX (REPEAT_SPACE_MIN+1000)
#define BIT_MARK_MIN (500)
#define BIT_MARK_MAX (BIT_MARK_MIN+200)
#define INVALID_CODE (0x00000000)
#define REPEATED_CODE (0xffffffff)
#define DEBUG
#define BUF_SIZE (128)
volatile uint32_t pulse_widths_count;
volatile uint16_t pulse_widths[ BUF_SIZE ];
volatile uint32_t ts_saved;
#if defined(ESP32)
IRAM_ATTR void ir_recv_isr();
#endif
void setup() {
Serial.begin( 9600 );
Serial.println( F("Arduino Infrared Sender - Receiver") );
pinMode( IR_PIN, INPUT );
}
void loop() {
uint32_t ir_code = ir_decode();
if ( ir_code != INVALID_CODE ) {
if ( ir_code == REPEATED_CODE ) {
Serial.println( "Repeated Code" );
} else {
Serial.print( "Code: " );
Serial.println( ir_code, HEX );
}
}
delay(5);
}
void ir_recv_isr() { // ISR
uint32_t ts_now = micros();
if ( pulse_widths_count > 0 ) {
pulse_widths[ pulse_widths_count-1 ] = (ts_now - ts_saved);
}
ts_saved = ts_now;
if ( pulse_widths_count < BUF_SIZE ) {
pulse_widths_count++;
}
}
typedef enum { S0=0, S1, S2, S3 } state_t;
uint32_t ir_decode() {
static state_t state = S0;
static uint32_t ts_start = 0;
uint32_t ret_code = INVALID_CODE;
switch (state) {
case S0:
pulse_widths_count = 0;
// Enable the external interrupt on the IR pin.
attachInterrupt( digitalPinToInterrupt(IR_PIN),
ir_recv_isr, CHANGE );
state = S1;
break;
case S1:
if ( pulse_widths_count > 2 ) {
ts_start = millis();
state = S2;
}
break;
case S2:
if ( millis() - ts_start >= TIMEOUT_MS ) {
// Disable the external interrupt on the IR pin.
detachInterrupt( digitalPinToInterrupt(IR_PIN) );
uint32_t n = pulse_widths_count-2;
volatile uint16_t *p = pulse_widths;
if ( HEADER_MARK_MIN < p[0] && p[0] < HEADER_MARK_MAX ) {
if ( HEADER_SPACE_MIN < p[1] && p[1] < HEADER_SPACE_MAX ) {
// message header found
uint32_t code = 0;
for ( uint32_t i=2; i < n; i+=2 ) {
#ifdef DEBUG
Serial.print( p[i] );
Serial.print( ' ' );
Serial.println( p[i+1] );
#endif
if ( BIT_MARK_MIN < p[i] && p[i] < BIT_MARK_MAX ) {
code = (code << 1) | (p[i+1] > BIT_MARK_MAX);
} else { // bit timing error
code = INVALID_CODE;
break;
}
} // end-for
if ( code != INVALID_CODE ) {
ret_code = code;
}
}
else if ( REPEAT_SPACE_MIN < p[1] && p[1] < REPEAT_SPACE_MAX ) {
// repeated code found
ret_code = REPEATED_CODE;
}
}
state = S0;
}
break;
default:
state = S0;
}
return ret_code;
}