feat: implement telemetry parser
cel_crsf_telemetry_parse() decodes link stats, battery, heartbeat, and airspeed frames. Updated cel_telem_battery and cel_telem_airspeed structs to use uint16_t values matching CRSF protocol format.
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
#include "unity.h"
|
||||
#include "celrs/crsf.h"
|
||||
#include <string.h>
|
||||
|
||||
void setUp(void) {}
|
||||
void tearDown(void) {}
|
||||
|
||||
/* Helper: build a valid test frame with known CRC */
|
||||
static size_t build_frame(uint8_t* dst, uint8_t addr, uint8_t type,
|
||||
uint8_t const* payload, uint8_t payload_len) {
|
||||
uint8_t length = 1 + payload_len + 1;
|
||||
dst[0] = addr;
|
||||
dst[1] = length;
|
||||
dst[2] = type;
|
||||
memcpy(dst + 3, payload, payload_len);
|
||||
uint8_t crc = cel_crsf_crc(dst + 2, 1 + payload_len);
|
||||
dst[2 + length - 1] = crc;
|
||||
return 2 + length;
|
||||
}
|
||||
|
||||
/* Telemetry parse tests */
|
||||
|
||||
void test_parse_link_stats(void) {
|
||||
uint8_t buf[32];
|
||||
uint8_t payload[10] = {
|
||||
80, 70, 95, 0x7F, /* rssi1, rssi2, uplink_qual, snr(-127..127) */
|
||||
0, 5, 20, 60, 90, 0x60 /* antenna, rf_mode, power, down_rssi, down_qual, snr */
|
||||
};
|
||||
build_frame(buf, 0x08, CEL_CRSF_TYPE_LINK_STATS, payload, 10);
|
||||
|
||||
cel_crsf_frame frame;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
||||
|
||||
cel_telemetry telem;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_telemetry_parse(&frame, &telem));
|
||||
TEST_ASSERT_EQUAL_UINT(CEL_TELEM_LINK, telem.type);
|
||||
TEST_ASSERT_EQUAL_UINT8(80, telem.data.link.uplink_rssi1);
|
||||
TEST_ASSERT_EQUAL_UINT8(70, telem.data.link.uplink_rssi2);
|
||||
TEST_ASSERT_EQUAL_UINT8(95, telem.data.link.uplink_quality);
|
||||
TEST_ASSERT_EQUAL_INT8(0x7F, telem.data.link.uplink_snr);
|
||||
TEST_ASSERT_EQUAL_UINT8(0, telem.data.link.active_antenna);
|
||||
TEST_ASSERT_EQUAL_UINT8(5, telem.data.link.rf_mode);
|
||||
TEST_ASSERT_EQUAL_UINT8(20, telem.data.link.uplink_power);
|
||||
TEST_ASSERT_EQUAL_UINT8(60, telem.data.link.downlink_rssi);
|
||||
TEST_ASSERT_EQUAL_UINT8(90, telem.data.link.downlink_qual);
|
||||
TEST_ASSERT_EQUAL_INT8(0x60, telem.data.link.downlink_snr);
|
||||
}
|
||||
|
||||
void test_parse_link_stats_short(void) {
|
||||
uint8_t buf[32];
|
||||
uint8_t payload[5] = {80, 70, 95, 0x7F, 0};
|
||||
build_frame(buf, 0x08, CEL_CRSF_TYPE_LINK_STATS, payload, 5);
|
||||
|
||||
cel_crsf_frame frame;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
||||
|
||||
cel_telemetry telem;
|
||||
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_telemetry_parse(&frame, &telem));
|
||||
}
|
||||
|
||||
void test_parse_battery(void) {
|
||||
uint8_t buf[32];
|
||||
uint8_t payload[7] = {
|
||||
0x40, 0x03, /* voltage: 0x0340 = 832 -> 0.832V */
|
||||
0x00, 0x00, /* current: 0 */
|
||||
0x00, 0x00, /* capacity: 0 */
|
||||
0x64 /* remaining: 100% */
|
||||
};
|
||||
build_frame(buf, 0x08, CEL_CRSF_TYPE_BATTERY, payload, 7);
|
||||
|
||||
cel_crsf_frame frame;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
||||
|
||||
cel_telemetry telem;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_telemetry_parse(&frame, &telem));
|
||||
TEST_ASSERT_EQUAL_UINT(CEL_TELEM_BATTERY, telem.type);
|
||||
TEST_ASSERT_EQUAL_UINT16(0x0340, telem.data.battery.voltage_mv);
|
||||
TEST_ASSERT_EQUAL_UINT8(0x64, telem.data.battery.remaining_pct);
|
||||
}
|
||||
|
||||
void test_parse_heartbeat(void) {
|
||||
uint8_t buf[32];
|
||||
uint8_t payload[2] = {0x10, 0x80}; /* origin_addr = 0x8010 */
|
||||
build_frame(buf, 0x10, CEL_CRSF_TYPE_HEARTBEAT, payload, 2);
|
||||
|
||||
cel_crsf_frame frame;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
||||
|
||||
cel_telemetry telem;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_telemetry_parse(&frame, &telem));
|
||||
TEST_ASSERT_EQUAL_UINT(CEL_TELEM_HEARTBEAT, telem.type);
|
||||
TEST_ASSERT_EQUAL_UINT16(0x8010, telem.data.heartbeat.origin_addr);
|
||||
}
|
||||
|
||||
void test_parse_airspeed(void) {
|
||||
uint8_t buf[32];
|
||||
uint8_t payload[2] = {0x00, 0x01}; /* speed = 0x0100 = 256 km/h */
|
||||
build_frame(buf, 0x08, CEL_CRSF_TYPE_AIRSPEED, payload, 2);
|
||||
|
||||
cel_crsf_frame frame;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
||||
|
||||
cel_telemetry telem;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_telemetry_parse(&frame, &telem));
|
||||
TEST_ASSERT_EQUAL_UINT(CEL_TELEM_AIRSPEED, telem.type);
|
||||
TEST_ASSERT_EQUAL_UINT16(256, telem.data.airspeed.speed_kmh);
|
||||
}
|
||||
|
||||
void test_parse_unknown_type(void) {
|
||||
uint8_t buf[32];
|
||||
uint8_t payload[2] = {0x00, 0x01};
|
||||
build_frame(buf, 0x08, 0xFF, payload, 2);
|
||||
|
||||
cel_crsf_frame frame;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
||||
|
||||
cel_telemetry telem;
|
||||
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_telemetry_parse(&frame, &telem));
|
||||
}
|
||||
|
||||
void test_parse_null_args(void) {
|
||||
cel_telemetry telem;
|
||||
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_telemetry_parse(NULL, &telem));
|
||||
}
|
||||
|
||||
void test_parse_null_out(void) {
|
||||
uint8_t buf[32];
|
||||
uint8_t payload[2] = {0x10, 0x80};
|
||||
build_frame(buf, 0x10, CEL_CRSF_TYPE_HEARTBEAT, payload, 2);
|
||||
|
||||
cel_crsf_frame frame;
|
||||
TEST_ASSERT_EQUAL_INT(0, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
||||
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_telemetry_parse(&frame, NULL));
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_parse_link_stats);
|
||||
RUN_TEST(test_parse_link_stats_short);
|
||||
RUN_TEST(test_parse_battery);
|
||||
RUN_TEST(test_parse_heartbeat);
|
||||
RUN_TEST(test_parse_airspeed);
|
||||
RUN_TEST(test_parse_unknown_type);
|
||||
RUN_TEST(test_parse_null_args);
|
||||
RUN_TEST(test_parse_null_out);
|
||||
return UNITY_END();
|
||||
}
|
||||
Reference in New Issue
Block a user