Skip to content

feat: HostSim live telemetry, PWM scope, and SPWM demo for NodeGUI - #3

Open
hibyemy wants to merge 32 commits into
OpenVVVF:mainfrom
hibyemy:feat/hostsim-live-telemetry
Open

feat: HostSim live telemetry, PWM scope, and SPWM demo for NodeGUI#3
hibyemy wants to merge 32 commits into
OpenVVVF:mainfrom
hibyemy:feat/hostsim-live-telemetry

Conversation

@hibyemy

@hibyemy hibyemy commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds live HostSim ↔ NodeGUI telemetry over InverterProtocol (IVP) TCP, an optional PWM scope simulator for gate-level waveform inspection, and an SPWM demo with one-click launch. It builds on the HostSim base image work already on this branch.

What was done (by area)

HostSim (Images/HostSim/)

  • Live TCP telemetrytelemetry_publisher.cpp/h publishes IVP signal frames on port 14608 when run with --live.
  • PWM scope simulatorpwm_scope.cpp/h models triangle-carrier PWM in parallel with the motor plant, emitting pwm_gate_* and pwm_v_* signals for oscilloscope-style plots.
  • Split telemetry tiers — plant signals (duty_*, i_*, theta, etc.) publish every plant cycle; PWM scope signals publish on a separate, speed-scaled rate via EffectivePwmTelemHz() (caps flood at ~1500 Hz).
  • Sim speed / pause over TCPmain.cpp uses GlobalSimRuntime() so NodeGUI speed and pause commands affect the running loop (fixes speed slider having no effect).
  • SPWM helperplatform_spwm_step() in platform_api.h/cpp for scalar SPWM from node graphs.
  • SPWM demo assetsgraphs/spwm_demo_graph.json, scenarios/spwm_demo.json, and scripts/run_spwm_live.ps1 (emit, build, launch HostSim + NodeGUI).

InverterProtocol (Lib/InverterProtocol/)

  • TCP transporttcp_transport.cpp/h for HostSim server and NodeGUI client.
  • Multi-frame recv fix — TCP client now queues all COBS frames per recv() call (was dropping frames after the first, causing connect/disconnect loops in NodeGUI).
  • host_client.cpp — drains all queued packets per loop iteration before sleeping.

NodeGUI (Source/NodeGUI/src/runtime/)

  • Ingress coalescingpwm_gate_* uses edge-preserving accumulation (every 0↔1 transition kept); other pwm_* coalesced to last value; plant signals pass through every sample. Prevents queue overflow without destroying gate edges.
  • TelemetryStore — batch AddF32Batch(), 60 s / 20k retention, history freeze on pause.
  • SignalPlotWidget — proper step geometry for digital gates, fixed 0–1 Y axis, pause freezes plot time, higher point budget for gates.
  • TelemetryPanel / RuntimeTab — 40 ms plot refresh, hide empty graphs, per-graph view windows, SPWM preset layout button, compact PAUSED / RX rate status chips.
  • SimSpeedControl — UI slider wired to IVP speed command.
  • CLI--tcp host:port and --protocol ivp for HostSim live mode; --protocol legacy remains the default for real Gen6/Nucleo firmware.

VVVF / OpenVVVF compatibility

This work is additive and does not change how VVVF control graphs drive the inverter:

Concern Status
platform_pwm_set() / platform_pwm_set_voltage_vector() Unchanged — FOC, SVPWM, and scalar paths still use the same APIs
Real hardware telemetry Unchanged — Legacy UART is still the default NodeGUI protocol
Default HostSim scenario (default_motor.json) No pwm_scope block — PWM scope is opt-in via scenario JSON only
SPWM demo Optional — separate scenario/graph and Runtime → SPWM preset; does not affect FOC/VVVF graphs
IVP/TCP HostSim live path only — new transport layer; does not replace firmware UART
FOC example graphs (Assets/Examples/foc_demo.json, foc_chain.json) Compatible — no graph or node type changes required

The PWM scope is a HostSim visualization aid for switched waveforms. It runs alongside the existing motor model and is only enabled when a scenario includes a "pwm_scope" block (as in spwm_demo.json).

Bug fixes included

  • Connect/disconnect loop (TCP multi-frame handling)
  • Speed slider not affecting running sim (GlobalSimRuntime)
  • PWM gate aliasing / zigzags (edge-preserving ingress vs min/max batch coalescing)
  • Plot lag (PWM telemetry rate cap, ingress coalescing, batched store writes, decoupled plot refresh timer)
  • Duty trace only at right edge (plant signals no longer dropped by coalescing)

Test plan

  • Images/HostSim builds (host_sim.exe)
  • Source/NodeGUI builds
  • SPWM live demo:
    powershell -File Images\HostSim\scripts\run_spwm_live.ps1
    Connect NodeGUI (or let script launch it), Runtime → SPWM preset, verify gate traces on Graph 1 (~40 ms window), duty/current on Graphs 2–3.
  • Default motor (VVVF-style, no PWM scope):
    Images\HostSim\build\Debug\host_sim.exe --scenario Images\HostSim\scenarios\default_motor.json --live --tcp 127.0.0.1:14608
    build\Source\NodeGUI\NodeGUI.exe --tcp 127.0.0.1:14608 --protocol ivp
    Verify plant telemetry (duty_*, currents) without pwm_gate_* flood.
  • Pause freezes plot time; Resume continues; speed slider changes sim rate.
  • Legacy UART path still works with --serial / default protocol (no regression on real hardware workflow).

