Files
esp32-aldl/main/decoder.c
T
gronod 98d35a82e1
Build and Package Firmware / build (push) Failing after 2m0s
feat: add decoder module, host unit tests, and GitHub Actions CI pipeline
2026-06-12 14:04:58 +01:00

116 lines
3.7 KiB
C

#include "decoder.h"
static enqueue_frame_cb_t s_enqueue_cb = NULL;
static print_frame_cb_t s_print_cb = NULL;
void decoder_init(enqueue_frame_cb_t enqueue_cb, print_frame_cb_t print_cb) {
s_enqueue_cb = enqueue_cb;
s_print_cb = print_cb;
}
uint8_t classify_pulse(uint32_t us) {
if (us < MIN_VALID_US) return PC_GLITCH;
if (us > MAX_VALID_US) return PC_IDLE_GAP;
if (us > MERGE_THRESHOLD_US) return PC_MERGED;
if (us < THRESHOLD_US) return PC_LOGIC_0;
return PC_LOGIC_1;
}
void reset_decoder(struct DecoderContext *ctx_ptr) {
ctx_ptr->state = DS_HUNT_SYNC;
ctx_ptr->sync_count = 0;
ctx_ptr->bit_count = 0;
ctx_ptr->byte_count = 0;
ctx_ptr->separator_count = 0;
ctx_ptr->frame_errors = 0;
ctx_ptr->bytes_this_frame = 0;
}
static void feed_bit(struct DecoderContext *ctx_ptr, uint8_t pc) {
switch (ctx_ptr->state) {
case DS_HUNT_SYNC:
if (pc == PC_LOGIC_1) {
ctx_ptr->sync_count++;
if (ctx_ptr->sync_count >= SYNC_ONES_NEEDED) {
ctx_ptr->sync_count = 0;
ctx_ptr->byte_count = 0;
ctx_ptr->bit_count = 0;
ctx_ptr->separator_count = 0;
ctx_ptr->frame_errors = 0;
ctx_ptr->bytes_this_frame = 0;
ctx_ptr->state = DS_AWAIT_START;
}
} else {
ctx_ptr->sync_count = 0;
}
break;
case DS_AWAIT_START:
if (pc == PC_LOGIC_0) {
ctx_ptr->current_byte = 0;
ctx_ptr->bit_count = 0;
ctx_ptr->separator_count = 0;
ctx_ptr->state = DS_READ_BITS;
} else {
ctx_ptr->separator_count++;
if (ctx_ptr->separator_count > MAX_SEPARATORS) {
reset_decoder(ctx_ptr);
}
}
break;
case DS_READ_BITS: {
uint8_t bit_val = (pc == PC_LOGIC_1) ? 1u : 0u;
ctx_ptr->current_byte = (uint8_t)((ctx_ptr->current_byte << 1) | bit_val);
ctx_ptr->bit_count++;
if (ctx_ptr->bit_count == 8) {
ctx_ptr->frame[ctx_ptr->byte_count] = ctx_ptr->current_byte;
ctx_ptr->bytes_this_frame++;
ctx_ptr->bit_count = 0;
ctx_ptr->byte_count++;
if (ctx_ptr->byte_count >= PAYLOAD_BYTES) {
ctx_ptr->frames_decoded++;
if (s_print_cb) {
s_print_cb(ctx_ptr->frames_decoded, ctx_ptr->frame);
}
if (s_enqueue_cb) {
s_enqueue_cb(ctx_ptr->frame, PAYLOAD_BYTES);
}
reset_decoder(ctx_ptr);
} else {
ctx_ptr->separator_count = 0;
ctx_ptr->state = DS_AWAIT_START;
}
}
break;
}
default:
reset_decoder(ctx_ptr);
break;
}
}
void process_pulse(struct DecoderContext *ctx_ptr, uint32_t pulse_us) {
uint8_t pc = classify_pulse(pulse_us);
if (pc == PC_GLITCH) return;
if (pc == PC_IDLE_GAP) {
reset_decoder(ctx_ptr);
return;
}
if (pc == PC_MERGED) {
uint32_t hidden_est = pulse_us - LOGIC1_PULSE_US;
uint8_t hidden_bit = (hidden_est >= THRESHOLD_US) ? PC_LOGIC_1 : PC_LOGIC_0;
feed_bit(ctx_ptr, hidden_bit);
feed_bit(ctx_ptr, PC_LOGIC_1);
return;
}
feed_bit(ctx_ptr, pc);
}