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:18:21 +01:00
parent ac477e290e
commit d51ff27e26

View File

@@ -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);