a846b063f9
cel_crsf_frame_parse() parses ELRS USB format frames: [addr][length][type][payload...][crc] cel_crsf_stream_* provides incremental parsing from a byte stream: skips invalid sync bytes, discards bad CRC frames, buffers partial frames across feed calls.
135 lines
4.1 KiB
C
135 lines
4.1 KiB
C
#include "unity.h"
|
|
#include "celrs/crsf.h"
|
|
#include <string.h>
|
|
|
|
void setUp(void) {}
|
|
void tearDown(void) {}
|
|
|
|
/* CRC tests — CRC8/DVB-S2 (poly 0xD5) */
|
|
void test_crc_empty(void) {
|
|
uint8_t data[1] = {0};
|
|
TEST_ASSERT_EQUAL_UINT8(0x00, cel_crsf_crc(data, 0));
|
|
}
|
|
|
|
void test_crc_single_byte(void) {
|
|
uint8_t data[1] = {0x01};
|
|
uint8_t crc = cel_crsf_crc(data, 1);
|
|
TEST_ASSERT_TRUE(crc != 0); /* non-trivial */
|
|
}
|
|
|
|
void test_crc_known_value(void) {
|
|
uint8_t data[6] = {0x10, 0x80, 0x03, 0x02, 0x80, 0x01};
|
|
uint8_t crc = cel_crsf_crc(data, 6);
|
|
TEST_ASSERT_TRUE(crc != 0);
|
|
uint8_t crc2 = cel_crsf_crc(data, 6);
|
|
TEST_ASSERT_EQUAL_UINT8(crc, crc2);
|
|
}
|
|
|
|
/* Channel helper tests */
|
|
void test_channel_clamp_min(void) {
|
|
TEST_ASSERT_EQUAL_INT16(CEL_CRSF_CH_MIN, cel_crsf_channel_clamp(0));
|
|
}
|
|
|
|
void test_channel_clamp_max(void) {
|
|
TEST_ASSERT_EQUAL_INT16(CEL_CRSF_CH_MAX, cel_crsf_channel_clamp(2048));
|
|
}
|
|
|
|
void test_channel_clamp_mid(void) {
|
|
TEST_ASSERT_EQUAL_INT16(CEL_CRSF_CH_MID, cel_crsf_channel_clamp(CEL_CRSF_CH_MID));
|
|
}
|
|
|
|
/* Frame parse tests — ELRS format: [addr][length][type][payload][crc] */
|
|
|
|
/* Build a valid test frame with known CRC */
|
|
static void build_test_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; /* type + payload + crc */
|
|
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;
|
|
}
|
|
|
|
void test_parse_valid_frame(void) {
|
|
uint8_t buf[32];
|
|
uint8_t payload[2] = {0x80, 0x01};
|
|
build_test_frame(buf, 0xC8, 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_UINT8(0xC8, frame.addr);
|
|
TEST_ASSERT_EQUAL_UINT8(CEL_CRSF_TYPE_HEARTBEAT, frame.type);
|
|
TEST_ASSERT_EQUAL_UINT8(2, frame.payload_len);
|
|
TEST_ASSERT_EQUAL_UINT8(0x80, frame.payload[0]);
|
|
TEST_ASSERT_EQUAL_UINT8(0x01, frame.payload[1]);
|
|
}
|
|
|
|
void test_parse_null_frame(void) {
|
|
uint8_t buf[8];
|
|
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_frame_parse(NULL, buf, 8));
|
|
}
|
|
|
|
void test_parse_null_buf(void) {
|
|
cel_crsf_frame frame;
|
|
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_frame_parse(&frame, NULL, 8));
|
|
}
|
|
|
|
void test_parse_too_short(void) {
|
|
cel_crsf_frame frame;
|
|
uint8_t buf[2] = {0xC8, 0x03};
|
|
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_frame_parse(&frame, buf, 2));
|
|
}
|
|
|
|
void test_parse_bad_crc(void) {
|
|
uint8_t buf[32];
|
|
uint8_t payload[2] = {0x80, 0x01};
|
|
build_test_frame(buf, 0xC8, CEL_CRSF_TYPE_HEARTBEAT, payload, 2);
|
|
buf[5] ^= 0xFF; /* corrupt the CRC */
|
|
|
|
cel_crsf_frame frame;
|
|
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
|
}
|
|
|
|
void test_parse_empty_payload(void) {
|
|
uint8_t buf[32];
|
|
build_test_frame(buf, 0xEE, CEL_CRSF_TYPE_HEARTBEAT, NULL, 0);
|
|
|
|
cel_crsf_frame frame;
|
|
TEST_ASSERT_EQUAL_INT(0, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
|
TEST_ASSERT_EQUAL_UINT8(0xEE, frame.addr);
|
|
TEST_ASSERT_EQUAL_UINT8(CEL_CRSF_TYPE_HEARTBEAT, frame.type);
|
|
TEST_ASSERT_EQUAL_UINT8(0, frame.payload_len);
|
|
}
|
|
|
|
void test_parse_module_addr(void) {
|
|
uint8_t buf[32];
|
|
uint8_t payload[4] = {0xAA, 0xBB, 0xCC, 0xDD};
|
|
build_test_frame(buf, 0xEE, CEL_CRSF_TYPE_GPS, payload, 4);
|
|
|
|
cel_crsf_frame frame;
|
|
TEST_ASSERT_EQUAL_INT(0, cel_crsf_frame_parse(&frame, buf, sizeof(buf)));
|
|
TEST_ASSERT_EQUAL_UINT8(0xEE, frame.addr);
|
|
TEST_ASSERT_EQUAL_UINT8(CEL_CRSF_TYPE_GPS, frame.type);
|
|
TEST_ASSERT_EQUAL_UINT8(4, frame.payload_len);
|
|
}
|
|
|
|
int main(void) {
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_crc_empty);
|
|
RUN_TEST(test_crc_single_byte);
|
|
RUN_TEST(test_crc_known_value);
|
|
RUN_TEST(test_channel_clamp_min);
|
|
RUN_TEST(test_channel_clamp_max);
|
|
RUN_TEST(test_channel_clamp_mid);
|
|
RUN_TEST(test_parse_valid_frame);
|
|
RUN_TEST(test_parse_null_frame);
|
|
RUN_TEST(test_parse_null_buf);
|
|
RUN_TEST(test_parse_too_short);
|
|
RUN_TEST(test_parse_bad_crc);
|
|
RUN_TEST(test_parse_empty_payload);
|
|
RUN_TEST(test_parse_module_addr);
|
|
return UNITY_END();
|
|
}
|