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.
This commit is contained in:
+61
-18
@@ -59,22 +59,65 @@ int cel_crsf_param_set_power(cel_serial_port* port, int mw,
|
||||
|
||||
int cel_crsf_param_parse(cel_crsf_param* out, uint8_t const* payload,
|
||||
size_t len) {
|
||||
/* TODO: parse PARAM_ENTRY payload into cel_crsf_param.
|
||||
* Layout:
|
||||
* [0] dest (uint8)
|
||||
* [1] src (uint8)
|
||||
* [2] index (uint8)
|
||||
* [3] chunks_remaining (uint8)
|
||||
* [4] parent (uint8)
|
||||
* [5] type (uint8, bit 7 = hidden flag)
|
||||
* [6..] name (null-terminated ASCII string)
|
||||
* Then type-specific data after name:
|
||||
* TEXT_SELECT: options (null-terminated, semicolon-separated),
|
||||
* then [value][min][max][default] (1 byte each)
|
||||
* UINT8/INT8: [min][max][default][value] (1 byte each)
|
||||
* Minimum payload length: 6 bytes. */
|
||||
(void)out;
|
||||
(void)payload;
|
||||
(void)len;
|
||||
return -1;
|
||||
if (out == NULL || payload == NULL) return -1;
|
||||
if (len < 6) return -1;
|
||||
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
size_t offset = 0;
|
||||
(void)payload[offset++]; /* dest */
|
||||
(void)payload[offset++]; /* src */
|
||||
out->index = payload[offset++];
|
||||
(void)payload[offset++]; /* chunks_remaining */
|
||||
(void)payload[offset++]; /* parent */
|
||||
uint8_t raw_type = payload[offset++];
|
||||
out->hidden = (raw_type & 0x80) ? 1 : 0;
|
||||
out->type = raw_type & 0x7F;
|
||||
|
||||
/* Parse name (null-terminated) */
|
||||
size_t name_start = offset;
|
||||
while (offset < len && payload[offset] != '\0') offset++;
|
||||
size_t name_len = offset - name_start;
|
||||
if (name_len >= sizeof(out->name)) name_len = sizeof(out->name) - 1;
|
||||
memcpy(out->name, payload + name_start, name_len);
|
||||
out->name[name_len] = '\0';
|
||||
if (offset < len) offset++; /* skip null terminator */
|
||||
|
||||
/* Parse type-specific data */
|
||||
switch (out->type) {
|
||||
case CEL_PARAM_TEXT_SELECT: {
|
||||
/* Options: null-terminated, semicolon-separated string */
|
||||
size_t opts_start = offset;
|
||||
while (offset < len && payload[offset] != '\0') offset++;
|
||||
size_t opts_len = offset - opts_start;
|
||||
if (opts_len >= sizeof(out->options)) opts_len = sizeof(out->options) - 1;
|
||||
memcpy(out->options, payload + opts_start, opts_len);
|
||||
out->options[opts_len] = '\0';
|
||||
if (offset < len) offset++; /* skip null terminator */
|
||||
|
||||
/* [value][min][max][default] */
|
||||
if (offset + 4 <= len) {
|
||||
out->value = payload[offset++];
|
||||
out->min_val = payload[offset++];
|
||||
out->max_val = payload[offset++];
|
||||
out->default_val = payload[offset++];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CEL_PARAM_UINT8:
|
||||
case CEL_PARAM_INT8:
|
||||
/* [min][max][default][value] */
|
||||
if (offset + 4 <= len) {
|
||||
out->min_val = payload[offset++];
|
||||
out->max_val = payload[offset++];
|
||||
out->default_val = payload[offset++];
|
||||
out->value = payload[offset++];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Other types have no simple value representation */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user