sync during ir_recv dev
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 12s

This commit is contained in:
2026-02-16 14:34:02 +01:00
parent a1b047f4bb
commit 0113edb816

View File

@@ -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.
*/