hibyemy and others added 24 commits August 6, 2026 18:08
Adds Images/NucleoL476FW — a minimal RTE-compatible base firmware image
for the ST Nucleo-L476RG (Cortex-M4F @ 80 MHz). It follows the same
contracts as Gen6FW (RTE_EMIT markers, platform_api, STM32CubeMX CMake
target) so NodeGUI graphs can be emitted and built without the full
OpenVVVF hardware.

Includes:
- TIM1 center-aligned 3-phase complementary PWM at 10 kHz with 1 us DT
- tim_isr + app_loop timing domains
- baseline_graph.json proving codegen end-to-end (60/35/85% duties)
- Build/flash/emit PowerShell scripts
- Vendored CMSIS + STM32L4 HAL subset
- SPI2 pins reserved for future FPGA join

This is a lab/validation target, not a production inverter image.
Sensor, telemetry, and safety paths are stubbed.

Co-authored-by: Cursor <cursoragent@cursor.com>
Absorb origin/main NodeGUI telemetry/runtime-inspection work (signal plots, RuntimeController, Legacy + InverterProtocol clients) and introduce Images/HostSim: an RTECodeEmitter-compatible host simulator with PMSM plant, throttle injection, CSV traces, and emit-and-run scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
HostSim publishes InverterProtocol over TCP for NodeGUI live mode, with an
optional PWM scope (triangle carrier gate signals) alongside the existing
plant telemetry (duty, currents, theta). Adds SPWM demo graph/scenario and
run_spwm_live.ps1. NodeGUI gains IVP TCP client fixes, edge-preserving PWM
gate rendering, pause/freeze, sim speed control, and SPWM plot presets.

VVVF/FOC compatibility: platform_pwm_set and platform_pwm_set_voltage_vector
are unchanged; pwm_scope is scenario-opt-in; Legacy UART telemetry remains
the default for real hardware.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keeps default_motor and FOC/VVVF HostSim runs on plant telemetry only;
SPWM demo and other scenarios enable pwm_scope via JSON.

Co-authored-by: Cursor <cursoragent@cursor.com>
- ConsolePanel gains a Plant row: backend combo (ode fast / ngspice
  accurate), render duration / ISR Hz / substeps spin boxes, and
  Apply Backend / Render SPICE buttons that send the corresponding
  HostSim console commands
- Increase signal plot sample buffers (60k/120k) for longer capture
  windows
Checkpoint of in-progress master-agent work (stopped mid-refactor, builds
clean, ngspice_tiny passes):

- NgspicePlant: free-running tran throttled by CallbackGetSyncData
  (sync_allow_time_/sync_actual_time_/sync_waiting_) with deltatime
  clamping to tick boundaries; replaces bg_halt/bg_resume stepping that
  cost ~107 ms per pause (0.05 s sim: 3m37s -> 0.26s). bg_halt remains
  only as Reset/shutdown hatch. WaitOnAddress futex handshake in
  progress.
- Netlist: huge tstop for open-ended live sessions (tstep must stay
  <= smallest sub_dt or stepping collapses).
- telemetry_publisher: console commands plant backend/render/reset,
  WriteAll bounded at 100 ms so a non-reading client is dropped
  instead of stalling the sim, fflush on command/connect/disconnect
  output.
- sim_runtime/main: --plant-backend/--duration/--tim-isr-hz/--substeps
  CLI overrides, RecreatePlant default netlist.
- New scenarios fast_ode/accurate_spice + render_spice scripts; README
  documents the fast/accurate two-view and the harmonic sizing rule.
Enables reproducible live-ceiling sweeps, e.g.
python scripts/live_check.py 8 scenarios/ngspice_short.json 4.0 --substeps 1

With the WaitOnAddress futex handshake (bf4833a), live ngspice co-sim
tracks 1.0x realtime with ~2x headroom (measured ceiling 2.09x at
substeps=4, 2.44x at substeps=1); batch 0.05 s sim in ~0.19 s.
- Merge origin/main into hostsim-live-telemetry-clean and resolve
  NodeGUI runtime conflicts (session export + sim pause/speed features).
- Remove broken run_svpwm_live.ps1 (referenced deleted NucleoL476FW).
- Add Linux-native run_spwm_live.sh and run_live.sh.
- Make MainWindow BuildSimulation cross-platform (SPWM script on Win/Linux).
- Document HostSim SIL architecture: compiled firmware + OdePlant default,
  NgspicePlant experimental.
Using pkill -f 'NodeGUI' matched the NodeGUI process that launched the
script via Build -> Build Simulation, causing an instant 'terminated' crash.
Switch to pgrep -x for exact-name matching and stop killing NodeGUI from
the build-simulation script entirely.
…me layout

