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:
@@ -8,6 +8,7 @@ menuconfig IR_RECV
|
||||
if IR_RECV
|
||||
config IR_RECV_SIMULATOR
|
||||
bool "Enable IR receiver simulator"
|
||||
select ENTROPY_GENERATOR
|
||||
help
|
||||
Replaces real ADC/Hardware input with a software-based sample generator
|
||||
for protocol testing.
|
||||
|
||||
@@ -12,8 +12,18 @@
|
||||
int ir_recv_init(void);
|
||||
|
||||
#ifdef CONFIG_IR_RECV_SIMULATOR
|
||||
/* Helper to trigger a simulation from main.c or shell */
|
||||
void ir_recv_sim_send_packet(ir_packet_t *packet);
|
||||
|
||||
/* Configuration for injecting signal errors */
|
||||
typedef struct {
|
||||
uint8_t noise_flips_per_8; /* Noise: number of inverted samples per block of 8 (0, 1, 2) */
|
||||
uint8_t jitter_mark; /* Jitter for mark pulse: +/- samples (e.g. 2) */
|
||||
uint8_t jitter_space_0; /* Jitter for space0: +/- samples (e.g. 4) */
|
||||
uint8_t jitter_space_1; /* Jitter for space1: +/- samples (e.g. 2) */
|
||||
} ir_sim_error_t;
|
||||
|
||||
/* err can be NULL to send a perfect signal */
|
||||
void ir_recv_sim_send_packet(ir_packet_t *packet, ir_sim_error_t *err);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* IR_RECV_H */
|
||||
|
||||
@@ -23,71 +23,119 @@ static struct k_sem adc_sem;
|
||||
|
||||
/* --- Enhanced Simulator --- */
|
||||
#ifdef CONFIG_IR_RECV_SIMULATOR
|
||||
static ir_packet_t sim_packet;
|
||||
#include <zephyr/random/random.h>
|
||||
|
||||
#define SIM_MAX_SAMPLES 1000
|
||||
static bool sim_buffer[SIM_MAX_SAMPLES];
|
||||
static uint32_t sim_total_samples = 0;
|
||||
static bool sim_trigger = false;
|
||||
static uint32_t sim_sample_pos = 0;
|
||||
|
||||
void ir_recv_sim_send_packet(ir_packet_t *packet)
|
||||
/* Hilfsfunktion für den Jitter: Liefert einen Zufallswert zwischen -max und +max */
|
||||
static int get_jitter(uint8_t max_jitter)
|
||||
{
|
||||
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]);
|
||||
if (max_jitter == 0) return 0;
|
||||
return (int)(sys_rand32_get() % (max_jitter * 2 + 1)) - max_jitter;
|
||||
}
|
||||
|
||||
static bool get_sim_level(uint32_t pos)
|
||||
void ir_recv_sim_send_packet(ir_packet_t *packet, ir_sim_error_t *err)
|
||||
{
|
||||
if (pos < 32)
|
||||
return 1; // Header Mark
|
||||
if (pos < 40)
|
||||
return 0; // Header Gap
|
||||
/* Blockieren, bis vorheriges Paket abgearbeitet ist */
|
||||
while (sim_trigger) {
|
||||
k_msleep(5);
|
||||
}
|
||||
|
||||
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;
|
||||
ir_packet_t pkt;
|
||||
memcpy(&pkt, packet, sizeof(ir_packet_t));
|
||||
pkt.data.fields.crc = lastertag_crc8(pkt.data.bytes, 2);
|
||||
|
||||
if (p < bit_len)
|
||||
return (p >= space_len);
|
||||
p -= bit_len;
|
||||
}
|
||||
return 0;
|
||||
ir_sim_error_t default_err = {0};
|
||||
if (err == NULL) {
|
||||
err = &default_err;
|
||||
}
|
||||
|
||||
sim_total_samples = 0;
|
||||
|
||||
/* 1. Header Mark */
|
||||
int m_len = 32 + get_jitter(err->jitter_mark);
|
||||
for (int i = 0; i < m_len && sim_total_samples < SIM_MAX_SAMPLES; i++) {
|
||||
sim_buffer[sim_total_samples++] = 1;
|
||||
}
|
||||
|
||||
/* 2. Header Gap */
|
||||
int g_len = 8 + get_jitter(err->jitter_space_0);
|
||||
for (int i = 0; i < g_len && sim_total_samples < SIM_MAX_SAMPLES; i++) {
|
||||
sim_buffer[sim_total_samples++] = 0;
|
||||
}
|
||||
|
||||
/* 3. Payload Bits (24 Bit) */
|
||||
for (int i = 0; i < 24; i++) {
|
||||
bool bit = (pkt.data.bytes[i / 8] >> (i % 8)) & 1;
|
||||
|
||||
/* Space Phase */
|
||||
int s_base = bit ? 16 : 8;
|
||||
int s_jit = bit ? get_jitter(err->jitter_space_1) : get_jitter(err->jitter_space_0);
|
||||
int s_len = s_base + s_jit;
|
||||
for (int j = 0; j < s_len && sim_total_samples < SIM_MAX_SAMPLES; j++) {
|
||||
sim_buffer[sim_total_samples++] = 0;
|
||||
}
|
||||
|
||||
/* Mark Phase */
|
||||
int bm_len = 8 + get_jitter(err->jitter_mark);
|
||||
for (int j = 0; j < bm_len && sim_total_samples < SIM_MAX_SAMPLES; j++) {
|
||||
sim_buffer[sim_total_samples++] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 4. Rauschen injizieren (Bit Flips) */
|
||||
if (err->noise_flips_per_8 > 0) {
|
||||
for (uint32_t i = 0; i < sim_total_samples; i += 8) {
|
||||
for (int f = 0; f < err->noise_flips_per_8; f++) {
|
||||
uint32_t flip_idx = i + (sys_rand32_get() % 8);
|
||||
if (flip_idx < sim_total_samples) {
|
||||
sim_buffer[flip_idx] = !sim_buffer[flip_idx]; /* Bit kippen */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sim_sample_pos = 0;
|
||||
sim_trigger = true;
|
||||
|
||||
LOG_DBG("Simulator: Queued (Type: %u, CRC: 0x%02X), Total Samples: %u",
|
||||
pkt.data.fields.type, pkt.data.fields.crc, sim_total_samples);
|
||||
}
|
||||
|
||||
void ir_recv_sim_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
k_usleep(75 * SAMPLES_PER_BUFFER);
|
||||
if (!sim_trigger)
|
||||
continue;
|
||||
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);
|
||||
int16_t *buf = adc_buffers[write_idx];
|
||||
for (int i = 0; i < SAMPLES_PER_BUFFER; i++)
|
||||
{
|
||||
bool level = 0;
|
||||
if (sim_sample_pos < sim_total_samples) {
|
||||
level = sim_buffer[sim_sample_pos++];
|
||||
}
|
||||
|
||||
bool active = IS_ENABLED(CONFIG_IR_RECV_INVERT_SIGNAL) ? !level : level;
|
||||
buf[i * ADC_CHANNELS] = active ? 0x0FFF : 0x0000;
|
||||
buf[i * ADC_CHANNELS + 3] = 2400; // VBat Dummy
|
||||
}
|
||||
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.");
|
||||
}
|
||||
}
|
||||
/* Nach dem Puffer noch eine kurze Pause einhalten, um das Paket abzuschließen */
|
||||
if (sim_sample_pos >= sim_total_samples + 50)
|
||||
{
|
||||
sim_trigger = false;
|
||||
LOG_INF("Simulation sequence finished.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
K_THREAD_DEFINE(sim_tid, 1024, ir_recv_sim_thread, NULL, NULL, NULL, 5, 0, 0);
|
||||
#endif
|
||||
|
||||
@@ -136,6 +184,7 @@ static void process_ir_sample(ir_ctx_t *ctx, int16_t raw)
|
||||
{
|
||||
ctx->state = IR_STATE_HEADER_SYNC;
|
||||
ctx->timer = 0;
|
||||
LOG_DBG("Header detected. Energy: %u", energy_32);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -151,6 +200,7 @@ static void process_ir_sample(ir_ctx_t *ctx, int16_t raw)
|
||||
else if (ctx->timer > 50)
|
||||
{
|
||||
ctx->state = IR_STATE_IDLE; /* Timeout */
|
||||
LOG_DBG("Header sync timeout. Energy: %u", energy_8);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -218,12 +268,12 @@ static void process_ir_sample(ir_ctx_t *ctx, int16_t raw)
|
||||
p.data.bytes[2] = (ctx->bit_acc >> 16) & 0xFF;
|
||||
|
||||
if (lastertag_crc8(p.data.bytes, 2) == p.data.fields.crc)
|
||||
{
|
||||
LOG_INF("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.id,
|
||||
p.data.fields.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WRN("CRC Error! Acc: 0x%06X", ctx->bit_acc);
|
||||
|
||||
Reference in New Issue
Block a user