diff --git a/firmware/libs/ir/recv/src/ir_recv.c b/firmware/libs/ir/recv/src/ir_recv.c index c7ce882..0bdd454 100644 --- a/firmware/libs/ir/recv/src/ir_recv.c +++ b/firmware/libs/ir/recv/src/ir_recv.c @@ -95,9 +95,8 @@ typedef enum { IR_STATE_IDLE, IR_STATE_HEADER_SYNC, - IR_STATE_WAIT_HEADER_GAP, - IR_STATE_WAIT_MARK, - IR_STATE_WAIT_SPACE, + IR_STATE_FIND_MARK, + IR_STATE_SYNC_MARK, IR_STATE_VALIDATE } ir_state_t; @@ -108,6 +107,9 @@ typedef struct uint32_t bit_acc; uint16_t timer; uint8_t bit_count; + uint8_t max_energy; + uint16_t timer_at_max; + uint8_t sync_window; } ir_ctx_t; static ir_ctx_t channels[3]; @@ -116,15 +118,21 @@ 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; + } + /* 32-Bit Shift-Register aktualisieren */ ctx->sample_window = (ctx->sample_window << 1) | (active ? 1 : 0); - uint8_t energy = __builtin_popcount(ctx->sample_window); + + /* Energie über 32 Samples (Header) und 8 Samples (Bits) berechnen */ + uint8_t energy_32 = __builtin_popcount(ctx->sample_window); + uint8_t energy_8 = __builtin_popcount(ctx->sample_window & 0xFF); switch (ctx->state) { case IR_STATE_IDLE: - if (energy >= 24) + if (energy_32 >= 24) { ctx->state = IR_STATE_HEADER_SYNC; ctx->timer = 0; @@ -132,35 +140,56 @@ static void process_ir_sample(ir_ctx_t *ctx, int16_t raw) 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) + ctx->timer++; + if (energy_8 <= 2) { - // Wir sind jetzt im Gap nach dem Header. - // Wir wechseln in einen Modus, der auf den Start des ersten Bits (Mark) wartet. - ctx->state = IR_STATE_WAIT_MARK; + ctx->state = IR_STATE_FIND_MARK; + ctx->timer = 0; ctx->bit_count = 0; ctx->bit_acc = 0; - ctx->timer = 0; + } + else if (ctx->timer > 50) + { + ctx->state = IR_STATE_IDLE; /* Timeout */ } break; - case IR_STATE_WAIT_MARK: - if (active) + case IR_STATE_FIND_MARK: + ctx->timer++; + + if (energy_8 >= 4) { - // Steigende Flanke: Das Space (die Pause) ist vorbei. - // Jetzt bewerten wir die Länge der Pause (Timer). - if (ctx->timer >= 4) // Mindestlänge für Rauschunterdrückung + ctx->state = IR_STATE_SYNC_MARK; + ctx->max_energy = energy_8; + ctx->timer_at_max = ctx->timer; + ctx->sync_window = 0; + } + else if (ctx->timer > 40) + { + ctx->state = IR_STATE_IDLE; + } + break; + + case IR_STATE_SYNC_MARK: + ctx->timer++; + ctx->sync_window++; + + if (energy_8 > ctx->max_energy) + { + ctx->max_energy = energy_8; + ctx->timer_at_max = ctx->timer; + } + + if (ctx->sync_window >= 10) + { + if (ctx->max_energy >= 6) { - bool bit = (ctx->timer >= 12); // Schwelle zwischen 8 und 16 Samples - - /* Rechtsschub: Das erste empfangene Bit landet nach 24 Schüben an Bit 0 */ + bool bit = (ctx->timer_at_max >= 20); + ctx->bit_acc = (ctx->bit_acc >> 1) | (bit ? (1 << 23) : 0); - - LOG_DBG("Bit %u: %d (T:%u)", ctx->bit_count, bit, ctx->timer); + + LOG_DBG("Bit %u: %d (T_Max:%u, E_Max:%u)", + ctx->bit_count, bit, ctx->timer_at_max, ctx->max_energy); if (++ctx->bit_count >= 24) { @@ -168,33 +197,16 @@ case IR_STATE_WAIT_HEADER_GAP: } else { - ctx->state = IR_STATE_WAIT_SPACE; + ctx->state = IR_STATE_FIND_MARK; + + + ctx->timer = ctx->timer - ctx->timer_at_max; } } - else if (ctx->bit_count == 0 && ctx->timer == 0) - { - // Sonderfall: Erster Puls nach dem Header-Gap. s - // Wir fangen gerade erst an zu zählen. Nichts tun. - } else { - // Zu kurz -> Rauschen ctx->state = IR_STATE_IDLE; } - ctx->timer = 0; - } - else - { - ctx->timer++; // Wir zählen die Samples der Pause - } - 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; @@ -207,8 +219,10 @@ case IR_STATE_WAIT_HEADER_GAP: 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); + LOG_INF("VALID: Type %u, ID %u, Val %u", + p.data.fields.type, + p.data.fields.heal.healer_id, + p.data.fields.heal.amount); } else { @@ -219,7 +233,6 @@ case IR_STATE_WAIT_HEADER_GAP: break; } } - /** * @brief Main processing thread for incoming ADC buffers. */