diff --git a/firmware/libs/ir/recv/src/ir_recv.c b/firmware/libs/ir/recv/src/ir_recv.c index 5c54405..eed8762 100644 --- a/firmware/libs/ir/recv/src/ir_recv.c +++ b/firmware/libs/ir/recv/src/ir_recv.c @@ -27,138 +27,185 @@ static ir_packet_t sim_packet; static bool sim_trigger = false; static uint32_t sim_sample_pos = 0; -void ir_recv_sim_send_packet(ir_packet_t *packet) { - memcpy(&sim_packet, packet, sizeof(ir_packet_t)); - // Auto-calculate CRC for the simulator - sim_packet.data.fields.crc = lastertag_crc8(sim_packet.data.bytes, 2); - sim_sample_pos = 0; - sim_trigger = true; - LOG_DBG("Simulator: Packet queued (Type: %u, CRC: 0x%02X, Bytes: 0x%02%02X)", - sim_packet.data.fields.type, sim_packet.data.fields.crc, sim_packet.data.bytes[0], sim_packet.data.bytes[1]); +void ir_recv_sim_send_packet(ir_packet_t *packet) +{ + memcpy(&sim_packet, packet, sizeof(ir_packet_t)); + // Auto-calculate CRC for the simulator + sim_packet.data.fields.crc = lastertag_crc8(sim_packet.data.bytes, 2); + sim_sample_pos = 0; + sim_trigger = true; + LOG_DBG("Simulator: Packet queued (Type: %u, CRC: 0x%02X, Bytes: 0x%02X%02X)", + sim_packet.data.fields.type, sim_packet.data.fields.crc, sim_packet.data.bytes[0], sim_packet.data.bytes[1]); } -static bool get_sim_level(uint32_t pos) { - if (pos < 32) return 1; // Header Mark - if (pos < 40) return 0; // Header Gap - - uint32_t p = pos - 40; - for (int i = 0; i < 24; i++) { - // Extract bit from struct (LSB first to match our new right-shift receiver) - bool bit = (sim_packet.data.bytes[i/8] >> (i%8)) & 1; - uint32_t bit_len = bit ? 24 : 16; - uint32_t space_len = bit ? 16 : 8; - - if (p < bit_len) return (p >= space_len); - p -= bit_len; - } - return 0; +static bool get_sim_level(uint32_t pos) +{ + if (pos < 32) + return 1; // Header Mark + if (pos < 40) + return 0; // Header Gap + + uint32_t p = pos - 40; + for (int i = 0; i < 24; i++) + { + // Extract bit from struct (LSB first to match our new right-shift receiver) + bool bit = (sim_packet.data.bytes[i / 8] >> (i % 8)) & 1; + uint32_t bit_len = bit ? 24 : 16; + uint32_t space_len = bit ? 16 : 8; + + if (p < bit_len) + return (p >= space_len); + p -= bit_len; + } + return 0; } -void ir_recv_sim_thread(void *p1, void *p2, void *p3) { - while (1) { - k_usleep(75 * SAMPLES_PER_BUFFER); - if (!sim_trigger) continue; +void ir_recv_sim_thread(void *p1, void *p2, void *p3) +{ + while (1) + { + k_usleep(75 * SAMPLES_PER_BUFFER); + if (!sim_trigger) + continue; - int16_t *buf = adc_buffers[write_idx]; - for (int i = 0; i < SAMPLES_PER_BUFFER; i++) { - bool level = get_sim_level(sim_sample_pos++); - bool active = IS_ENABLED(CONFIG_IR_RECV_INVERT_SIGNAL) ? !level : level; - buf[i * ADC_CHANNELS] = active ? 0x0FFF : 0x0000; - // Clear other channels - buf[i * ADC_CHANNELS + 3] = 2400; - } - write_idx = (write_idx + 1) % BUFFER_COUNT; - k_sem_give(&adc_sem); - - if (sim_sample_pos > 600) { // Safety stop - sim_trigger = false; - LOG_INF("Simulation finished."); - } - } + int16_t *buf = adc_buffers[write_idx]; + for (int i = 0; i < SAMPLES_PER_BUFFER; i++) + { + bool level = get_sim_level(sim_sample_pos++); + bool active = IS_ENABLED(CONFIG_IR_RECV_INVERT_SIGNAL) ? !level : level; + buf[i * ADC_CHANNELS] = active ? 0x0FFF : 0x0000; + // Clear other channels + buf[i * ADC_CHANNELS + 3] = 2400; + } + write_idx = (write_idx + 1) % BUFFER_COUNT; + k_sem_give(&adc_sem); + + if (sim_sample_pos > 600) + { // Safety stop + sim_trigger = false; + LOG_INF("Simulation finished."); + } + } } K_THREAD_DEFINE(sim_tid, 1024, ir_recv_sim_thread, NULL, NULL, NULL, 5, 0, 0); #endif -typedef enum { - IR_STATE_IDLE, - IR_STATE_HEADER_SYNC, - IR_STATE_WAIT_HEADER_GAP, - IR_STATE_WAIT_MARK, - IR_STATE_WAIT_SPACE, - IR_STATE_VALIDATE +typedef enum +{ + IR_STATE_IDLE, + IR_STATE_HEADER_SYNC, + IR_STATE_WAIT_HEADER_GAP, + IR_STATE_WAIT_MARK, + IR_STATE_WAIT_SPACE, + IR_STATE_VALIDATE } ir_state_t; -typedef struct { - ir_state_t state; - uint32_t sample_window; - uint32_t bit_acc; - uint16_t timer; - uint8_t bit_count; +typedef struct +{ + ir_state_t state; + uint32_t sample_window; + uint32_t bit_acc; + uint16_t timer; + uint8_t bit_count; } ir_ctx_t; static ir_ctx_t channels[3]; -static void process_ir_sample(ir_ctx_t *ctx, int16_t raw) { - bool active = (raw > 2048); - if (IS_ENABLED(CONFIG_IR_RECV_INVERT_SIGNAL)) active = !active; +static void process_ir_sample(ir_ctx_t *ctx, int16_t raw) +{ + bool active = (raw > 2048); + if (IS_ENABLED(CONFIG_IR_RECV_INVERT_SIGNAL)) + active = !active; - ctx->sample_window = (ctx->sample_window << 1) | (active ? 1 : 0); - uint8_t energy = __builtin_popcount(ctx->sample_window); + ctx->sample_window = (ctx->sample_window << 1) | (active ? 1 : 0); + uint8_t energy = __builtin_popcount(ctx->sample_window); - switch (ctx->state) { - case IR_STATE_IDLE: - if (energy >= 24) { - ctx->state = IR_STATE_HEADER_SYNC; - ctx->timer = 0; - } - break; - case IR_STATE_HEADER_SYNC: - if (++ctx->timer >= 10) ctx->state = IR_STATE_WAIT_HEADER_GAP; - break; - case IR_STATE_WAIT_HEADER_GAP: - if (!active) { // Sync exactly on falling edge - ctx->state = IR_STATE_WAIT_MARK; - ctx->bit_count = 0; - ctx->bit_acc = 0; - ctx->timer = 0; - LOG_DBG("Header detectet, energy: %u", energy); - } - break; - case IR_STATE_WAIT_MARK: - if (active) { - // Gap measured! Timer had the space length. - if (ctx->timer >= 4) { - bool bit = (ctx->timer >= 12); - // Right-shift: First bit ends up at bit 0 - ctx->bit_acc = (ctx->bit_acc >> 1) | (bit ? (1 << 23) : 0); - LOG_DBG("Bit %u: %u (Timer: %u), Accumulator: 0x%06X", ctx->bit_count, bit, ctx->timer, ctx->bit_acc); - if (++ctx->bit_count >= 24) ctx->state = IR_STATE_VALIDATE; - else ctx->state = IR_STATE_WAIT_SPACE; - } else { ctx->state = IR_STATE_IDLE; } - ctx->timer = 0; - } else { ctx->timer++; } - break; - case IR_STATE_WAIT_SPACE: - if (!active) { ctx->state = IR_STATE_WAIT_MARK; ctx->timer = 0; } - break; - case IR_STATE_VALIDATE: - { - ir_packet_t p; - p.data.bytes[0] = ctx->bit_acc & 0xFF; - p.data.bytes[1] = (ctx->bit_acc >> 8) & 0xFF; - p.data.bytes[2] = (ctx->bit_acc >> 16) & 0xFF; - - if (lastertag_crc8(p.data.bytes, 2) == p.data.fields.crc) { - LOG_DBG("VALID: Type %u, ID %u, Val %u", - p.data.fields.type, p.data.fields.heal.healer_id, p.data.fields.heal.amount); - } else { - LOG_WRN("CRC Error! Acc: 0x%06X", ctx->bit_acc); - } - ctx->state = IR_STATE_IDLE; - } - break; - } + switch (ctx->state) + { + case IR_STATE_IDLE: + if (energy >= 24) + { + ctx->state = IR_STATE_HEADER_SYNC; + ctx->timer = 0; + } + break; + + case IR_STATE_HEADER_SYNC: + if (++ctx->timer >= 10) + ctx->state = IR_STATE_WAIT_HEADER_GAP; + break; + + case IR_STATE_WAIT_HEADER_GAP: + if (!active) + { + // Header-Puls ist vorbei, wir sind im Gap + ctx->state = IR_STATE_WAIT_MARK; + ctx->bit_count = 0; + ctx->bit_acc = 0; + ctx->timer = 0; + // LOG_DBG removed to save timing + } + break; + + case IR_STATE_WAIT_MARK: + if (active) + { + // Rising edge: Space is over. Measure it! + // threshold between 8 and 16 is ~12 + bool bit = (ctx->timer >= 12); + + /* Right-shift: The FIRST bit received becomes Bit 0 of the result + * after 24 shifts. */ + ctx->bit_acc = (ctx->bit_acc >> 1) | (bit ? (1 << 23) : 0); + + LOG_DBG("Bit %u: %u (T:%u)", ctx->bit_count, bit, ctx->timer); + + if (++ctx->bit_count >= 24) + { + ctx->state = IR_STATE_VALIDATE; + } + else + { + ctx->state = IR_STATE_WAIT_SPACE; + } + ctx->timer = 0; + } + else + { + ctx->timer++; // Counting space length + } + break; + + case IR_STATE_WAIT_SPACE: + if (!active) + { + // Falling edge: Mark is over, next Space starts + ctx->state = IR_STATE_WAIT_MARK; + ctx->timer = 0; + } + break; + + case IR_STATE_VALIDATE: + { + ir_packet_t p; + p.data.bytes[0] = ctx->bit_acc & 0xFF; + p.data.bytes[1] = (ctx->bit_acc >> 8) & 0xFF; + p.data.bytes[2] = (ctx->bit_acc >> 16) & 0xFF; + + if (lastertag_crc8(p.data.bytes, 2) == p.data.fields.crc) + { + LOG_DBG("VALID: Type %u, ID %u, Val %u", + p.data.fields.type, p.data.fields.heal.healer_id, p.data.fields.heal.amount); + } + else + { + LOG_WRN("CRC Error! Acc: 0x%06X", ctx->bit_acc); + } + ctx->state = IR_STATE_IDLE; + } + break; + } } /** @@ -166,22 +213,22 @@ static void process_ir_sample(ir_ctx_t *ctx, int16_t raw) { */ void ir_recv_thread(void *arg1, void *arg2, void *arg3) { - while (1) - { - k_sem_take(&adc_sem, K_FOREVER); - while (read_idx != write_idx) - { - int16_t *buf = adc_buffers[read_idx]; - for (int i = 0; i < SAMPLES_PER_BUFFER; i++) - { - /* Now this call matches the static function name above */ - process_ir_sample(&channels[0], buf[i * ADC_CHANNELS + 0]); - process_ir_sample(&channels[1], buf[i * ADC_CHANNELS + 1]); - process_ir_sample(&channels[2], buf[i * ADC_CHANNELS + 2]); - } - read_idx = (read_idx + 1) % BUFFER_COUNT; - } - } + while (1) + { + k_sem_take(&adc_sem, K_FOREVER); + while (read_idx != write_idx) + { + int16_t *buf = adc_buffers[read_idx]; + for (int i = 0; i < SAMPLES_PER_BUFFER; i++) + { + /* Now this call matches the static function name above */ + process_ir_sample(&channels[0], buf[i * ADC_CHANNELS + 0]); + process_ir_sample(&channels[1], buf[i * ADC_CHANNELS + 1]); + process_ir_sample(&channels[2], buf[i * ADC_CHANNELS + 2]); + } + read_idx = (read_idx + 1) % BUFFER_COUNT; + } + } } K_THREAD_DEFINE(ir_recv_tid, 2048, ir_recv_thread, NULL, NULL, NULL, 2, 0, 0);