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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user