IR1838 Decode Success
IR1838 Decode Success
![IR1838 Decode Success](/content/images/size/w2000/2023/09/Screenshot-at-2023-09-17-04-55-37.png)
Finally after much tinkering a general direct packet decoder for remotes is working. But what is powerful about this from a foundational sense is now a RPi2040 can decode any remote, and do so strictly from interrupt calls. Your system is not tied up waiting for the next bit. That's game changing because it is one building block in building complex multi-tasking concepts into small systems. In addition you have built your own library - from scratch.
![](https://www.hotconfig.com/content/images/2023/09/image-47.png)
- There is incredible bit width slew in these junk remotes. Small bits require an astounding time slew from 450 to 650 microseconds. Really?!
- Quickly pressing the small remote sends a clean packet. Anything else will send garbage with a reset bit in the range of 2000-2350 microseconds.
- Because the clock slews are absolutely horrific - and do not seem to cleanly work in multiples - you have to think in terms of time ranges as specific symbols.
- A startup bit of approximately 8800 - 9200 microseconds initiates the remote packet - stage 1
- A second bit of approximately 4200 - 4600 microseconds initiates stage 2.
- After this 8 toggles of two bit types follow. The long bit being from 1550-1800 and the short bit being from 450-650 us.
- After this a encoded bit pattern follows out to approximately 48 bits of either short bits (450-650 us) and long bits (1550-1800)
- A sign-off 'long bit / short bit' will finish the packet.
The decoder code:
#include <stdio.h>
#include <math.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#define max_pulse 14000
#define max_bit_array 80
#define diagnostic 0
#define packet_threshold 48
uint time_a = 0;
uint elapsed_time = 0;
uint old_elapsed_time = 0;
uint difference_time = 0;
uint old_difference_time = 0;
int bit_state = 0;
int a_count = 0;
int b_count = 0;
char d[max_bit_array] = {0};
int cpos = 0;
void reset_run()
{
a_count = 0;
b_count = 0;
bit_state = 0;
cpos = 0;
for (int t = 0; t < max_bit_array; t++)
{
d[t] = 0;
}
}
int check_range(uint elapsed, uint minval, uint maxval)
{
if ((elapsed >= minval) && (elapsed <= maxval))
return 1;
return 0;
}
void gpio_callback(uint gpio, uint32_t events)
{
elapsed_time = time_us_32();
old_difference_time = difference_time; // Shuttle down.1
difference_time = elapsed_time - old_elapsed_time;
old_elapsed_time = elapsed_time;
if (diagnostic)
{
printf("elptime: %d dif time: %d, old_d_t: %d old_elp_t: %d\n", elapsed_time, difference_time, old_elapsed_time, old_elapsed_time);
}
if (difference_time > 15000)
{
printf("Reset run activated -- Current Difference Time: %d Stage %d \n", difference_time, bit_state);
reset_run();
return;
}
// counters must be pass through as the sections below decide returns from stages.
if (check_range(difference_time, 450, 650))
{
a_count += 1; // a_count is simply the count of any short bit high or low no matter what.
if (a_count >= packet_threshold)
{
for (int t = 0; t < cpos; t++)
{
printf("%d", d[t]);
}
printf(" Done!\n");
reset_run();
return;
}
// We do not return here where the stages need to check the bit width
}
if (bit_state == 3)
{
printf("Stage 3 Active: Current difference_time: %d\n", difference_time);
if (check_range(difference_time, 450, 650))
{
d[cpos] = 0;
cpos += 1;
printf(" Stage 3 --> dif %d Inside cpos: %d\n", difference_time, cpos);
return;
}
if (check_range(difference_time, 1550, 1780))
{
d[cpos] = 1;
cpos += 1;
printf(" Stage 3 --> dif %d Inside cpos: %d\n", difference_time, cpos);
return;
}
}
if (bit_state == 2)
{
printf("Stage 2 Difference time: %d Old Difference Time: %d \n", difference_time, old_difference_time);
if (check_range(difference_time, 450, 650))
if (check_range(old_difference_time, 1550, 1800))
{
b_count += 1;
printf(" Stage 2 --> Inside Check Range b_count: %d\n",b_count);
if (b_count >= 8)
{
printf( " Stage 2 --> Activating to Stage 3\n");
bit_state = 3;
return;
}
}
return;
}
if (check_range(difference_time, 4200, 4600))
{
printf("Stage 2 Active: Current dif: %d\n", difference_time);
bit_state = 2;
return;
}
if (check_range(difference_time, 8800, 9200))
{
printf("Stage 1 Active: Current dif: %d\n", difference_time);
bit_state = 1;
return;
}
if (check_range(difference_time, 2000, 2350))
{
printf("Fail abort packet: %d\n", difference_time);
reset_run();
return;
}
printf("Missed process number: %d Stage: %d a_count %d b_count %d\n", difference_time,bit_state, a_count, b_count);
}
int main()
{
stdio_init_all();
printf("Startup!\n");
const uint LED_PIN = PICO_DEFAULT_LED_PIN;
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
gpio_init(0);
gpio_set_dir(0, GPIO_IN);
gpio_init(1);
gpio_set_dir(1, GPIO_IN);
gpio_set_irq_enabled_with_callback(0, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
//gpio_set_irq_enabled(1, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
//gpio_set_irq_enabled_with_callback(1, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
while (true)
{
sleep_ms(100);
//printf("Test push\n");
// printf("Test push\n");
}
}
This code will produce prodigious logging output as in:
Stage 3 --> dif 571 Inside cpos: 24
Stage 3 Active: Current difference_time: 1657
Stage 3 --> dif 1657 Inside cpos: 25
Stage 3 Active: Current difference_time: 571
Stage 3 --> dif 571 Inside cpos: 26
Stage 3 Active: Current difference_time: 1662
Stage 3 --> dif 1662 Inside cpos: 27
Stage 3 Active: Current difference_time: 541
Stage 3 --> dif 541 Inside cpos: 28
Stage 3 Active: Current difference_time: 1689
Stage 3 --> dif 1689 Inside cpos: 29
10000010000000000010100010101 Done!
Missed process number: 1685 Stage: 0 a_count 0 b_count 0
Missed process number: 545 Stage: 0 a_count 1 b_count 0
Reset run activated -- Current Difference Time: 39830 Stage 0
Stage 1 Active: Current dif: 8955
Fail abort packet: 2263
Missed process number: 594 Stage: 0 a_count 1 b_count 0
Reset run activated -- Current Difference Time: 2547459 Stage 0
...
This simple toolbox of block code can be quickly built upon - one could decode other remotes easily by simply adapting some of the logic to handle the different pulse widths.