add reliable BLE telemetry transport
This commit is contained in:
+93
-19
@@ -15,7 +15,11 @@
|
||||
#include "l3g4200d.h"
|
||||
#include "trikke_protocol.h"
|
||||
#include "trikke_transport.h"
|
||||
#if CONFIG_TRIKKE_TRANSPORT_BLE
|
||||
#include "trikke_ble_transport.h"
|
||||
#else
|
||||
#include "trikke_usb_transport.h"
|
||||
#endif
|
||||
|
||||
// Seeed Studio XIAO ESP32-C3: D4/SDA = GPIO6, D5/SCL = GPIO7.
|
||||
#define TRIKKE_I2C_PORT I2C_NUM_0
|
||||
@@ -26,6 +30,7 @@
|
||||
#define TRIKKE_SAMPLE_TICKS pdMS_TO_TICKS(1000 / TRIKKE_SAMPLE_RATE_HZ)
|
||||
#define TRIKKE_SAMPLE_QUEUE_DEPTH 512
|
||||
#define TRIKKE_METADATA_INTERVAL_PACKETS 64
|
||||
#define TRIKKE_STATUS_INTERVAL_PACKETS 64
|
||||
#define TRIKKE_TRANSPORT_RETRY_DELAY_MS 10
|
||||
|
||||
// Software calibration from the 2026-08-17 enclosure six-face capture.
|
||||
@@ -54,10 +59,15 @@ typedef struct {
|
||||
adxl345_t accelerometer;
|
||||
l3g4200d_t gyroscope;
|
||||
QueueHandle_t sample_queue;
|
||||
atomic_uint_least32_t dropped_sample_count;
|
||||
atomic_uint_least32_t sensor_read_failure_count;
|
||||
atomic_uint_least32_t queue_overflow_count;
|
||||
atomic_uint_least32_t loop_overrun_count;
|
||||
trikke_transport_t transport;
|
||||
#if CONFIG_TRIKKE_TRANSPORT_BLE
|
||||
trikke_ble_transport_t ble_transport;
|
||||
#else
|
||||
trikke_usb_transport_t usb_transport;
|
||||
#endif
|
||||
} trikke_context_t;
|
||||
|
||||
static trikke_context_t s_context;
|
||||
@@ -109,6 +119,34 @@ static trikke_axes_sample_t map_gyro_to_enclosure(const l3g4200d_sample_t *nativ
|
||||
};
|
||||
}
|
||||
|
||||
static uint32_t dropped_sample_count(const trikke_context_t *context)
|
||||
{
|
||||
return atomic_load(&context->sensor_read_failure_count) +
|
||||
atomic_load(&context->queue_overflow_count);
|
||||
}
|
||||
|
||||
static trikke_wire_status_t status_snapshot(
|
||||
trikke_context_t *context,
|
||||
const trikke_transport_sender_t *sender)
|
||||
{
|
||||
trikke_wire_status_t status = {
|
||||
.sensor_read_failure_count =
|
||||
atomic_load(&context->sensor_read_failure_count),
|
||||
.queue_overflow_count = atomic_load(&context->queue_overflow_count),
|
||||
.transport_begin_retry_count = sender->begin_retry_count,
|
||||
};
|
||||
#if CONFIG_TRIKKE_TRANSPORT_BLE
|
||||
trikke_ble_transport_counters_t ble_counters = {0};
|
||||
trikke_ble_transport_get_counters(
|
||||
&context->ble_transport, &ble_counters);
|
||||
status.transport_disconnect_count = ble_counters.disconnect_count;
|
||||
status.transport_send_failure_count = ble_counters.send_failure_count;
|
||||
status.transport_replay_count = ble_counters.replay_count;
|
||||
status.transport_invalid_ack_count = ble_counters.invalid_ack_count;
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
static void acquisition_task(void *argument)
|
||||
{
|
||||
trikke_context_t *context = argument;
|
||||
@@ -146,10 +184,10 @@ static void acquisition_task(void *argument)
|
||||
.gyro_status = gyro_status,
|
||||
};
|
||||
if (xQueueSend(context->sample_queue, &sample, 0) != pdPASS) {
|
||||
atomic_fetch_add(&context->dropped_sample_count, 1);
|
||||
atomic_fetch_add(&context->queue_overflow_count, 1);
|
||||
}
|
||||
} else {
|
||||
atomic_fetch_add(&context->dropped_sample_count, 1);
|
||||
atomic_fetch_add(&context->sensor_read_failure_count, 1);
|
||||
}
|
||||
|
||||
++sequence;
|
||||
@@ -207,10 +245,17 @@ static void output_task(void *argument)
|
||||
|
||||
size_t packet_size = trikke_encode_metadata_packet(
|
||||
packet, sizeof(packet), packet_sequence++, esp_timer_get_time(),
|
||||
atomic_load(&context->dropped_sample_count),
|
||||
dropped_sample_count(context),
|
||||
atomic_load(&context->loop_overrun_count), &TRIKKE_METADATA);
|
||||
write_binary_packet_until_sent(context, &sender, packet, packet_size);
|
||||
|
||||
trikke_wire_status_t status = status_snapshot(context, &sender);
|
||||
packet_size = trikke_encode_status_packet(
|
||||
packet, sizeof(packet), packet_sequence++, esp_timer_get_time(),
|
||||
dropped_sample_count(context),
|
||||
atomic_load(&context->loop_overrun_count), &status);
|
||||
write_binary_packet_until_sent(context, &sender, packet, packet_size);
|
||||
|
||||
while (true) {
|
||||
trikke_wire_sample_t samples[TRIKKE_WIRE_MAX_RECORDS] = {0};
|
||||
size_t sample_count = 0;
|
||||
@@ -244,15 +289,26 @@ static void output_task(void *argument)
|
||||
sample_packet_count % TRIKKE_METADATA_INTERVAL_PACKETS == 0) {
|
||||
packet_size = trikke_encode_metadata_packet(
|
||||
packet, sizeof(packet), packet_sequence++, esp_timer_get_time(),
|
||||
atomic_load(&context->dropped_sample_count),
|
||||
dropped_sample_count(context),
|
||||
atomic_load(&context->loop_overrun_count), &TRIKKE_METADATA);
|
||||
write_binary_packet_until_sent(
|
||||
context, &sender, packet, packet_size);
|
||||
}
|
||||
|
||||
if (sample_packet_count > 0 &&
|
||||
sample_packet_count % TRIKKE_STATUS_INTERVAL_PACKETS == 0) {
|
||||
status = status_snapshot(context, &sender);
|
||||
packet_size = trikke_encode_status_packet(
|
||||
packet, sizeof(packet), packet_sequence++, esp_timer_get_time(),
|
||||
dropped_sample_count(context),
|
||||
atomic_load(&context->loop_overrun_count), &status);
|
||||
write_binary_packet_until_sent(
|
||||
context, &sender, packet, packet_size);
|
||||
}
|
||||
|
||||
packet_size = trikke_encode_sample_packet(
|
||||
packet, sizeof(packet), packet_sequence++,
|
||||
atomic_load(&context->dropped_sample_count),
|
||||
dropped_sample_count(context),
|
||||
atomic_load(&context->loop_overrun_count), samples, sample_count);
|
||||
write_binary_packet_until_sent(context, &sender, packet, packet_size);
|
||||
++sample_packet_count;
|
||||
@@ -338,27 +394,22 @@ void app_main(void)
|
||||
"records_per_packet=%d\n",
|
||||
TRIKKE_WIRE_VERSION, TRIKKE_WIRE_SAMPLE_RECORD_SIZE,
|
||||
TRIKKE_WIRE_MAX_RECORDS);
|
||||
#if CONFIG_TRIKKE_TRANSPORT_BLE
|
||||
printf("# transport=ble,device_name=TrikkeSensor\n");
|
||||
#else
|
||||
printf("# transport=usb_serial_jtag\n");
|
||||
#endif
|
||||
fflush(stdout);
|
||||
|
||||
#if !CONFIG_TRIKKE_TRANSPORT_BLE
|
||||
// The console defaults to CRLF conversion, which would insert bytes into
|
||||
// binary frames whenever a payload byte equals LF.
|
||||
usb_serial_jtag_vfs_set_tx_line_endings(ESP_LINE_ENDINGS_LF);
|
||||
|
||||
err = trikke_usb_transport_init(
|
||||
&s_context.usb_transport, &s_context.transport);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "USB transport initialization failed: %s",
|
||||
esp_err_to_name(err));
|
||||
l3g4200d_deinit(&s_context.gyroscope);
|
||||
adxl345_deinit(&s_context.accelerometer);
|
||||
i2c_del_master_bus(bus);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
s_context.sample_queue =
|
||||
xQueueCreate(TRIKKE_SAMPLE_QUEUE_DEPTH, sizeof(trikke_wire_sample_t));
|
||||
if (s_context.sample_queue == NULL) {
|
||||
trikke_usb_transport_deinit(&s_context.usb_transport);
|
||||
ESP_LOGE(TAG, "sample queue allocation failed");
|
||||
l3g4200d_deinit(&s_context.gyroscope);
|
||||
adxl345_deinit(&s_context.accelerometer);
|
||||
@@ -379,7 +430,6 @@ void app_main(void)
|
||||
vTaskDelete(acquisition_task_handle);
|
||||
}
|
||||
vQueueDelete(s_context.sample_queue);
|
||||
trikke_usb_transport_deinit(&s_context.usb_transport);
|
||||
ESP_LOGE(TAG, "telemetry task creation failed");
|
||||
l3g4200d_deinit(&s_context.gyroscope);
|
||||
adxl345_deinit(&s_context.accelerometer);
|
||||
@@ -387,6 +437,30 @@ void app_main(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#if CONFIG_TRIKKE_TRANSPORT_BLE
|
||||
err = trikke_ble_transport_init(
|
||||
&s_context.ble_transport, &s_context.transport);
|
||||
#else
|
||||
err = trikke_usb_transport_init(
|
||||
&s_context.usb_transport, &s_context.transport);
|
||||
#endif
|
||||
if (err != ESP_OK) {
|
||||
vTaskDelete(output_task_handle);
|
||||
vTaskDelete(acquisition_task_handle);
|
||||
vQueueDelete(s_context.sample_queue);
|
||||
#if CONFIG_TRIKKE_TRANSPORT_BLE
|
||||
ESP_LOGE(TAG, "BLE transport initialization failed: %s",
|
||||
esp_err_to_name(err));
|
||||
#else
|
||||
ESP_LOGE(TAG, "USB transport initialization failed: %s",
|
||||
esp_err_to_name(err));
|
||||
#endif
|
||||
l3g4200d_deinit(&s_context.gyroscope);
|
||||
adxl345_deinit(&s_context.accelerometer);
|
||||
i2c_del_master_bus(bus);
|
||||
return;
|
||||
}
|
||||
|
||||
// No text may share the byte stream once framed binary output begins.
|
||||
esp_log_level_set("*", ESP_LOG_NONE);
|
||||
xTaskNotifyGive(output_task_handle);
|
||||
|
||||
Reference in New Issue
Block a user