From 9d91b039bf23455e37cc68df4e1707d99c2c89e4 Mon Sep 17 00:00:00 2001 From: mikecarper Date: Fri, 18 Sep 2026 11:24:18 -0700 Subject: [PATCH] Fit Wio companion USB logging --- build.sh | 27 --------- examples/companion_radio/MyMesh.h | 3 + examples/companion_radio/main.cpp | 90 +++++++++++++++++++++++++++++ test/test_build_profiles.sh | 5 -- variants/wio-e5-mini/platformio.ini | 14 +++-- 5 files changed, 101 insertions(+), 38 deletions(-) diff --git a/build.sh b/build.sh index 7b7d670b..c41080f7 100755 --- a/build.sh +++ b/build.sh @@ -60,7 +60,6 @@ REQUIRE_OTA_UPDATES="${REQUIRE_OTA_UPDATES:-}" OTA_EXCLUDED_TARGETS=() LOGGING_MATRIX_FAILURES=() LOGGING_MATRIX_DEFERRED_TARGETS=() -LOGGING_MATRIX_DEFERRED_CAPACITY_TARGETS=() RADIO_PRESET_SELECTION="" KISS_MODE_OVERRIDE="${KISS_MODE_OVERRIDE-}" PARSED_COMMAND_ARGS=() @@ -2108,23 +2107,6 @@ is_logging_size_constrained_target() { esac } -is_logging_matrix_capacity_deferred_target() { - # This STM32WL Companion needs 238 KiB with its complete storage, sensor, - # and runtime USB logging contract, while the deployed layout reserves - # 32 KiB of its 256 KiB flash for LittleFS. Do not silently shrink that - # storage or remove a feature just to publish a matrix artifact. The target - # remains directly buildable for capacity work; it is omitted from the - # logging matrix until its storage-layout decision is explicitly approved. - case "$1" in - wio-e5-mini_companion_radio_usb) - return 0 - ;; - *) - return 1 - ;; - esac -} - prompt_for_kiss_modem_build_policy() { local kiss_count=0 local target @@ -5680,7 +5662,6 @@ run_logging_matrix_build_targets() { fi LOGGING_MATRIX_FAILURES=() LOGGING_MATRIX_DEFERRED_TARGETS=() - LOGGING_MATRIX_DEFERRED_CAPACITY_TARGETS=() if [ "${REQUIRE_OTA_UPDATES:-0}" = "1" ]; then printf '%s\n' "${OTA_EXCLUDED_TARGETS[@]}" > "${OUTPUT_DIR}/ota-excluded-targets.txt" fi @@ -5691,10 +5672,6 @@ run_logging_matrix_build_targets() { if is_mqtt_bridge_target "$target"; then continue fi - if is_logging_matrix_capacity_deferred_target "$target"; then - LOGGING_MATRIX_DEFERRED_CAPACITY_TARGETS+=("$target") - continue - fi if requires_esp32_full_cli_profile "$target"; then full_only_standard_skip_count=$((full_only_standard_skip_count + 1)) else @@ -5751,10 +5728,6 @@ run_logging_matrix_build_targets() { echo "${#LOGGING_MATRIX_DEFERRED_TARGETS[@]} standard ESP32 target(s) exceeded the portable OTA slot and were deferred to the expanded FULL pass:" printf ' %s\n' "${LOGGING_MATRIX_DEFERRED_TARGETS[@]}" fi - if [ ${#LOGGING_MATRIX_DEFERRED_CAPACITY_TARGETS[@]} -gt 0 ]; then - echo "${#LOGGING_MATRIX_DEFERRED_CAPACITY_TARGETS[@]} standard target(s) are deferred pending an approved storage-capacity decision:" - printf ' %s\n' "${LOGGING_MATRIX_DEFERRED_CAPACITY_TARGETS[@]}" - fi if [ ${#LOGGING_MATRIX_FAILURES[@]} -gt 0 ]; then echo "Logging matrix completed with ${#LOGGING_MATRIX_FAILURES[@]} failed build(s):" printf ' %s\n' "${LOGGING_MATRIX_FAILURES[@]}" diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 8392a0a8..7d086dd7 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -221,6 +221,9 @@ public: void handleCmdFrame(size_t len); bool advert(); void enterCLIRescue(); + // Physical controls must flush deferred contact writes before entering a + // board's irreversible power-off state. + bool prepareForUserShutdown() { return prepareForUiShutdown(); } #if COMPANION_FEATURE_TEXT_TERMINAL void enterTerminalMode(bool show_banner = true); diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index a0790ec9..9dc8ac36 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -228,6 +228,90 @@ MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables, store #endif ); +#if defined(WIO_E5_MINI_HEADLESS_COMPANION_UI) && defined(PIN_USER_BTN) +namespace { +// The Wio E5 mini has no display, but its single button is still useful: +// double-click sends an advert; long-press during early boot enters the USB +// rescue CLI; a later long-press powers the board off. Keep those controls +// without pulling in the display-oriented UITask and its NullDisplayDriver. +constexpr uint32_t WIO_E5_BUTTON_READ_INTERVAL_MS = 10; +constexpr uint32_t WIO_E5_BUTTON_DEBOUNCE_MS = 50; +constexpr uint32_t WIO_E5_BUTTON_MULTI_CLICK_MS = 500; +constexpr uint32_t WIO_E5_BUTTON_LONG_PRESS_MS = 3000; +constexpr uint32_t WIO_E5_RESCUE_WINDOW_MS = 8000; + +bool wio_e5_button_raw_pressed = false; +bool wio_e5_button_pressed = false; +bool wio_e5_button_long_press_handled = false; +uint8_t wio_e5_button_clicks = 0; +uint32_t wio_e5_button_last_read_at = 0; +uint32_t wio_e5_button_raw_changed_at = 0; +uint32_t wio_e5_button_pressed_at = 0; +uint32_t wio_e5_button_released_at = 0; +uint32_t wio_e5_controls_started_at = 0; + +bool wioE5ButtonPressed() { + return digitalRead(PIN_USER_BTN) == LOW; +} + +void beginWioE5HeadlessControls() { + const uint32_t now = millis(); + wio_e5_button_raw_pressed = wioE5ButtonPressed(); + wio_e5_button_pressed = wio_e5_button_raw_pressed; + // Match Button::begin(): a button already held across boot must be released + // and pressed again before it can trigger a long-press action. + wio_e5_button_long_press_handled = wio_e5_button_pressed; + wio_e5_button_raw_changed_at = now; + wio_e5_controls_started_at = now; +} + +void serviceWioE5HeadlessControls() { + const uint32_t now = millis(); + if (now - wio_e5_button_last_read_at < WIO_E5_BUTTON_READ_INTERVAL_MS) { + return; + } + wio_e5_button_last_read_at = now; + + const bool raw_pressed = wioE5ButtonPressed(); + if (raw_pressed != wio_e5_button_raw_pressed) { + wio_e5_button_raw_pressed = raw_pressed; + wio_e5_button_raw_changed_at = now; + } + + if (now - wio_e5_button_raw_changed_at > WIO_E5_BUTTON_DEBOUNCE_MS + && raw_pressed != wio_e5_button_pressed) { + wio_e5_button_pressed = raw_pressed; + if (wio_e5_button_pressed) { + wio_e5_button_pressed_at = now; + wio_e5_button_long_press_handled = false; + } else if (!wio_e5_button_long_press_handled) { + ++wio_e5_button_clicks; + wio_e5_button_released_at = now; + } + } + + if (wio_e5_button_pressed && !wio_e5_button_long_press_handled + && now - wio_e5_button_pressed_at > WIO_E5_BUTTON_LONG_PRESS_MS) { + wio_e5_button_long_press_handled = true; + wio_e5_button_clicks = 0; + if (now - wio_e5_controls_started_at < WIO_E5_RESCUE_WINDOW_MS) { + the_mesh.enterCLIRescue(); + } else if (the_mesh.prepareForUserShutdown()) { + board.powerOff(); + } + } + + if (!wio_e5_button_pressed && wio_e5_button_clicks != 0 + && now - wio_e5_button_released_at > WIO_E5_BUTTON_MULTI_CLICK_MS) { + if (wio_e5_button_clicks == 2) { + (void)the_mesh.advert(); + } + wio_e5_button_clicks = 0; + } +} +} // namespace +#endif + #if COMPANION_FEATURE_BLE_MOTA_SOURCE #include #include @@ -2992,6 +3076,9 @@ void setup() { #ifdef DISPLAY_CLASS ui_task.begin(disp, &sensors, the_mesh.getNodePrefs()); // still want to pass this in as dependency, as prefs might be moved #endif +#if defined(WIO_E5_MINI_HEADLESS_COMPANION_UI) && defined(PIN_USER_BTN) + beginWioE5HeadlessControls(); +#endif board.onBootComplete(); @@ -3044,6 +3131,9 @@ void loop() { ble_mota_source_control.loop(); #endif sensors.loop(); +#if defined(WIO_E5_MINI_HEADLESS_COMPANION_UI) && defined(PIN_USER_BTN) + serviceWioE5HeadlessControls(); +#endif #ifdef DISPLAY_CLASS #ifdef INDICATOR_WIFI_FONT_RECOVERY // The Indicator keeps rendering with its built-in fallback while a missing diff --git a/test/test_build_profiles.sh b/test/test_build_profiles.sh index d02c38af..292e43fd 100644 --- a/test/test_build_profiles.sh +++ b/test/test_build_profiles.sh @@ -813,11 +813,6 @@ for constrained_companion in \ is_logging_size_constrained_target "$constrained_companion" \ || fail "$constrained_companion enabled oversized verbose mesh diagnostics" done -is_logging_matrix_capacity_deferred_target wio-e5-mini_companion_radio_usb \ - || fail "Wio E5 Mini Companion was not deferred pending its storage decision" -if is_logging_matrix_capacity_deferred_target wio-e5-mini_repeater; then - fail "Wio E5 Mini capacity deferral expanded beyond the affected Companion" -fi if uses_merged_standard_usb_logging nrf_repeater_lora_ota_no_external_sensors; then fail "LoRa OTA repeater incorrectly merged USB logging" fi diff --git a/variants/wio-e5-mini/platformio.ini b/variants/wio-e5-mini/platformio.ini index 5404e2d0..c201c588 100644 --- a/variants/wio-e5-mini/platformio.ini +++ b/variants/wio-e5-mini/platformio.ini @@ -76,7 +76,8 @@ build_src_filter = ${lora_e5_mini.build_src_filter} [env:wio-e5-mini_companion_radio_usb] extends = lora_e5_mini platform_packages = platformio/toolchain-gccarmnoneeabi@^1.140201.0 -build_unflags = -Os +build_unflags = + -Os build_flags = ${lora_e5_mini.build_flags} -Oz -flto @@ -90,17 +91,18 @@ build_flags = ${lora_e5_mini.build_flags} -fno-asynchronous-unwind-tables -fno-schedule-insns2 -Wl,--sort-section=alignment - -I examples/companion_radio/ui-orig -D LORA_TX_POWER=22 -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 - -D DISPLAY_CLASS=NullDisplayDriver + ; This board has no display. Retain its physical-button Companion controls + ; without linking the full display-oriented UI task. + -D WIO_E5_MINI_HEADLESS_COMPANION_UI=1 + ; The optional I2C BME280 is not board-integrated; retain board voltage. + -D WIO_E5_MINI_NO_EXTERNAL_SENSORS=1 -D ENABLE_USB_INTERFACE build_src_filter = ${lora_e5_mini.build_src_filter} - + +<../examples/companion_radio/*.cpp> - +<../examples/companion_radio/ui-orig/*.cpp> -lib_deps = ${lora_e5_mini.lib_deps} +lib_deps = ${stm32_base.lib_deps} densaugeo/base64 @ ~1.4.0 [env:wio-e5-mini_kiss_modem]