sync during ir_recv dev
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 12s
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 12s
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user