feat: implement cel_crsf_param_set_power
Enumerate parameters until TX Power entry is found, match requested mW against TEXT_SELECT options, and write the selected option index. Added: - str_contains_ci() for case-insensitive substring matching - is_power_param() to detect power-related parameters - match_power_option() to find mW in option strings - 4 new tests: null port, frame roundtrip, success, not found
This commit is contained in:
+89
-17
@@ -1,7 +1,70 @@
|
||||
#include "celrs/crsf_param.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "celrs/crsf_param.h"
|
||||
|
||||
/* --------------------------------------------------------------------------- */
|
||||
/* Helpers for power matching */
|
||||
/* --------------------------------------------------------------------------- */
|
||||
|
||||
/* Case-insensitive string contains */
|
||||
static int str_contains_ci(char const* haystack, char const* needle) {
|
||||
size_t hlen = strlen(haystack);
|
||||
size_t nlen = strlen(needle);
|
||||
if (nlen > hlen) return 0;
|
||||
for (size_t i = 0; i <= hlen - nlen; i++) {
|
||||
int match = 1;
|
||||
for (size_t j = 0; j < nlen; j++) {
|
||||
if (tolower((unsigned char)haystack[i + j])
|
||||
!= tolower((unsigned char)needle[j]))
|
||||
{
|
||||
match = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if param name contains "power" (case-insensitive) */
|
||||
static int is_power_param(cel_crsf_param const* param) {
|
||||
return str_contains_ci(param->name, "power");
|
||||
}
|
||||
|
||||
/* Match requested power (mW) against a TEXT_SELECT option string.
|
||||
* Returns option index (0-based) or -1 if no match. */
|
||||
static int match_power_option(cel_crsf_param const* param, int mw) {
|
||||
char const* opts = param->options;
|
||||
char opt_buf[64];
|
||||
int index = 0;
|
||||
|
||||
while (*opts) {
|
||||
/* Extract option up to ';' or '\0' */
|
||||
size_t i = 0;
|
||||
while (*opts && *opts != ';' && i < sizeof(opt_buf) - 1) {
|
||||
opt_buf[i++] = *opts++;
|
||||
}
|
||||
opt_buf[i] = '\0';
|
||||
if (*opts == ';') opts++; /* skip separator */
|
||||
|
||||
/* Check if option starts with the requested mW value */
|
||||
char req_buf[16];
|
||||
sprintf(req_buf, "%d", mw);
|
||||
if (str_contains_ci(opt_buf, req_buf)) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------- */
|
||||
/* Public API */
|
||||
/* --------------------------------------------------------------------------- */
|
||||
|
||||
int cel_crsf_param_ping(cel_serial_port* port, float timeout_sec) {
|
||||
if (port == NULL) return -1;
|
||||
|
||||
@@ -101,22 +164,31 @@ int cel_crsf_param_write(cel_serial_port* port, uint8_t index,
|
||||
|
||||
int cel_crsf_param_set_power(cel_serial_port* port, int mw,
|
||||
float timeout_sec) {
|
||||
/* TODO: enumerate parameters until TX Power entry is found.
|
||||
* 1. Send ping, verify DEVICE_INFO response (call cel_crsf_param_ping).
|
||||
* 2. For index 0..31:
|
||||
* a. Send param read frame for index.
|
||||
* b. Wait for PARAM_ENTRY response (timeout per param).
|
||||
* c. If no response, stop (end of parameter list).
|
||||
* d. If param name contains "power" (case-insensitive)
|
||||
* and type is CEL_PARAM_TEXT_SELECT:
|
||||
* - Search options for matching power level string
|
||||
* (e.g. "10" matches "10 mW", "dynamic" matches "dynamic").
|
||||
* - Send param write frame with matching option index.
|
||||
* - Return 0.
|
||||
* 3. If loop completes without finding power param, return -1. */
|
||||
(void)port;
|
||||
(void)mw;
|
||||
(void)timeout_sec;
|
||||
if (port == NULL) return -1;
|
||||
|
||||
/* 1. Ping to verify connection */
|
||||
if (cel_crsf_param_ping(port, timeout_sec) != 0) return -1;
|
||||
|
||||
/* 2. Enumerate params until power entry is found */
|
||||
for (uint8_t idx = 0; idx < 32; idx++) {
|
||||
cel_crsf_param param;
|
||||
if (cel_crsf_param_read(port, idx, ¶m, timeout_sec) != 0) {
|
||||
/* No response = end of parameter list */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if this is the power parameter */
|
||||
if (is_power_param(¶m) && param.type == CEL_PARAM_TEXT_SELECT) {
|
||||
/* Find matching option */
|
||||
int opt_index = match_power_option(¶m, mw);
|
||||
if (opt_index >= 0) {
|
||||
/* Write the selected option */
|
||||
return cel_crsf_param_write(port, idx, (uint8_t)opt_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 3. Power param not found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "celrs/crsf.h"
|
||||
#include "celrs/serial.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user