feat(shell): add interactive shell and console testing framework#4
feat(shell): add interactive shell and console testing framework#4
Conversation
There was a problem hiding this comment.
Pull request overview
Dieses PR erweitert die Simulations- und Shell-Infrastruktur von OpenDriveHub um eine interaktive Konsole inkl. End-to-End-Console-Tests und trennt die TX-Simulation in Headless- und GUI-Variante, um CI und lokale Nutzung klarer/robuster zu machen.
Changes:
- Neue Shell-Library (
odh-shell) mit Command-Registry, Line-Editing/History, Tokenizer sowie eingebauten Commands (u.a.help,exitim Sim). - Neue Console-Test-Suite (Pytest) inkl. PTY-Transport für Simulationen und Serial-Transport für echte Hardware; plus Unity-Tests für den Tokenizer.
- Build/Docs/CI:
sim_txwird headless, neuessim_tx_guifür SDL2/LVGL; CI baut beide Varianten separat.
Reviewed changes
Copilot reviewed 33 out of 41 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| firmware/test/test_native/test_shell.cpp | Neue Unity-Tests für shellTokenize() (Whitespace/Quotes/Edge-Cases). |
| firmware/test/test_native/test_protocol.cpp | Registriert die neuen Shell-Tokenizer-Tests im zentralen Unity-Test-Runner. |
| firmware/test/test_console/transport.py | Transport-Abstraktion + PTY-Subprocess-Transport und pyserial-Transport für Console-Tests. |
| firmware/test/test_console/test_startup.py | Startup-/Shutdown-Tests inkl. Prompt, Banner und exit (nur Simulation). |
| firmware/test/test_console/test_help.py | Prüft, dass help erwartete Commands listet. |
| firmware/test/test_console/test_commands_tx.py | TX-spezifische Command-Tests (bind/trim/module/disconnect). |
| firmware/test/test_console/test_commands_rx.py | RX-spezifische Command-Tests (vehicle/channel set). |
| firmware/test/test_console/test_commands_common.py | Gemeinsame Command-Tests (unknown/empty/status/config/channel). |
| firmware/test/test_console/requirements.txt | Python-Abhängigkeiten für Console-Test-Suite. |
| firmware/test/test_console/console.py | High-Level Console-Wrapper (Prompt-Wait, Echo-Strip, Command-Helper). |
| firmware/test/test_console/conftest.py | Pytest-CLI, Marker/Skips, Build-Helper (pio run -e …) und Console-Fixture. |
| firmware/test/test_console/pycache/transport.cpython-313.pyc | (Sollte nicht versioniert sein) Bytecode-Artefakt. |
| firmware/test/test_console/pycache/test_startup.cpython-313-pytest-9.0.2.pyc | (Sollte nicht versioniert sein) Bytecode-Artefakt. |
| firmware/test/test_console/pycache/test_help.cpython-313-pytest-9.0.2.pyc | (Sollte nicht versioniert sein) Bytecode-Artefakt. |
| firmware/test/test_console/pycache/test_commands_rx.cpython-313-pytest-9.0.2.pyc | (Sollte nicht versioniert sein) Bytecode-Artefakt. |
| firmware/test/test_console/pycache/console.cpython-313.pyc | (Sollte nicht versioniert sein) Bytecode-Artefakt. |
| firmware/test/test_console/pycache/conftest.cpython-313-pytest-9.0.2.pyc | (Sollte nicht versioniert sein) Bytecode-Artefakt. |
| firmware/test/test_console/README.md | Doku für Console-Test-Framework (Targets, Architektur, Troubleshooting). |
| firmware/src/transmitter/shell/TransmitterShellCommands.h | TX Shell-Command-Registrierung (Header). |
| firmware/src/transmitter/shell/TransmitterShellCommands.cpp | TX Shell-Commands (status/bind/disconnect/channel/trim/module/config). |
| firmware/src/transmitter/TransmitterApp.h | Shell-Integration + Accessors für Commands + Headless-Guards/Helper. |
| firmware/src/transmitter/TransmitterApp.cpp | Startet Shell-Task; Headless-Mode übernimmt Teile aus Display-Task; Trim/Snapshot-Helpers. |
| firmware/src/receiver/shell/ReceiverShellCommands.h | RX Shell-Command-Registrierung (Header). |
| firmware/src/receiver/shell/ReceiverShellCommands.cpp | RX Shell-Commands (status/channel/config/vehicle). |
| firmware/src/receiver/ReceiverApp.h | Shell-Integration + Accessors für Commands + setVehicleName(). |
| firmware/src/receiver/ReceiverApp.cpp | Startet Shell-Task + Implementierung setVehicleName() + Shell-Loop. |
| firmware/sim/src/sim_arduino.cpp | Simulation: unbuffered I/O, Raw-Terminal-Input via /dev/tty + Reader-Thread. |
| firmware/sim/include/Arduino.h | Simulation: Serial-Ringbuffer (stdin-reader) + Output-Stream Auswahl (stdout vs /dev/tty). |
| firmware/sim/README.md | Doku-Update: sim_tx headless, sim_tx_gui SDL2, neue Hinweise/URLs. |
| firmware/platformio.ini | Neue Environment-Definition sim_tx_gui; sim_tx wird headless mit -DODH_HEADLESS. |
| firmware/lib/odh-shell/Shell.h | Neue Shell-API + Tokenizer-API, Command-Registry, Prompt/History/Exit (sim). |
| firmware/lib/odh-shell/Shell.cpp | Implementierung Tokenizer + Shell-Poll/Line-Editing/History/Dispatch + help/exit. |
| firmware/lib/odh-config/Config.h | Neue Shell-Konstanten (Poll-Intervall + Task-Config). |
| docs/index.md | Simulation-Command-Beispiele an headless sim_tx angepasst. |
| docs/getting-started.md | Getting-started aktualisiert für sim_tx vs sim_tx_gui. |
| docs/architecture.md | Architektur-Doku aktualisiert (3 Sims + Build-Commands); enthält Tippfehler im Pfad. |
| README.md | Root-README: sim_tx Beschreibung auf headless angepasst. |
| .github/workflows/ci.yml | CI baut nun sim_tx (headless) und sim_tx_gui (SDL2) getrennt. |
| .github/copilot-instructions.md | Doku/Instruktionen aktualisiert (neue Envs, CI-Jobs, SDL2 nur für GUI). |
docs/architecture.md
Outdated
| ## Build Environments | ||
|
|
||
| The unified `firmwave/platformio.ini` defines five environments: | ||
| The unified `firmwave/platformio.ini` defines six environments: |
There was a problem hiding this comment.
Im Pfad ist ein Tippfehler: firmwave/platformio.ini existiert nicht; gemeint ist firmware/platformio.ini. Bitte korrigieren, damit die Doku-Build-Anweisungen stimmen.
| The unified `firmwave/platformio.ini` defines six environments: | |
| The unified `firmware/platformio.ini` defines six environments: |
| if (xSemaphoreTake(_funcMux, pdMS_TO_TICKS(10)) == pdTRUE) { | ||
| _inputMap[idx].trim = value; | ||
| if (idx < _funcValueCount) | ||
| _funcValues[idx].trim = value; | ||
| xSemaphoreGive(_funcMux); | ||
| } | ||
|
|
||
| // Persist | ||
| NvsStore nvs("odh", false); | ||
| NvsStore nvsr("odh", true); | ||
| uint8_t m = nvsr.getU8("model_type", static_cast<uint8_t>(ModelType::Generic)); | ||
| char ek[16]; | ||
| snprintf(ek, sizeof(ek), "imape_%u", m); | ||
| nvs.putBytes(ek, _inputMap, _inputMapCount * sizeof(InputAssignment)); | ||
| return true; |
There was a problem hiding this comment.
In setTrim() wird auch dann true zurückgegeben und der Input-Map-Block in NVS persistiert, wenn xSemaphoreTake(_funcMux, …) fehlschlägt. In diesem Fall wurde _inputMap[idx].trim ggf. gar nicht aktualisiert, aber der Caller bekommt trotzdem Erfolg gemeldet und es wird potentiell ein inkonsistenter/alter Zustand gespeichert. Lösung: bei fehlendem Semaphore-Take einen Fehler zurückgeben (oder retry), und nur dann persistieren, wenn das Update unter Lock tatsächlich durchgeführt wurde (inkl. ggf. Separierung von Update+Persist mit klarer Fehlerbehandlung).
| #include "OdhWebServer.h" | ||
| #include "OutputManager.h" | ||
| #include "ReceiverRadioLink.h" | ||
| #include "Shell.h" |
There was a problem hiding this comment.
Neuer Include nutzt Anführungszeichen ("Shell.h"). Für Shared-Lib-Header verwendet das Repo ansonsten konsistent #include <Shell.h> (z.B. firmware/src/transmitter/TransmitterApp.cpp und firmware/src/receiver/ReceiverApp.cpp). Bitte hier ebenfalls <Shell.h> verwenden, um Include-Search-Order-Probleme zu vermeiden und die Konvention einzuhalten.
| #include "Shell.h" | |
| #include <Shell.h> |
This pull request introduces a major enhancement to the simulation and shell infrastructure, primarily by adding a new headless transmitter simulation environment (
sim_tx), splitting the SDL2 GUI simulation into its own environment (sim_tx_gui), and implementing a robust shell console for command-line interaction. Documentation and CI workflows have been updated to reflect and support these changes.Simulation environments and build system updates:
Added a new
sim_tx_guienvironment for transmitter simulation with SDL2 GUI, and redefinedsim_txas a headless (terminal-only) simulation. Documentation, build instructions, and CI workflows are updated to distinguish between these environments and clarify their usage. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14]CI workflow (
.github/workflows/ci.yml) now separately builds and tests bothsim_tx(headless) andsim_tx_gui(SDL2 GUI), ensuring both simulation modes are validated in continuous integration. [1] [2]Shell console implementation:
firmware/lib/odh-shell/Shell.cpp, featuring command registration, input handling (with history and line editing), and built-in commands (help,exitfor simulation). The shell is configurable via new constants inConfig.h. [1] [2]Documentation improvements:
docs/architecture.md,docs/getting-started.md,README.md,.github/copilot-instructions.md,docs/index.md) to describe the new simulation environments, usage instructions, and the distinction between headless and GUI transmitter simulations. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]Configuration additions:
Config.hfor easier tuning and platform adaptation.These changes collectively improve simulation flexibility, developer experience, and documentation clarity.