Reduce RAK Full Companion help overhead without removing commands
This commit is contained in:
1 parent
807343de8d
commit
684df9c643
5 files changed
+487
-216
No files matched your search
@@ -830,6 +830,7 @@ jobs:
|
||||
python3 -B test/test_companion_hil_startup_frequency.py -v
|
||||
python3 -B test/test_companion_board_power_commands.py -v
|
||||
python3 -B test/test_companion_radio_diagnostics.py -v
|
||||
python3 -B test/test_companion_help_writer.py -v
|
||||
python3 -B test/test_sdcard_cli_parity.py -v
|
||||
python3 -B test/test_esp32_buffered_radio_targets.py -v
|
||||
python3 -B test/test_xiao_battery_safety.py -v
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
// Reusable help fragments. The caller selects printing or aggregation.
|
||||
// Keep feature gates here so both paths expose the same commands and options.
|
||||
#if !defined(MESH_COMPANION_HELP_BEGIN) || !defined(MESH_COMPANION_HELP_END) \
|
||||
|| !defined(MESH_COMPANION_HELP_LINE_BEGIN) || !defined(MESH_COMPANION_HELP_LINE_END)
|
||||
#error "CompanionHelp.inc requires all four help emission macros"
|
||||
#endif
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
"Commands:\r\n"
|
||||
" stats-core / stats-radio / stats-radio-diag / stats-packets\r\n"
|
||||
" get prv.key (if export enabled)\r\n"
|
||||
#if defined(ESP32_PLATFORM) && defined(WIFI_SSID)
|
||||
" password <new-password> (shared setup WiFi, WebConfig and WiFi OTA)\r\n"
|
||||
" get password (management password status)\r\n"
|
||||
#else
|
||||
" get password (no admin password)\r\n"
|
||||
#endif
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" erase (settings and identity)\r\n"
|
||||
" board\r\n"
|
||||
" version\r\n"
|
||||
" get storage.layout\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get beacon [slot] / set beacon <slot> <meshcore|meshtext> ...\r\n"
|
||||
" delete beacon <slot|all> / set beacon.interval <12|24|36|48> (default 24h)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#if MESH_ENABLE_MESHTEXT_CHAT
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get mt.status / get mt.region / get mt.slot / get mt.hops\r\n"
|
||||
" get mt.node / get mt.shortname\r\n"
|
||||
" get mt.rebroadcast / set mt.rebroadcast <on|off> (saved; default off)\r\n"
|
||||
" Relay decoded channel text only; adds 5 packet airtimes before TX\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set mt.region <auto|us|eu868|eu433|anz>\r\n"
|
||||
" set mt.slot <0|1-based frequency slot>\r\n"
|
||||
" set mt.hops <0..7> (saved; default 7)\r\n"
|
||||
" set mt.node <!8hex|default> (saved; use a unique ID)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set mt.shortname <1..4 UTF-8 characters|default> (saved; NodeInfo uses 4 bytes)\r\n"
|
||||
" send mt.nodeinfo <channel slot> (GPS-free; also automatic after first chat)\r\n"
|
||||
" set mt.preset <longfast|shortturbo|...> (saved manual radio2)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set mt.channel <slot> <mt-name> <32/64 hex digits|AQ==>\r\n"
|
||||
" get mt.channel <slot> / delete mt.channel <slot>\r\n"
|
||||
" Join #mt-longfast or #mt-shortturbo in the app for automatic radio2\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM) && defined(EXTRAFS) && !defined(QSPIFLASH)
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get flash.health\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#if COMPANION_FEATURE_READER
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get reader <chapter>[:<verse>[-<last>]] [page] (World English Bible, offline)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get/set tx.media auto|radio|radio2|both|off (binary media)\r\n"
|
||||
" get/set tx.ssh auto|radio|radio2|both|off (tagged tunnel data)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#if MESH_ENABLE_ETHERNET_TUNNEL
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get ethernet / get ethernet.radio\r\n"
|
||||
" set ethernet.radio <MHz>,<kHz>,<SF>,<CR>[,<preamble>]\r\n"
|
||||
" set ethernet on|off (saved; trusted-LAN KISS TCP 5003, radio2 only)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#if defined(OTA_RAK15002_SD_STORE) && defined(ETHERNET_USE_RAK13800)
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get eth / set eth on|off (physical RAK13800; default off, this boot)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_SD_STORE)
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get sdcard [free|ls|dir [page]|format|erase|*]\r\n"
|
||||
" set sdcard format|erase [--force]\r\n"
|
||||
" ota cache [on|off] (SD archive)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" power / get pwrmgt.support / get pwrmgt.source / get pwrmgt.bootmv\r\n"
|
||||
" get system.watchdog (hardware status)\r\n"
|
||||
" get bootloader.ver\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get pwrmgt.bootreason\r\n"
|
||||
#if COMPANION_FEATURE_MEMORY_DIAGNOSTICS
|
||||
" memory\r\n"
|
||||
#endif
|
||||
" get/set display.rotation <0|90|180|270>\r\n"
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT && defined(DISPLAY_CLASS)
|
||||
" get/set display.controller <auto|ssd1306|sh1106> (saved; restart to apply)\r\n"
|
||||
#endif
|
||||
#ifdef PIN_BUZZER
|
||||
" get/set buzzer on|off\r\n"
|
||||
#endif
|
||||
#if defined(PIN_VIBRATION) || defined(HAS_DRV2605)
|
||||
" get/set vibration on|off\r\n"
|
||||
#endif
|
||||
MESH_COMPANION_HELP_END
|
||||
#if COMPANION_FEATURE_NOTIFICATIONS
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get notify / get notify.rules / get notify.gpio.pins\r\n"
|
||||
" set notify.{sound|vibration|led|screen|gpio} on|off\r\n"
|
||||
" set notify.<output> <all|contact:key|room:key|channel:slot> <pattern>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set notify.remote <contact:key|room:key> on|off (!notify, max 15s, no GPIO)\r\n"
|
||||
" notify.test <target> / notify.stop / notify.delete <target>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get/set display.inbox <history|pending|unread>\r\n"
|
||||
" get/set display.touch <on|off> (this boot)\r\n"
|
||||
" get public.key\r\n"
|
||||
" set {name|lat|lon|freq|tx|af} {value}\r\n"
|
||||
" get wifi|espnow|2.4ghz\r\n"
|
||||
" set wifi|espnow on|off [force] (force only with off)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set 2.4ghz on [all|force]|off [force] (this boot)\r\n"
|
||||
" get/set bluetooth.name <name|default>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#if defined(BLE_PIN_CODE)
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get bluetooth (alias: get ble)\r\n"
|
||||
" set bluetooth <on|off> [force] (saved; force only with off)\r\n"
|
||||
" get bluetooth.mac\r\n"
|
||||
" set bluetooth.mac <address|random|random-every-boot|random-after-connect|default>\r\n"
|
||||
" get/set bluetooth.stealth on|off\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
#if MESH_ENABLE_LOST_REPLY
|
||||
" get/set lost.reply <off|no|yes>\r\n"
|
||||
#endif
|
||||
" set pin <0-999999>\r\n"
|
||||
" powersaving [on|off]\r\n"
|
||||
#if MESH_USB_LOGGING_AVAILABLE
|
||||
" get/set usb.logging <on|off|stream> [reboot]\r\n"
|
||||
" get/set usb.debug <on|off>\r\n"
|
||||
#if MESH_USB_CONSOLE_COOPERATIVE
|
||||
" get usb.watchdog.last\r\n"
|
||||
" get/set usb.watchdog <off|on|auto> (saved; default auto)\r\n"
|
||||
#endif
|
||||
#endif
|
||||
MESH_COMPANION_HELP_END
|
||||
#if defined(ESP32) && defined(WIFI_SSID)
|
||||
#if defined(COMPANION_RADIO_FULL)
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" start ota [ap] (WiFi firmware update on port 8080)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" stop ota\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#if defined(COMPANION_EXCLUSIVE_WIFI_BLE)
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get companion.transport\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set companion.transport <wifi|ble>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get wifi.powersave\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set wifi.powersave <none|min|max>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get wifi.protocol\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get wifi.status (connection, saved/boot/live settings)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set wifi.protocol <bg|bgn> (saved; reboot required)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#if !defined(COMPANION_EXCLUSIVE_WIFI_BLE)
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get wifi.mode\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set wifi.mode <normal|wifi-only> (saved; reboot required)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#ifdef WITH_WEBCONFIG
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get wifi.{ssid|pwd}\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set wifi.ssid <network name>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set wifi.pwd <password>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get webui\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set webui <on|off>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" start webconfig [ap]\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" stop webconfig\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#endif
|
||||
#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get espnow.channel\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" set espnow.channel <1-13>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
// Keep native USB producer writes within 256 bytes without changing help text.
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get radio.rxps.config\r\n"
|
||||
" get/set radio.rxps <off|on|level 1-10 [preamble 16|32]|rx_us sleep_us>\r\n"
|
||||
" get/set radio.cad <on|off>\r\n"
|
||||
" set radio.cad timings <scan_ms|auto> <retry_ms|auto> <max_ms|auto>\r\n"
|
||||
" get/set radio.rxgain <on|off>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get rxps.wd\r\n"
|
||||
" get/set radio.rxps.rfrx_disabled <on|off> (this boot)\r\n"
|
||||
" clear stats\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" get/set radio.fem.rxgain <on|off>\r\n"
|
||||
" get/set radio.fem.txgain <on|off>\r\n"
|
||||
" get/set flood.retry.count <0-15>\r\n"
|
||||
" get/set flood.retry.path <0-63|off>\r\n"
|
||||
" get/set flood.retry.group.path <0-63|off>\r\n"
|
||||
" get/set flood.retry.advert <on|off>\r\n"
|
||||
" card\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" import <meshcore://card>\r\n"
|
||||
" clock\r\n"
|
||||
" time <epoch-seconds>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" list [n]\r\n"
|
||||
" show [adverts|channels|emergency] [on|off]\r\n"
|
||||
" to [name|prefix]\r\n"
|
||||
" path [direct|clear|hop,...]\r\n"
|
||||
" send <text>\r\n"
|
||||
" login <admin-password>\r\n"
|
||||
" cmd <remote-command>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" trace [name|prefix]\r\n"
|
||||
" trace path <1|2|4> <prefixes...>\r\n"
|
||||
" advert\r\n"
|
||||
" reset path\r\n"
|
||||
" public <text>\r\n"
|
||||
" channels\r\n"
|
||||
" channel <name-or-slot> <text>\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#if defined(NRF52_PLATFORM) && defined(EXTRAFS) && !defined(QSPIFLASH)
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" repair extrafs (erases/rebuilds internal ExtraFS)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" scan extrafs erase (USB only; reboot for destructive page test)\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#if COMPANION_FEATURE_TEMP_RADIO || COMPANION_FEATURE_OTA_CLI
|
||||
#if COMPANION_FEATURE_TEMP_RADIO
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" tempradio [freq,bw,sf,cr,minutes]\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" normalradio\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#if COMPANION_FEATURE_OTA_CLI
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" ota {status|ls|announce|folder|config|...}\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#endif
|
||||
#endif
|
||||
MESH_COMPANION_HELP_BEGIN
|
||||
" reboot\r\n"
|
||||
" ver\r\n"
|
||||
MESH_COMPANION_HELP_END
|
||||
#if defined(NRF52_PLATFORM)
|
||||
MESH_COMPANION_HELP_LINE_BEGIN
|
||||
" uf2reset"
|
||||
MESH_COMPANION_HELP_LINE_END
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh { namespace companion {
|
||||
|
||||
// Native USB accepts bounded producer writes. Honor partial progress, and stop
|
||||
// if the sink cannot accept another byte rather than spinning on a closed host.
|
||||
template<typename Output>
|
||||
size_t writeHelpChunks(Output& output, const char* text, size_t length) {
|
||||
if (!text) return 0;
|
||||
size_t written = 0;
|
||||
while (written < length) {
|
||||
const size_t remaining = length - written;
|
||||
const size_t chunk = remaining > 256 ? 256 : remaining;
|
||||
const size_t accepted = output.write(
|
||||
reinterpret_cast<const uint8_t*>(text) + written, chunk);
|
||||
if (accepted == 0 || accepted > chunk) break;
|
||||
written += accepted;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
} } // namespace mesh::companion
|
||||
@@ -21,6 +21,9 @@
|
||||
#include <helpers/ui/StartupScreen.h>
|
||||
#include "NotificationSettingsFile.h"
|
||||
#include "MyMesh.h"
|
||||
#if defined(RAK_4631) && defined(COMPANION_RADIO_FULL)
|
||||
#include "CompanionHelpWriter.h"
|
||||
#endif
|
||||
#include <helpers/CompanionStartupFrequency.h>
|
||||
#include <helpers/CompanionRadioDiagnostics.h>
|
||||
#include <helpers/CompanionPowerDiagnostics.h>
|
||||
@@ -10401,223 +10404,30 @@ void MyMesh::handleTerminalCommand(char* command, bool reader_prompt,
|
||||
FIRMWARE_VERSION, (unsigned)FIRMWARE_VER_CODE, FIRMWARE_BUILD_DATE);
|
||||
} else if (strcmp(command, "help") == 0) {
|
||||
auto& output = terminalOutput();
|
||||
output.print(
|
||||
"Commands:\r\n"
|
||||
" stats-core / stats-radio / stats-radio-diag / stats-packets\r\n"
|
||||
" get prv.key (if export enabled)\r\n"
|
||||
#if defined(ESP32_PLATFORM) && defined(WIFI_SSID)
|
||||
" password <new-password> (shared setup WiFi, WebConfig and WiFi OTA)\r\n"
|
||||
" get password (management password status)\r\n"
|
||||
#if defined(RAK_4631) && defined(COMPANION_RADIO_FULL)
|
||||
// Keep every help byte and feature gate while sharing the printing code.
|
||||
static const char help_text[] =
|
||||
#define MESH_COMPANION_HELP_BEGIN
|
||||
#define MESH_COMPANION_HELP_END
|
||||
#define MESH_COMPANION_HELP_LINE_BEGIN
|
||||
#define MESH_COMPANION_HELP_LINE_END "\r\n"
|
||||
#include "CompanionHelp.inc"
|
||||
#undef MESH_COMPANION_HELP_BEGIN
|
||||
#undef MESH_COMPANION_HELP_END
|
||||
#undef MESH_COMPANION_HELP_LINE_BEGIN
|
||||
#undef MESH_COMPANION_HELP_LINE_END
|
||||
;
|
||||
mesh::companion::writeHelpChunks(output, help_text, sizeof(help_text) - 1);
|
||||
#else
|
||||
" get password (no admin password)\r\n"
|
||||
#endif
|
||||
);
|
||||
output.print(
|
||||
" erase (settings and identity)\r\n"
|
||||
" board\r\n"
|
||||
" version\r\n"
|
||||
" get storage.layout\r\n");
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
output.print(
|
||||
" get beacon [slot] / set beacon <slot> <meshcore|meshtext> ...\r\n"
|
||||
" delete beacon <slot|all> / set beacon.interval <12|24|36|48> (default 24h)\r\n");
|
||||
#endif
|
||||
#if MESH_ENABLE_MESHTEXT_CHAT
|
||||
output.print(
|
||||
" get mt.status / get mt.region / get mt.slot / get mt.hops\r\n"
|
||||
" get mt.node / get mt.shortname\r\n"
|
||||
" get mt.rebroadcast / set mt.rebroadcast <on|off> (saved; default off)\r\n"
|
||||
" Relay decoded channel text only; adds 5 packet airtimes before TX\r\n");
|
||||
output.print(
|
||||
" set mt.region <auto|us|eu868|eu433|anz>\r\n"
|
||||
" set mt.slot <0|1-based frequency slot>\r\n"
|
||||
" set mt.hops <0..7> (saved; default 7)\r\n"
|
||||
" set mt.node <!8hex|default> (saved; use a unique ID)\r\n");
|
||||
output.print(
|
||||
" set mt.shortname <1..4 UTF-8 characters|default> (saved; NodeInfo uses 4 bytes)\r\n"
|
||||
" send mt.nodeinfo <channel slot> (GPS-free; also automatic after first chat)\r\n"
|
||||
" set mt.preset <longfast|shortturbo|...> (saved manual radio2)\r\n");
|
||||
output.print(
|
||||
" set mt.channel <slot> <mt-name> <32/64 hex digits|AQ==>\r\n"
|
||||
" get mt.channel <slot> / delete mt.channel <slot>\r\n"
|
||||
" Join #mt-longfast or #mt-shortturbo in the app for automatic radio2\r\n");
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM) && defined(EXTRAFS) && !defined(QSPIFLASH)
|
||||
output.print(" get flash.health\r\n");
|
||||
#endif
|
||||
#if COMPANION_FEATURE_READER
|
||||
output.print(" get reader <chapter>[:<verse>[-<last>]] [page] (World English Bible, offline)\r\n");
|
||||
#endif
|
||||
output.print(
|
||||
" get/set tx.media auto|radio|radio2|both|off (binary media)\r\n"
|
||||
" get/set tx.ssh auto|radio|radio2|both|off (tagged tunnel data)\r\n");
|
||||
#if MESH_ENABLE_ETHERNET_TUNNEL
|
||||
output.print(
|
||||
" get ethernet / get ethernet.radio\r\n"
|
||||
" set ethernet.radio <MHz>,<kHz>,<SF>,<CR>[,<preamble>]\r\n"
|
||||
" set ethernet on|off (saved; trusted-LAN KISS TCP 5003, radio2 only)\r\n");
|
||||
#endif
|
||||
#if defined(OTA_RAK15002_SD_STORE) && defined(ETHERNET_USE_RAK13800)
|
||||
output.print(
|
||||
" get eth / set eth on|off (physical RAK13800; default off, this boot)\r\n");
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_SD_STORE)
|
||||
output.print(
|
||||
" get sdcard [free|ls|dir [page]|format|erase|*]\r\n"
|
||||
" set sdcard format|erase [--force]\r\n"
|
||||
" ota cache [on|off] (SD archive)\r\n");
|
||||
#endif
|
||||
output.print(
|
||||
" power / get pwrmgt.support / get pwrmgt.source / get pwrmgt.bootmv\r\n"
|
||||
" get system.watchdog (hardware status)\r\n"
|
||||
" get bootloader.ver\r\n");
|
||||
output.print(
|
||||
" get pwrmgt.bootreason\r\n"
|
||||
#if COMPANION_FEATURE_MEMORY_DIAGNOSTICS
|
||||
" memory\r\n"
|
||||
#endif
|
||||
" get/set display.rotation <0|90|180|270>\r\n"
|
||||
#if defined(OLED_AUTO_DETECT) && OLED_AUTO_DETECT && defined(DISPLAY_CLASS)
|
||||
" get/set display.controller <auto|ssd1306|sh1106> (saved; restart to apply)\r\n"
|
||||
#endif
|
||||
#ifdef PIN_BUZZER
|
||||
" get/set buzzer on|off\r\n"
|
||||
#endif
|
||||
#if defined(PIN_VIBRATION) || defined(HAS_DRV2605)
|
||||
" get/set vibration on|off\r\n"
|
||||
#endif
|
||||
);
|
||||
#if COMPANION_FEATURE_NOTIFICATIONS
|
||||
output.print(
|
||||
" get notify / get notify.rules / get notify.gpio.pins\r\n"
|
||||
" set notify.{sound|vibration|led|screen|gpio} on|off\r\n"
|
||||
" set notify.<output> <all|contact:key|room:key|channel:slot> <pattern>\r\n");
|
||||
output.print(
|
||||
" set notify.remote <contact:key|room:key> on|off (!notify, max 15s, no GPIO)\r\n"
|
||||
" notify.test <target> / notify.stop / notify.delete <target>\r\n");
|
||||
#endif
|
||||
output.print(
|
||||
" get/set display.inbox <history|pending|unread>\r\n"
|
||||
" get/set display.touch <on|off> (this boot)\r\n"
|
||||
" get public.key\r\n"
|
||||
" set {name|lat|lon|freq|tx|af} {value}\r\n"
|
||||
" get wifi|espnow|2.4ghz\r\n"
|
||||
" set wifi|espnow on|off [force] (force only with off)\r\n");
|
||||
output.print(
|
||||
" set 2.4ghz on [all|force]|off [force] (this boot)\r\n"
|
||||
" get/set bluetooth.name <name|default>\r\n");
|
||||
#if defined(BLE_PIN_CODE)
|
||||
output.print(
|
||||
" get bluetooth (alias: get ble)\r\n"
|
||||
" set bluetooth <on|off> [force] (saved; force only with off)\r\n"
|
||||
" get bluetooth.mac\r\n"
|
||||
" set bluetooth.mac <address|random|random-every-boot|random-after-connect|default>\r\n"
|
||||
" get/set bluetooth.stealth on|off\r\n");
|
||||
#endif
|
||||
output.print(
|
||||
#if MESH_ENABLE_LOST_REPLY
|
||||
" get/set lost.reply <off|no|yes>\r\n"
|
||||
#endif
|
||||
" set pin <0-999999>\r\n"
|
||||
" powersaving [on|off]\r\n"
|
||||
#if MESH_USB_LOGGING_AVAILABLE
|
||||
" get/set usb.logging <on|off|stream> [reboot]\r\n"
|
||||
" get/set usb.debug <on|off>\r\n"
|
||||
#if MESH_USB_CONSOLE_COOPERATIVE
|
||||
" get usb.watchdog.last\r\n"
|
||||
" get/set usb.watchdog <off|on|auto> (saved; default auto)\r\n"
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
#if defined(ESP32) && defined(WIFI_SSID)
|
||||
#if defined(COMPANION_RADIO_FULL)
|
||||
output.print(" start ota [ap] (WiFi firmware update on port 8080)\r\n");
|
||||
output.print(" stop ota\r\n");
|
||||
#endif
|
||||
#if defined(COMPANION_EXCLUSIVE_WIFI_BLE)
|
||||
output.print(" get companion.transport\r\n");
|
||||
output.print(" set companion.transport <wifi|ble>\r\n");
|
||||
#endif
|
||||
output.print(" get wifi.powersave\r\n");
|
||||
output.print(" set wifi.powersave <none|min|max>\r\n");
|
||||
output.print(" get wifi.protocol\r\n");
|
||||
output.print(" get wifi.status (connection, saved/boot/live settings)\r\n");
|
||||
output.print(" set wifi.protocol <bg|bgn> (saved; reboot required)\r\n");
|
||||
#if !defined(COMPANION_EXCLUSIVE_WIFI_BLE)
|
||||
output.print(" get wifi.mode\r\n");
|
||||
output.print(" set wifi.mode <normal|wifi-only> (saved; reboot required)\r\n");
|
||||
#endif
|
||||
#ifdef WITH_WEBCONFIG
|
||||
output.print(" get wifi.{ssid|pwd}\r\n");
|
||||
output.print(" set wifi.ssid <network name>\r\n");
|
||||
output.print(" set wifi.pwd <password>\r\n");
|
||||
output.print(" get webui\r\n");
|
||||
output.print(" set webui <on|off>\r\n");
|
||||
output.print(" start webconfig [ap]\r\n");
|
||||
output.print(" stop webconfig\r\n");
|
||||
#endif
|
||||
#endif
|
||||
#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW
|
||||
output.print(" get espnow.channel\r\n");
|
||||
output.print(" set espnow.channel <1-13>\r\n");
|
||||
#endif
|
||||
// Keep native USB producer writes within 256 bytes without changing help text.
|
||||
output.print(
|
||||
" get radio.rxps.config\r\n"
|
||||
" get/set radio.rxps <off|on|level 1-10 [preamble 16|32]|rx_us sleep_us>\r\n"
|
||||
" get/set radio.cad <on|off>\r\n"
|
||||
" set radio.cad timings <scan_ms|auto> <retry_ms|auto> <max_ms|auto>\r\n"
|
||||
" get/set radio.rxgain <on|off>\r\n");
|
||||
output.print(
|
||||
" get rxps.wd\r\n"
|
||||
" get/set radio.rxps.rfrx_disabled <on|off> (this boot)\r\n"
|
||||
" clear stats\r\n");
|
||||
output.print(
|
||||
" get/set radio.fem.rxgain <on|off>\r\n"
|
||||
" get/set radio.fem.txgain <on|off>\r\n"
|
||||
" get/set flood.retry.count <0-15>\r\n"
|
||||
" get/set flood.retry.path <0-63|off>\r\n"
|
||||
" get/set flood.retry.group.path <0-63|off>\r\n"
|
||||
" get/set flood.retry.advert <on|off>\r\n"
|
||||
" card\r\n");
|
||||
output.print(
|
||||
" import <meshcore://card>\r\n"
|
||||
" clock\r\n"
|
||||
" time <epoch-seconds>\r\n");
|
||||
output.print(
|
||||
" list [n]\r\n"
|
||||
" show [adverts|channels|emergency] [on|off]\r\n"
|
||||
" to [name|prefix]\r\n"
|
||||
" path [direct|clear|hop,...]\r\n"
|
||||
" send <text>\r\n"
|
||||
" login <admin-password>\r\n"
|
||||
" cmd <remote-command>\r\n");
|
||||
output.print(
|
||||
" trace [name|prefix]\r\n"
|
||||
" trace path <1|2|4> <prefixes...>\r\n"
|
||||
" advert\r\n"
|
||||
" reset path\r\n"
|
||||
" public <text>\r\n"
|
||||
" channels\r\n"
|
||||
" channel <name-or-slot> <text>\r\n");
|
||||
#if defined(NRF52_PLATFORM) && defined(EXTRAFS) && !defined(QSPIFLASH)
|
||||
output.print(" repair extrafs (erases/rebuilds internal ExtraFS)\r\n");
|
||||
output.print(" scan extrafs erase (USB only; reboot for destructive page test)\r\n");
|
||||
#endif
|
||||
#if COMPANION_FEATURE_TEMP_RADIO || COMPANION_FEATURE_OTA_CLI
|
||||
#if COMPANION_FEATURE_TEMP_RADIO
|
||||
output.print(" tempradio [freq,bw,sf,cr,minutes]\r\n");
|
||||
output.print(" normalradio\r\n");
|
||||
#endif
|
||||
#if COMPANION_FEATURE_OTA_CLI
|
||||
output.print(" ota {status|ls|announce|folder|config|...}\r\n");
|
||||
#endif
|
||||
#endif
|
||||
output.print(
|
||||
" reboot\r\n"
|
||||
" ver\r\n");
|
||||
#if defined(NRF52_PLATFORM)
|
||||
output.println(" uf2reset");
|
||||
#define MESH_COMPANION_HELP_BEGIN output.print(
|
||||
#define MESH_COMPANION_HELP_END );
|
||||
#define MESH_COMPANION_HELP_LINE_BEGIN output.println(
|
||||
#define MESH_COMPANION_HELP_LINE_END );
|
||||
#include "CompanionHelp.inc"
|
||||
#undef MESH_COMPANION_HELP_BEGIN
|
||||
#undef MESH_COMPANION_HELP_END
|
||||
#undef MESH_COMPANION_HELP_LINE_BEGIN
|
||||
#undef MESH_COMPANION_HELP_LINE_END
|
||||
#endif
|
||||
if (_terminal_mode) {
|
||||
output.print(" +++MESHCORE-TERM-STOP\r\n");
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Execute actual help branches; preserve807 UI and bounded partial writes."""
|
||||
from pathlib import Path
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
FEATURES = ['COMPANION_FEATURE_READER=1', 'COMPANION_FEATURE_TEMP_RADIO=1',
|
||||
'COMPANION_FEATURE_OTA_CLI=1', 'COMPANION_FEATURE_NOTIFICATIONS=1',
|
||||
'MESH_ENABLE_LOST_REPLY=1', 'MESH_ENABLE_TX_BEACONS=1',
|
||||
'MESH_ENABLE_MESHTEXT_CHAT=1', 'MESH_ENABLE_ETHERNET_TUNNEL=1']
|
||||
PROFILES = {
|
||||
'rak_full': ['NRF52_PLATFORM', 'RAK_4631', 'COMPANION_RADIO_FULL', 'EXTRAFS',
|
||||
'DISPLAY_CLASS', 'OLED_AUTO_DETECT=1', 'BLE_PIN_CODE=123456',
|
||||
'OTA_RAK15002_SD_STORE', 'ETHERNET_USE_RAK13800', 'OTA_SD_STORE',
|
||||
'MESH_USB_LOGGING_AVAILABLE=1', 'MESH_USB_CONSOLE_COOPERATIVE=1', *FEATURES],
|
||||
'nrf_full': ['NRF52_PLATFORM', 'COMPANION_RADIO_FULL', 'EXTRAFS', 'DISPLAY_CLASS',
|
||||
'OLED_AUTO_DETECT=1', 'BLE_PIN_CODE=123456', 'MESH_USB_LOGGING_AVAILABLE=1',
|
||||
'MESH_USB_CONSOLE_COOPERATIVE=1', *FEATURES],
|
||||
'nrf_minimal': ['NRF52_PLATFORM'],
|
||||
'esp_full': ['ESP32_PLATFORM', 'ESP32', 'WIFI_SSID', 'COMPANION_RADIO_FULL',
|
||||
'COMPANION_FEATURE_MEMORY_DIAGNOSTICS=1', 'WITH_WEBCONFIG',
|
||||
'MESH_USB_LOGGING_AVAILABLE=1', 'MESH_USB_CONSOLE_COOPERATIVE=1',
|
||||
'MESH_PRIMARY_ESPNOW=1', 'BLE_PIN_CODE=123456', 'PIN_BUZZER',
|
||||
'PIN_VIBRATION', *FEATURES],
|
||||
}
|
||||
# Generated from807's original literal groups, including its dynamic TERM-STOP
|
||||
# suffix. Non-RAK call hashes bind print/println order as well as all text bytes.
|
||||
GOLDEN = {'rak_full': {'text': '9a68ce5a10905a201c3bddeb19f4819ce03c6dcaff248cff9c140803b70b14a7', 'calls': '56ed09dee7d53881b2c9fcf3f4ec9b6223e1562ce63e110a065e46706702b53b'}, 'nrf_full': {'text': 'b114ac12ae2ea01b7c47609b72f7eafb616c1dbeb7fb796a95b1377465fd9105', 'calls': '4973a7f21887d07b129cce4ae4cc8145f3f35e664bae09be658957210440d52e'}, 'nrf_minimal': {'text': '15fa8f290cd8c75cfde2fd2ac1cb5b5151a6755c68448fb2793dde3f27669033', 'calls': '6063fd1a699f9c0b588252bd8ce5922e0ff31cec6bbd24522789284ab2a37644'}, 'esp_full': {'text': '1e3b6781c81b5603f7092108e5e309543c60cef8ff4d7cb41a891f67396f716f', 'calls': 'b6335df2bd05b9cab44a7933469b76c5b2611c4b81057436a959feaf3bfbaf60'}}
|
||||
|
||||
HARNESS = r'''
|
||||
#include "CompanionHelpWriter.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
struct Output {
|
||||
std::string text, trace;
|
||||
std::vector<size_t> writes;
|
||||
size_t throttle = 256, credit = size_t(-1);
|
||||
bool overreport = false;
|
||||
void record(char kind, const char* value, size_t length) {
|
||||
trace += kind;
|
||||
for (unsigned i=0;i<4;++i) trace += char((length>>(i*8))&255);
|
||||
trace.append(value,length);
|
||||
}
|
||||
size_t print(const char* value) {
|
||||
size_t n=strlen(value);text+=value;record('P',value,n);return n;
|
||||
}
|
||||
size_t println(const char* value) {
|
||||
std::string line=std::string(value)+"\r\n";
|
||||
text+=line;record('L',line.data(),line.size());return line.size();
|
||||
}
|
||||
size_t write(const uint8_t* value, size_t length) {
|
||||
assert(length<=256);writes.push_back(length);
|
||||
if (overreport) return length+1;
|
||||
size_t n=std::min(length,std::min(throttle,credit));
|
||||
text.append(reinterpret_cast<const char*>(value),n);credit-=n;
|
||||
record('W',reinterpret_cast<const char*>(value),n);return n;
|
||||
}
|
||||
} output;
|
||||
Output& terminalOutput() {return output;}
|
||||
void actualHelp(bool _terminal_mode) {
|
||||
@ACTUAL_HELP@
|
||||
}
|
||||
int main() {
|
||||
actualHelp(true);
|
||||
#if defined(RAK_4631) && defined(COMPANION_RADIO_FULL)
|
||||
assert(!output.writes.empty());
|
||||
#else
|
||||
assert(output.writes.empty());
|
||||
#endif
|
||||
fwrite(output.text.data(),1,output.text.size(),stdout);
|
||||
fwrite(output.trace.data(),1,output.trace.size(),stderr);
|
||||
std::string text(777,'x');
|
||||
Output partial;partial.throttle=7;
|
||||
assert(mesh::companion::writeHelpChunks(partial,text.data(),text.size())==text.size());
|
||||
assert(partial.text==text && partial.writes.size()<=text.size());
|
||||
Output stalled;stalled.credit=13;
|
||||
assert(mesh::companion::writeHelpChunks(stalled,text.data(),text.size())==13);
|
||||
assert(stalled.text==text.substr(0,13) && stalled.writes.size()==2);
|
||||
Output closed;closed.credit=0;
|
||||
assert(mesh::companion::writeHelpChunks(closed,text.data(),text.size())==0);
|
||||
assert(closed.writes.size()==1 && closed.text.empty());
|
||||
Output invalid;invalid.overreport=true;
|
||||
assert(mesh::companion::writeHelpChunks(invalid,text.data(),text.size())==0);
|
||||
assert(invalid.writes.size()==1 && invalid.text.empty());
|
||||
Output empty;
|
||||
assert(mesh::companion::writeHelpChunks(empty,nullptr,1)==0);
|
||||
assert(mesh::companion::writeHelpChunks(empty,"",0)==0 && empty.writes.empty());
|
||||
}
|
||||
'''
|
||||
|
||||
|
||||
class CompanionHelpWriterTests(unittest.TestCase):
|
||||
def test_actual_branch_preserves_ui_and_non_rak_call_sequence(self):
|
||||
compiler = os.environ.get('CXX') or shutil.which('g++') or shutil.which('clang++')
|
||||
if not compiler:
|
||||
self.skipTest('host C++17 compiler required')
|
||||
source = (ROOT / 'examples/companion_radio/MyMesh.cpp').read_text()
|
||||
start = source.index(' auto& output = terminalOutput();',
|
||||
source.index('} else if (strcmp(command, "help") == 0)'))
|
||||
end = source.index(' } else if (handleCommand(command, 0, local_reply))', start)
|
||||
harness = HARNESS.replace('@ACTUAL_HELP@', source[start:end])
|
||||
for name, defines in PROFILES.items():
|
||||
with self.subTest(profile=name), tempfile.TemporaryDirectory(prefix='companion-help-') as folder:
|
||||
work = Path(folder);(work / 'test.cpp').write_text(harness)
|
||||
sanitizer = ['-fsanitize=address,undefined', '-fno-sanitize-recover=all',
|
||||
'-fno-pie', '-no-pie'] if sys.platform.startswith('linux') else []
|
||||
result = subprocess.run([compiler, '-std=c++17', '-Wall', '-Wextra', '-Werror',
|
||||
*sanitizer, *['-D'+value for value in defines],
|
||||
'-I'+str(ROOT/'examples/companion_radio'), str(work/'test.cpp'),
|
||||
'-o', str(work/'test')], capture_output=True, text=True)
|
||||
self.assertEqual(result.returncode,0,result.stdout+result.stderr)
|
||||
result = subprocess.run([str(work/'test')],capture_output=True)
|
||||
self.assertEqual(result.returncode,0,result.stderr.decode(errors='replace'))
|
||||
self.assertEqual(hashlib.sha256(result.stdout).hexdigest(),GOLDEN[name]['text'])
|
||||
if name != 'rak_full':
|
||||
self.assertEqual(hashlib.sha256(result.stderr).hexdigest(),GOLDEN[name]['calls'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user