Skip to content

Latest commit

 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RAD-IO2-TC Logger

neoRAD-IO2-TC logging to a FreeWili 2

Desktop temperature logger for the Intrepid neoRAD-IO2-TC thermocouple module (8 isolated K-type banks). Native C++20, SDL3 + Dear ImGui, talks to the module through Intrepid's libneoradio2 over USB HID. Windows, Linux and macOS.

This is stage 1 of two: a cross-platform GUI. Stage 2 is the same logger running on a Free-WiLi 2; see "Stage 2" below.

What it does

  • Finds attached RAD-IO2 chains (plus a built-in Simulator entry so the app can be tried with no hardware).
  • Connect → identifies the chain, starts application firmware on every bank, shows per-bank type, serial and firmware version.
  • Polls all banks at a configurable interval (0.1 s – 60 s), shows the thermocouple temperature and, when the firmware reports it, the cold junction temperature, in °C or °F.
  • Strip chart of the last N seconds (up to 4 h kept in memory) with per-bank toggles, auto-scale, hover readout.
  • CSV logging: one row per poll, all banks, wall-clock timestamp + elapsed seconds. Rows are flushed as written, so pulling the cable never loses more than one row. Files default to logs/ beside the executable.

CSV columns: timestamp,elapsed_s,bank1_tc_C..bank8_tc_C,bank1_cj_C..bank8_cj_C (unit suffix follows the unit chosen when logging was started; banks without a module leave the cell empty).

Build

Needs CMake ≥ 3.24, Ninja, a C++20 compiler, git (dependencies are fetched). Linux additionally needs libudev-dev and the usual X11/Wayland dev headers for SDL.

git clone --recursive https://github.com/freewili/radio2tc.git

(the freewili/wilibsp submodule is only needed for stage 2; the desktop build works without it).

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build        # runs the console test binaries

The finished, portable application is the folder build/stage/:

stage/
  radio2tc(.exe)
  assets/99-intrepidcs.rules
  README.md
  logs/                       created on first run

Copy that folder anywhere and run it. SDL3, ImGui, libneoradio2, hidapi and the C++ runtime are linked statically (MSVC: /MT); no redistributable is needed. All runtime paths are resolved from the executable's own directory.

Linux: device permissions

/dev/hidraw* is root-only by default. Install the udev rule once:

sudo cp assets/99-intrepidcs.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules && sudo udevadm trigger

then unplug/replug the module. Until this is done the device shows up in the list but Connect fails with a permission error.

Layout

src/main.cpp          SDL/ImGui bootstrap and the frame loop
src/app/              state, ring buffer, CSV logger, poller thread,
                      simulator — no ImGui, no OS calls
src/platform/         libneoradio2 backend, executable-relative paths
src/ui/               all drawing (reads a Snapshot, never owns state)
tests/                console tests (ring buffer, CSV, poller)
assets/               udev rule, staged beside the binary

The device is driven on a worker thread (app::Poller); the UI copies a Snapshot each frame, so a slow USB read can never stall rendering. Failures are bool + error string, never exceptions.

How the module is read

Sequence per libneoradio2: neoradio2_findopenchain_identifyapp_start(0, 0xFF) (modules boot into the bootloader) → per bank get_device_type/serial/firmware. Each poll is one request_sensor_data(0, 0xFF, ENABLED) followed by read_sensor_array per present bank; the first 4 bytes are the calibrated temperature as a little-endian float in °C, and a second float, when present, is the cold-junction temperature. The firmware tested (module IA0372) returns only the 4-byte value and reports an unconnected thermocouple as -1000 °C; the app shows that as "open (no probe)" and leaves the CSV cell empty.

Stage 2: Free-WiLi 2

freewili/ holds the FreeWili 2 port — freewili/README.md explains how it works, with screenshots.

The graph page running on a FreeWili 2: two live probes, 1 min/div, soft-menu bar

The RAD-IO2-TC plugs straight into the FreeWili 2 USB-A port: its FT260 HID-to-UART bridge is driven by the display CPU through the RP2350's native USB host, using the same feature-report setup and 250 kbaud framing that libneoradio2 uses on the PC. Readings go to the LCD — bank list or a live strip chart, FW2 soft-menu bar labelling the physical buttons (graph/rate/log/unit/clock) and to timestamped /appdata/radio2tc/*.csv files on the SD card; freewili/tools/set_clock.py seeds the clock from the PC.

Shared between both stages: src/radio2/protocol.* — the RAD-IO2 frame encoder/parser, CRC-8 and FT260 report packing, unit-tested by tests/test_protocol.cpp on the host.

cd freewili && ./build.sh                                   # -> build/radio2tc.uf2
python wilibsp/tools/fw.py install-app build/radio2tc.uf2   # copy to SD:/apps

Status: verified on a FreeWili 2 with the real module on 2026-08-25 (enumeration, 8-bank identify, polling with live readings from two probes, screen, buttons, SD logging and read-back); see freewili/docs/findings/.

License

MIT — see LICENSE. Vendored third-party components (SEGGER RTT, FatFs) keep their own permissive licenses, listed in THIRD-PARTY-NOTICES.md and in the vendored file headers. Drivers reused from other FreeWili 2 repositories carry the MIT/BSD-3-Clause terms noted in their file headers.

About

Thermocouple logger for the Intrepid neoRAD-IO2-TC (8 isolated K-type banks), in two stages: a cross-platform SDL3/ImGui desktop app, and a FreeWili 2 (RP2350B) port that drives the module's FT260 bridge over native USB host and logs to the SD card - live strip chart, soft-menu bar, software wall clock.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages