Files
celrs/tests/test_crsf_param.c
T
portersky 5d18258330 feat: implement cel_crsf_param_parse
Parse PARAM_ENTRY payload into cel_crsf_param struct. Handles
TEXT_SELECT with options string and UINT8/INT8 with min/max/default/
value fields. Respects hidden flag (bit 7 of type byte). Truncates
name and options to buffer limits.
2026-06-14 21:50:12 +02:00

177 lines
6.3 KiB
C

#include "unity.h"
#include "celrs/crsf_param.h"
#include <string.h>
void setUp(void) {}
void tearDown(void) {}
/* cel_crsf_param_parse tests */
void test_param_parse_null_args(void) {
uint8_t payload[16] = {0};
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_param_parse(NULL, payload, sizeof(payload)));
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_param_parse(NULL, NULL, 0));
}
void test_param_parse_too_short(void) {
cel_crsf_param param;
uint8_t payload[5] = {0};
TEST_ASSERT_EQUAL_INT(-1, cel_crsf_param_parse(&param, payload, sizeof(payload)));
}
void test_param_parse_text_select(void) {
cel_crsf_param param;
/* dest=0x10, src=0xEE, index=5, chunks=0, parent=0, type=TEXT_SELECT */
/* name="TX Power", options="10 mW;25 mW;100 mW;500 mW;1000 mW", value=2, min=0, max=4, default=0 */
uint8_t payload[] = {
0x10, /* dest */
0xEE, /* src */
0x05, /* index */
0x00, /* chunks_remaining */
0x00, /* parent */
0x09, /* type = CEL_PARAM_TEXT_SELECT */
'T', 'X', ' ', 'P', 'o', 'w', 'e', 'r', '\0', /* name */
'1', '0', ' ', 'm', 'W', ';', /* options */
'2', '5', ' ', 'm', 'W', ';',
'1', '0', '0', ' ', 'm', 'W', ';',
'5', '0', '0', ' ', 'm', 'W', ';',
'1', '0', '0', '0', ' ', 'm', 'W', '\0', /* end of options */
0x02, /* value */
0x00, /* min */
0x04, /* max */
0x00, /* default */
};
TEST_ASSERT_EQUAL_INT(0, cel_crsf_param_parse(&param, payload, sizeof(payload)));
TEST_ASSERT_EQUAL_UINT8(5, param.index);
TEST_ASSERT_EQUAL_UINT8(CEL_PARAM_TEXT_SELECT, param.type);
TEST_ASSERT_EQUAL_UINT8(0, param.hidden);
TEST_ASSERT_EQUAL_STRING("TX Power", param.name);
TEST_ASSERT_EQUAL_STRING("10 mW;25 mW;100 mW;500 mW;1000 mW", param.options);
TEST_ASSERT_EQUAL_UINT8(2, param.value);
TEST_ASSERT_EQUAL_UINT8(0, param.min_val);
TEST_ASSERT_EQUAL_UINT8(4, param.max_val);
TEST_ASSERT_EQUAL_UINT8(0, param.default_val);
}
void test_param_parse_hidden_flag(void) {
cel_crsf_param param;
uint8_t payload[] = {
0x10, 0xEE, 0x00, 0x00, 0x00,
0x88, /* type with hidden bit set (0x80 | 0x08) */
'H', 'i', 'd', 'd', 'e', 'n', '\0',
'A', ';', 'B', '\0',
0x00, 0x00, 0x01, 0x00,
};
TEST_ASSERT_EQUAL_INT(0, cel_crsf_param_parse(&param, payload, sizeof(payload)));
TEST_ASSERT_EQUAL_UINT8(CEL_PARAM_FLOAT, param.type);
TEST_ASSERT_EQUAL_UINT8(1, param.hidden);
}
void test_param_parse_uint8_type(void) {
cel_crsf_param param;
uint8_t payload[] = {
0x10, 0xEE, 0x10, 0x00, 0x00,
0x00, /* type = CEL_PARAM_UINT8 */
'V', 'a', 'l', '\0', /* name */
0x00, /* min */
0xFF, /* max */
0x80, /* default */
0x42, /* value */
};
TEST_ASSERT_EQUAL_INT(0, cel_crsf_param_parse(&param, payload, sizeof(payload)));
TEST_ASSERT_EQUAL_UINT8(0x10, param.index);
TEST_ASSERT_EQUAL_UINT8(CEL_PARAM_UINT8, param.type);
TEST_ASSERT_EQUAL_STRING("Val", param.name);
TEST_ASSERT_EQUAL_UINT8(0x42, param.value);
TEST_ASSERT_EQUAL_UINT8(0x00, param.min_val);
TEST_ASSERT_EQUAL_UINT8(0xFF, param.max_val);
TEST_ASSERT_EQUAL_UINT8(0x80, param.default_val);
}
void test_param_parse_int8_type(void) {
cel_crsf_param param;
uint8_t payload[] = {
0x10, 0xEE, 0x01, 0x00, 0x00,
0x01, /* type = CEL_PARAM_INT8 */
'S', '\0',
0x80, /* min (-128) */
0x7F, /* max (127) */
0x00, /* default */
0x10, /* value */
};
TEST_ASSERT_EQUAL_INT(0, cel_crsf_param_parse(&param, payload, sizeof(payload)));
TEST_ASSERT_EQUAL_UINT8(CEL_PARAM_INT8, param.type);
TEST_ASSERT_EQUAL_UINT8(0x10, param.value);
}
void test_param_parse_folder(void) {
cel_crsf_param param;
uint8_t payload[] = {
0x10, 0xEE, 0xFF, 0x00, 0x00,
0x0B, /* type = CEL_PARAM_FOLDER */
'F', 'o', 'l', 'd', 'e', 'r', '\0',
};
TEST_ASSERT_EQUAL_INT(0, cel_crsf_param_parse(&param, payload, sizeof(payload)));
TEST_ASSERT_EQUAL_UINT8(CEL_PARAM_FOLDER, param.type);
TEST_ASSERT_EQUAL_STRING("Folder", param.name);
}
void test_param_parse_name_truncation(void) {
cel_crsf_param param;
/* Name longer than 63 chars (should be truncated) */
uint8_t payload[128] = {0};
payload[0] = 0x10; /* dest */
payload[1] = 0xEE; /* src */
payload[2] = 0x00; /* index */
payload[3] = 0x00; /* chunks */
payload[4] = 0x00; /* parent */
payload[5] = 0x0B; /* type = FOLDER */
/* Fill name with 70 'A' chars */
for (int i = 0; i < 70; i++) payload[6 + i] = 'A';
payload[6 + 70] = '\0';
TEST_ASSERT_EQUAL_INT(0, cel_crsf_param_parse(&param, payload, sizeof(payload)));
TEST_ASSERT_EQUAL_UINT8(63, strlen(param.name)); /* truncated to 63 */
}
void test_param_parse_options_truncation(void) {
cel_crsf_param param;
/* Options longer than 255 chars (should be truncated) */
uint8_t payload[400] = {0};
payload[0] = 0x10; /* dest */
payload[1] = 0xEE; /* src */
payload[2] = 0x00; /* index */
payload[3] = 0x00; /* chunks */
payload[4] = 0x00; /* parent */
payload[5] = 0x09; /* type = TEXT_SELECT */
strcpy((char*)(payload + 6), "Name");
payload[6 + 4] = '\0';
/* Fill options with 300 'O' chars */
size_t opts_start = 6 + 5; /* after name */
for (int i = 0; i < 299; i++) payload[opts_start + i] = 'O';
payload[opts_start + 299] = '\0';
/* Add type-specific data after options */
size_t after_opts = opts_start + 300;
payload[after_opts] = 0x00; /* value */
payload[after_opts + 1] = 0x00; /* min */
payload[after_opts + 2] = 0x00; /* max */
payload[after_opts + 3] = 0x00; /* default */
TEST_ASSERT_EQUAL_INT(0, cel_crsf_param_parse(&param, payload, sizeof(payload)));
TEST_ASSERT_EQUAL_UINT8(255, strlen(param.options)); /* truncated to 255 */
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_param_parse_null_args);
RUN_TEST(test_param_parse_too_short);
RUN_TEST(test_param_parse_text_select);
RUN_TEST(test_param_parse_hidden_flag);
RUN_TEST(test_param_parse_uint8_type);
RUN_TEST(test_param_parse_int8_type);
RUN_TEST(test_param_parse_folder);
RUN_TEST(test_param_parse_name_truncation);
RUN_TEST(test_param_parse_options_truncation);
return UNITY_END();
}