- Add missing platform_api stubs so the FOC demo graph builds in HostSim:
  platform_get_motor_rpm, platform_phase_voltage_u/v/w,
  platform_get_throttle_valid, platform_digital_read/write,
  platform_can_send/rx.
- Make run_spwm_live.sh/.ps1 accept --graph/--scenario so any graph can be
  emitted/built/run, defaulting to a matching scenario or default_motor.json.
- Wire NodeGUI Build Simulation to pass the currently loaded graph to the
  launcher instead of hardcoding the SPWM demo graph.
- Add a FOC runtime plot preset (cg_id_a/iq_a, cg_vd_v/vq_v, cg_iu_a/iv_a/iw_a)
  and auto-select it when cg_id_a telemetry is present.
…ncher scripts, fix NodeGUI argument passing, dynamic pole pairs, and class-based parameterInputs
…tes and remove unused compiler warning variable
…e (sincos_lut, clarke, park, svpwm), testbenches, and MCU SPI2 driver
…eo SPWM demo graph

Adds a first-order LADRC dq-current regulator node (drop-in for Control.Pi)
with Vdc-aware output clamping, plus human-readable descriptions for the
CanTx node and its ports. (WIP left by Gemini session, reviewed and committed.)
…admap

- agent-log/: shared session journal for LLM agents (README convention +
  entries for the 2026-08-04 Gemini session and the 2026-08-05 Kimi fork
  sync/rebase/audit session, plus the full module audit report)
- docs/ROADMAP_HYBRID_NUCLEO_FPGA.md: pivot from simulation-first to hybrid
  MCU+FPGA (Gowin IDE toolchain); Phases 1-3, asset inventory, open questions
- README: fork-direction note linking both
Stray '=======' + duplicated BUILD_NODEGUI block survived the rebase onto
19dbb08; upstream's block already carries the option. Also logs the second
rebase in agent-log.
@hibyemy
hibyemy force-pushed the feat/hostsim-live-telemetry branch from b294763 to d1dddfc Compare August 7, 2026 01:44
hibyemy added 3 commits August 6, 2026 18:45
- All stats writes under stats_mtx_ (rx_bytes race); cb_stats_ gets a locked snapshot
- UART port read failures distinguishable via readFailed() -> dead reconnect loop works
- writeRaw bounded by 2s WouldBlock deadline instead of spinning forever
- getaddrinfo resolution (hostnames like localhost, not just IPv4 literals)
- Baud parameter plumbed through on Windows and POSIX (was ignored, 460800 hardcoded)
- Named constants for buffer sizes and the console key; reject_decode wired
- Remove dead idle-check block in pumpTransport
- Graph::Connect rejects double-connected input ports; RemoveNodeType refuses with live instances
- LoadIntoGraph propagates Add/Connect failures instead of silently dropping items
- NodeTemplates: top-level *.json templates load, accurate counters, zero types = failure,
  hardened filesystem/JSON error handling, no re-serialize round-trip
- Logger: thread-safe (mutex + localtime_r/localtime_s), ParseLevel warns on unknown level
- Remove committed fw_test.bin test artifact
hibyemy added 5 commits August 7, 2026 00:21
- error_code overloads with clean errors for create_directories/copy_file/relative
  (incl. base-tree copy loop and directory iterators)
- Boolean params accept only true/false/1/0; unknown-typed params error instead of
  silently appending 'f'; chmod 0644 not 0777 on generated files
- Out-of-range RTE_EMIT marker warns instead of dropping silently; MarkerParser
  splits domain/section on tabs too
- Runtime env override (RTE_INVERTERCODEGEN_INCLUDE_DIR/_THIRD_PARTY_DIR) for
  build-machine paths baked into the emitter binary
- ReadFile distinguishes open failure from empty file; drop dead variable
- tests: fixtures declare parameterTypes (strict undeclared-param rejection)
- Preferences -> Build -> Firmware target combo (Gen6FW/NucleoL476FW/HostSim),
  persisted via QSettings; threaded into the rte CLI --base-source via
  FirmwareBaseDir() (Gen6FW remains the default)
- BuildSimulation wiring: setWorkingDirectory before start(), explicit
  cliStage_=None for the one-shot path, clear stale cliOutputBuffer_
- migrate_graph_ids.py: deduplicate ID_MAP, single __main__ passes templates_dir
  resolved from the script location (template canonicalization was dead code)
- can_session_client.py: length guards on START frames and decode_packet
- fram_keys.py: .9g float round-trip, pyserial hint, named timeout constants
- sim_device.py: POSIX guard with clear message, --rate validation
- test_fram_keys.py: sys.path relative to the test file
- launch_*.bat: %~dp0-relative paths, %PORT% variable, timeout instead of ping-sleep
- --templatesDir -> --templates (RTECodeEmitter CLI flag; the wrong flag broke
  Build & Reflect in Simulator at the emit step)
- run_spwm_live.sh finds host_sim.exe under Debug/Release subdirs (MSVC
  multi-config) as well as the build root
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants