Add saved raw radio2 KISS host sessions to Full firmware

This commit is contained in:
mikecarper committed 2026-10-26 16:57:49 -07:00
1 parent 8a8c80ee6a
commit cb3c92a8da
50 files changed
+2750 -74

No files matched your search

+11
View File
@@ -28,6 +28,7 @@
#include <helpers/ui/StartupScreen.h>
#include "NotificationSettingsFile.h"
#include "MyMesh.h"
#include <helpers/HostKiss.h>
#if defined(RAK_4631) && defined(COMPANION_RADIO_FULL) \
|| (defined(STM32_PLATFORM) && defined(STM32WLxx) && COMPANION_FEATURE_TEXT_TERMINAL)
#include "CompanionHelpWriter.h"
@@ -3388,6 +3389,9 @@ void MyMesh::begin(bool has_display, bool radio_available,
#endif
configureRadioFromPrefs();
#if MESH_ENABLE_HOST_KISS
mesh::hostkiss::begin(_store->getPrimaryFS(), *_radio, _radio_profiles, *this);
#endif
#if MESH_ENABLE_TX_BEACONS
beginBeacons();
#endif
@@ -10789,6 +10793,9 @@ bool MyMesh::handleCommand(const char* command, uint32_t sender_timestamp,
// router is also used by USB/BLE/browser commands without a timestamp.
if (mesh::esp32::handlePowerTestCommand(command, reply, reply_capacity,
sender_timestamp == 0)) return true;
#endif
#if MESH_ENABLE_HOST_KISS
if (mesh::hostkiss::handleCommand(command, reply, reply_capacity, sender_timestamp == 0)) return true;
#endif
if (mesh::power::handleRegulatorCommand(command, reply, reply_capacity)) return true;
#if defined(WIO_E5_MINI_HEADLESS_COMPANION_UI)
@@ -11164,6 +11171,7 @@ bool MyMesh::handleCommand(const char* command, uint32_t sender_timestamp,
}
void MyMesh::checkCLIRescueCmd() {
if (mesh::isUsbBinaryStreamOwned()) return;
Stream& output = mesh::usbTerminalPort();
Stream& input = mesh::usbCompanionPort();
size_t len = strnlen(cli_command, sizeof(cli_command));
@@ -11525,6 +11533,9 @@ void MyMesh::loop() {
#endif
if (!mesh::morseTimingActive(_radio)) _radio_profiles.loop();
#if MESH_ENABLE_HOST_KISS
if (!mesh::morseTimingActive(_radio)) mesh::hostkiss::loop();
#endif
#if MESH_ENABLE_TX_BEACONS
if (!mesh::morseTimingActive(_radio)) loopBeacons();
#endif
+4
View File
@@ -34,6 +34,7 @@
#include <helpers/MeshtextConfig.h>
#if MESH_ENABLE_ETHERNET_TUNNEL
#include <helpers/EthernetTunnelSettings.h>
#include <helpers/HostKiss.h>
#include <helpers/esp32/EthernetKissServer.h>
#endif
namespace mesh { class BeaconManager; }
@@ -443,6 +444,9 @@ protected:
// Direct-only OTA inherits the Dispatcher's drop/no-op foreign callbacks.
bool allowForeignRadioTransmit() const override {
return _radio_available && _scheduled_reboot_at == 0 && (
#if MESH_ENABLE_HOST_KISS
mesh::hostkiss::radioActive() ||
#endif
#if MESH_ENABLE_MESHTEXT_CHAT
_mt_active ||
#endif
+73 -8
View File
@@ -18,6 +18,7 @@
#include <Mesh.h>
#include <helpers/BluetoothMac.h>
#include "MyMesh.h"
#include <helpers/HostKiss.h>
#include <helpers/CompanionReader.h>
#include "CompanionBluetooth.h"
#include "CompanionWireless.h"
@@ -1050,9 +1051,21 @@ static bool serviceUsbMotaResponseBoundary() {
// loss edge, before any protocol parser runs. No line, login, recipient, queued
// text, or mOTA attachment may survive into the next host session.
static bool usb_terminal_host_reset_completion_pending = false;
#if MESH_ENABLE_HOST_KISS
static bool host_kiss_usb_parked = false;
static bool host_kiss_usb_restore_enabled = false;
#endif
static uint32_t usb_terminal_host_reset_retry_at = 0;
static void resetUsbTerminalHostSession() {
#if MESH_ENABLE_HOST_KISS
mesh::hostkiss::resetUsbSession();
if (host_kiss_usb_parked) {
mesh::setUsbBinaryStreamOwned(false);
if (host_kiss_usb_restore_enabled && interface_manager.isEnabled()) usb_serial_interface.enable();
host_kiss_usb_parked = host_kiss_usb_restore_enabled = false;
}
#endif
#if COMPANION_FEATURE_READER
mesh::cancelReaderCommand(&mesh::usbTerminalPort());
#endif
@@ -1096,6 +1109,49 @@ static void resetUsbTerminalHostSession() {
#endif
}
// A saved KISS feature takes USB only after an explicit KISS delimiter.
// Park this one Companion transport; BLE/WiFi and the primary mesh stay live.
static bool serviceCompanionHostKissUsb() {
#if MESH_ENABLE_HOST_KISS
const bool claimed = mesh::hostkiss::serviceUsb();
if (claimed && mesh::hostkiss::usbActive() && !host_kiss_usb_parked) {
host_kiss_usb_restore_enabled = usb_serial_interface.isEnabled();
cancelUsbSerialOperations();
#if COMPANION_FEATURE_READER
mesh::cancelReaderCommand(&mesh::usbTerminalPort());
#endif
the_mesh.resetUsbHostSessionInput();
#if COMPANION_FEATURE_USB_MOTA_SOURCE
if (usb_mota_mode) leaveUsbMotaMode(false);
mesh::ota::OtaContext::serialFolderSource().resetSessionState();
#endif
if (the_mesh.isTerminalMode()) leaveUsbTerminalMode(false);
usb_binary_startup_probe.cancel();
usb_ascii_session_default.cancel();
clearUsbTerminalLine();
usb_terminal_discard_line = usb_logging_terminal_mode = false;
mesh::discardUsbTerminalOutput();
usb_serial_interface.disable();
host_kiss_usb_parked = true;
}
if (host_kiss_usb_parked && !claimed && !mesh::hostkiss::usbActive()) {
mesh::setUsbBinaryStreamOwned(false);
host_kiss_usb_parked = false;
if (host_kiss_usb_restore_enabled && interface_manager.isEnabled()) usb_serial_interface.enable();
host_kiss_usb_restore_enabled = false;
clearUsbTerminalLine();
usb_terminal_discard_line = false;
usb_serial_interface.resetSessionState();
usb_ascii_session_default.request(usb_serial_interface.getCompletedFrameCount());
}
if (host_kiss_usb_parked && claimed && !mesh::hostkiss::usbActive())
mesh::setUsbBinaryStreamOwned(true); // RETURN retires at the next poll.
return claimed;
#else
return false;
#endif
}
static void serviceUsbTerminalHostSessionReset() {
#if defined(NRF52_PLATFORM) || defined(RP2040_PLATFORM) \
|| MESH_ESP32_TINYUSB_NONBLOCKING
@@ -1392,6 +1448,7 @@ static void serviceUsbTerminal() {
}
static void serviceUsbLoggingOwnership(bool logging_enabled) {
if (mesh::hostkiss::usbActive()) return;
// A saved logging-on preference makes the one available TTY behave like a
// logging repeater: plaintext diagnostics plus an input-capable CLI. Put the
// Companion interface into passthrough before it can mix framed traffic with
@@ -4199,6 +4256,7 @@ static void serviceUsbLoggingOnlySession() {
}
static bool usbLoggingRecoverySafe(void*) {
if (mesh::hostkiss::usbActive()) return false;
if (board.isOTAUpdateRunning() || board.isRadioTestActive()
|| radio_driver.isWatchdogObserving() || radio_driver.isCalibratingNoiseFloor()
|| !the_mesh.canRecoverUsbLogging()) return false;
@@ -4245,9 +4303,12 @@ void loop() {
serviceUsbLoggingOnlySession();
#if defined(ENABLE_USB_INTERFACE)
serviceUsbTerminalHostSessionReset();
serviceUsbAsciiSessionDefault();
serviceUsbLoggingReplyBarrier();
serviceUsbLoggingOwnership(mesh::isUsbLoggingEnabled()); // Before framed dispatch.
const bool host_kiss_usb_claimed = serviceCompanionHostKissUsb();
if (!host_kiss_usb_claimed) {
serviceUsbAsciiSessionDefault();
serviceUsbLoggingReplyBarrier();
serviceUsbLoggingOwnership(mesh::isUsbLoggingEnabled()); // Before framed dispatch.
}
#endif
// Identify nRF52 CDC 1 when a terminal opens it. Doing this on the connection
// edge avoids losing the marker before the host has opened the port.
@@ -4258,13 +4319,15 @@ void loop() {
mesh::serviceUsbTerminalPort();
#endif
#if defined(ENABLE_USB_INTERFACE)
expireUsbBinaryStartupProbeBeforeDispatch();
if (!host_kiss_usb_claimed) {
expireUsbBinaryStartupProbeBeforeDispatch();
#if COMPANION_FEATURE_USB_MOTA_SOURCE
serviceUsbMotaResponseBoundary();
serviceUsbMotaResponseBoundary();
#endif
}
#endif
#if defined(ENABLE_USB_INTERFACE)
syncUsbTerminalInputEditing();
if (!host_kiss_usb_claimed) syncUsbTerminalInputEditing();
#endif
the_mesh.loop();
#if defined(NRF52_PLATFORM) && defined(EXTRAFS) && !defined(QSPIFLASH)
@@ -4286,8 +4349,10 @@ void loop() {
serviceCompanionRadioRecovery();
#endif
#if defined(ENABLE_USB_INTERFACE)
serviceUsbTerminal();
syncUsbTerminalInputEditing();
if (!host_kiss_usb_claimed) {
serviceUsbTerminal();
syncUsbTerminalInputEditing();
}
// Commands can synchronously enqueue a multi-line reply. Give it the
// remaining CDC FIFO capacity now; later loops retain any unwritten suffix.
mesh::serviceUsbTerminalPort();
+30 -2
View File
@@ -17,6 +17,7 @@
#endif
#include <helpers/UsbLoggingWatchdog.h>
#include <helpers/UsbLoggingClientActivity.h>
#include <helpers/HostKiss.h>
#include <helpers/MorseLoopPolicy.h>
#include <helpers/PowerManagementUtils.h>
#include <helpers/HilStartupTrace.h>
@@ -476,14 +477,31 @@ static void __attribute__((noinline)) serviceCommandInterfaces() {
bool usb_ready = true;
#if MESH_USB_CONSOLE_COOPERATIVE
mesh::serviceUsbLoggingPort();
mesh::serviceUsbTerminalPort();
if (mesh::takeUsbTerminalSessionReset()) {
#if MESH_ENABLE_HOST_KISS
mesh::hostkiss::resetUsbSession();
#endif
command[0] = 0;
command_overflow = false;
the_mesh.cancelPendingSerialOutput();
}
#endif
#if MESH_ENABLE_HOST_KISS
// Claim binary input before a pending terminal listing can append text.
// Keep the rest of this function alive for Ethernet and board housekeeping.
if (mesh::hostkiss::serviceUsb()) {
command[0] = 0;
command_overflow = false;
#if MESH_USB_CONSOLE_COOPERATIVE
the_mesh.cancelPendingSerialOutput();
#endif
usb_ready = false;
}
#endif
#if MESH_USB_CONSOLE_COOPERATIVE
if (usb_ready) mesh::serviceUsbTerminalPort();
// A busy USB session cleanup may defer the CLI, never the radio loop.
usb_ready = mesh::tryCompleteUsbTerminalSessionReset();
usb_ready = usb_ready && mesh::tryCompleteUsbTerminalSessionReset();
// Large listings advance from MyMesh::loop without blocking radio service.
usb_ready = usb_ready && !the_mesh.hasPendingSerialOutput()
&& mesh::canAcceptUsbConsoleCommand();
@@ -614,6 +632,9 @@ static void __attribute__((noinline)) serviceCommandInterfaces() {
}
static bool usbLoggingRecoverySafe(void*) {
#if MESH_ENABLE_HOST_KISS
if (mesh::hostkiss::usbActive()) return false;
#endif
if (board.isOTAUpdateRunning() || board.isRadioTestActive()
|| radio_driver.isWatchdogObserving() || radio_driver.isCalibratingNoiseFloor()
|| !the_mesh.canRecoverUsbLogging()) return false;
@@ -670,6 +691,9 @@ void loop() {
rtc_clock.tick();
if (mesh::serviceUsbLoggingWatchdog(usbLoggingRecoverySafe)) board.reboot();
#if MESH_USB_CONSOLE_COOPERATIVE
#if MESH_ENABLE_HOST_KISS
if (!mesh::hostkiss::usbActive())
#endif
mesh::serviceUsbTerminalPort();
#endif
@@ -702,6 +726,10 @@ void loop() {
&& sleep_guard(!board.isUsbDataConnected(), mesh::powerdiag::Reason::UsbSession)
&& sleep_guard(!mesh::isUsbLoggingWatchdogArmed(), mesh::powerdiag::Reason::UsbRecovery)
&& sleep_guard(!mesh::wireless::control().pending(), mesh::powerdiag::Reason::Wireless);
#if MESH_ENABLE_HOST_KISS
can_power_save = can_power_save
&& sleep_guard(!mesh::hostkiss::usbActive(), mesh::powerdiag::Reason::UsbSession);
#endif
#if defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP) \
&& MOMENTARY_BUTTON_WAKE_FROM_SLEEP \
&& defined(PIN_USER_BTN) && defined(DISPLAY_CLASS)
+27 -2
View File
@@ -17,6 +17,7 @@
#endif
#include <helpers/UsbLoggingWatchdog.h>
#include <helpers/UsbLoggingClientActivity.h>
#include <helpers/HostKiss.h>
#include <helpers/MorseLoopPolicy.h>
#include <helpers/PowerManagementUtils.h>
#if MESH_PACKET_LOGGING
@@ -331,6 +332,9 @@ void setup() {
}
static bool usbLoggingRecoverySafe(void*) {
#if MESH_ENABLE_HOST_KISS
if (mesh::hostkiss::usbActive()) return false;
#endif
if (board.isOTAUpdateRunning() || board.isRadioTestActive()
|| radio_driver.isWatchdogObserving() || radio_driver.isCalibratingNoiseFloor()
|| !the_mesh.canRecoverUsbLogging()) return false;
@@ -355,12 +359,26 @@ void loop() {
bool usb_ready = true;
#if MESH_USB_CONSOLE_COOPERATIVE
mesh::serviceUsbLoggingPort();
mesh::serviceUsbTerminalPort();
if (mesh::takeUsbTerminalSessionReset()) {
#if MESH_ENABLE_HOST_KISS
mesh::hostkiss::resetUsbSession();
#endif
command[0] = 0;
the_mesh.cancelPendingSerialOutput();
}
usb_ready = mesh::tryCompleteUsbTerminalSessionReset();
#endif
#if MESH_ENABLE_HOST_KISS
if (mesh::hostkiss::serviceUsb()) {
command[0] = 0;
#if MESH_USB_CONSOLE_COOPERATIVE
the_mesh.cancelPendingSerialOutput();
#endif
usb_ready = false;
}
#endif
#if MESH_USB_CONSOLE_COOPERATIVE
if (usb_ready) mesh::serviceUsbTerminalPort();
usb_ready = usb_ready && mesh::tryCompleteUsbTerminalSessionReset();
usb_ready = usb_ready && !the_mesh.hasPendingSerialOutput()
&& mesh::canAcceptUsbConsoleCommand();
#endif
@@ -449,6 +467,9 @@ void loop() {
board.loop();
if (mesh::serviceUsbLoggingWatchdog(usbLoggingRecoverySafe)) board.reboot();
#if MESH_USB_CONSOLE_COOPERATIVE
#if MESH_ENABLE_HOST_KISS
if (!mesh::hostkiss::usbActive())
#endif
mesh::serviceUsbTerminalPort();
#endif
#ifdef TBEAM_1W
@@ -477,6 +498,10 @@ void loop() {
&& sleep_guard(!board.isUsbDataConnected(), mesh::powerdiag::Reason::UsbSession)
&& sleep_guard(!mesh::isUsbLoggingWatchdogArmed(), mesh::powerdiag::Reason::UsbRecovery)
&& sleep_guard(!mesh::wireless::control().pending(), mesh::powerdiag::Reason::Wireless);
#if MESH_ENABLE_HOST_KISS
can_power_save = can_power_save
&& sleep_guard(!mesh::hostkiss::usbActive(), mesh::powerdiag::Reason::UsbSession);
#endif
#if defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP) \
&& MOMENTARY_BUTTON_WAKE_FROM_SLEEP \
&& defined(PIN_USER_BTN) && defined(DISPLAY_CLASS)
+27 -3
View File
@@ -21,6 +21,7 @@
#include <helpers/UsbLogging.h>
#include <helpers/UsbLoggingWatchdog.h>
#include <helpers/UsbLoggingClientActivity.h>
#include <helpers/HostKiss.h>
#include <helpers/MorseLoopPolicy.h>
#include <helpers/PowerManagementUtils.h>
#if defined(NRF52_PLATFORM) && MESH_ENABLE_SENSOR_TRACKER
@@ -325,6 +326,9 @@ void setup() {
}
static bool usbLoggingRecoverySafe(void*) {
#if MESH_ENABLE_HOST_KISS
if (mesh::hostkiss::usbActive()) return false;
#endif
if (board.isOTAUpdateRunning() || board.isRadioTestActive()
|| radio_driver.isWatchdogObserving() || radio_driver.isCalibratingNoiseFloor()
|| !the_mesh.canRecoverUsbLogging()) return false;
@@ -343,9 +347,22 @@ void loop() {
bool usb_ready = true;
#if MESH_USB_CONSOLE_COOPERATIVE
mesh::serviceUsbLoggingPort();
mesh::serviceUsbTerminalPort();
if (mesh::takeUsbTerminalSessionReset()) command[0] = 0;
usb_ready = mesh::tryCompleteUsbTerminalSessionReset()
if (mesh::takeUsbTerminalSessionReset()) {
#if MESH_ENABLE_HOST_KISS
mesh::hostkiss::resetUsbSession();
#endif
command[0] = 0;
}
#endif
#if MESH_ENABLE_HOST_KISS
if (mesh::hostkiss::serviceUsb()) {
command[0] = 0;
usb_ready = false;
}
#endif
#if MESH_USB_CONSOLE_COOPERATIVE
if (usb_ready) mesh::serviceUsbTerminalPort();
usb_ready = usb_ready && mesh::tryCompleteUsbTerminalSessionReset()
&& mesh::canAcceptUsbConsoleCommand();
#endif
Stream& console = mesh::usbConsolePort();
@@ -405,6 +422,9 @@ void loop() {
rtc_clock.tick();
if (mesh::serviceUsbLoggingWatchdog(usbLoggingRecoverySafe)) board.reboot();
#if MESH_USB_CONSOLE_COOPERATIVE
#if MESH_ENABLE_HOST_KISS
if (!mesh::hostkiss::usbActive())
#endif
mesh::serviceUsbTerminalPort();
#endif
#ifdef HAS_EXTERNAL_WATCHDOG
@@ -430,6 +450,10 @@ void loop() {
&& sleep_guard(!morse_timing, mesh::powerdiag::Reason::Morse)
&& sleep_guard(!board.isUsbDataConnected(), mesh::powerdiag::Reason::UsbSession)
&& sleep_guard(!mesh::isUsbLoggingWatchdogArmed(), mesh::powerdiag::Reason::UsbRecovery);
#if MESH_ENABLE_HOST_KISS
can_power_save = can_power_save
&& sleep_guard(!mesh::hostkiss::usbActive(), mesh::powerdiag::Reason::UsbSession);
#endif
#if defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP) \
&& MOMENTARY_BUTTON_WAKE_FROM_SLEEP \
&& defined(PIN_USER_BTN) && defined(DISPLAY_CLASS)