EXN-GS is the host-side ground-control and hardware-in-the-loop environment for the EXN avionics demonstrator. It provides a C++17 transport daemon, FTXUI operator client, command-line client, and STM32-oriented simulator for CCSDS/PUS traffic over Serial or TCP.
- CCSDSPack v2.x, with v2.0.0 as the reproducible fallback baseline;
- CCSDS Space Packet version 0;
- PUS revision A TC/TM secondary headers;
- one-octet TC source ID and zero-octet TM destination ID;
- CRC-16/CCITT-FALSE packet error control;
- TC APID = destination endpoint;
- TM APID = producing endpoint.
The mission wire contract is maintained in the ExoSpaceLabs/exn repository under docs/ICD.md and interfaces/.
graph LR
UI[exn_gsui\noperator/client tasks] -->|local IPC| D[exn_gsd\ntransport/router]
CLI[exn_gsdctl\noperations/raw packets] -->|local IPC| D
D -->|TCP| SIM[stm32_sim\nv2 endpoint simulator]
D -->|Serial| HW[Physical MCU/device]
The daemon owns infrastructure and transport operations:
- Serial/TCP device-link lifecycle;
- ordered device-link writes and reconnect handling;
- CCSDS byte-stream framing;
- structural packet validation before forwarding;
- direction-agnostic Space Packet routing between IPC clients and the device link;
- packet metadata, logging, state distribution, and transport counters over IPC.
The daemon does not own mission schedules, periodically generate housekeeping, assign mission transaction IDs, synthesize time packets, or decide which PUS application services should run.
Supported daemon operations are intentionally small:
CONNECT— open the configured device transport;DISCONNECT— close it;RECONNECT— cleanly cycle it;PING— daemon IPC liveness check, returnsPONG;STATUS— return current device-link state;STATS— return RX/TX byte/packet and decode/framing counters;PacketSend— route one complete structurally valid CCSDS Space Packet.
New IPC sessions receive both a daemon Hello and the current device-link state. The two concepts are deliberately separate: daemon IPC can be connected while the spacecraft/device link is disconnected or in error.
The UI owns operator/application behavior, including:
- CCSDSPack v2 packet construction;
- client-side packet sequence state;
- System HK transaction IDs;
- the optional periodic System HK task;
- one-shot mission requests initiated by the operator.
The UI displays Daemon IPC and Device Link independently. Daemon errors/messages are shown on the status line and do not overwrite transport state.
Current System HK behavior sends TC 3/10 every two seconds while the UI task is enabled and both daemon IPC and device link are connected. The packet is addressed to MCU APID 0x100, uses GS Source ID 0x10, and carries exactly {transactionId:u16, include_mask:u8, detailMask:u16} with no downstream proxy preamble.
The simulator validates incoming packets using the typed CCSDSPack v2 PUS-A TC parser and CRC, then emits CRC-protected PUS-A TM replies. Its current MCU identity is APID 0x100.
exn_gsd— central local transport/router daemon.exn_gsui— terminal operator client and scheduled client tasks.exn_gsdctl— command/raw-packet IPC client for operations and automation.stm32_sim— host-side MCU endpoint simulator using HardRT POSIX tasks.exn_shared— IPC framing, CCSDS framing, CCSDSPack v2 codec helpers, mission constants, and common types.
SpaceWire/SpWKit is not currently an EXN-GS dependency. A future SpaceWire transport should be another daemon transport backend and validated independently.
- CMake >= 3.20;
- C++17 compiler;
- Boost.System / Boost.Asio;
- FTXUI 5.0.0;
- CCSDSPack v2.x;
- HardRT 0.4.0 for
stm32_sim.
HardRT is pinned to the latest released version (0.4.0) rather than tracking its main branch, making clean GS builds reproducible.
On Debian/Ubuntu:
sudo apt update
sudo apt install -y build-essential cmake ninja-build libboost-dev libboost-system-devCMake first attempts:
find_package(CCSDSPack 2.0 CONFIG QUIET)If a compatible installed package is unavailable, the build fetches and installs released CCSDSPack v2.0.0 into the build tree. There are no developer-local absolute source paths.
The preferred local build entry point is:
./scripts/build_simulation.shIt configures and builds the complete simulator/HIL stack and all required dependencies:
stm32_sim;exn_gsd;exn_gsui;exn_gsdctl;exn_sharedand transitive CCSDSPack, HardRT and FTXUI dependencies;- packet regression and simulator/daemon HIL tests.
Useful variants:
# Rebuild the runtime stack without running tests.
./scripts/build_simulation.sh --no-tests
# Start from a clean build tree.
./scripts/build_simulation.sh --clean
# Select build type, build directory and parallelism.
./scripts/build_simulation.sh \
--build-type Release \
--build-dir build-release \
--jobs 8Run ./scripts/build_simulation.sh --help for all options. Existing CMake build trees retain their configured generator; for a fresh tree the script prefers Ninja when available.
The equivalent manual build remains:
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=ON
cmake --build build --parallel
ctest --test-dir build --output-on-failureTests include packet/CRC/framing regression coverage plus a simulator-daemon HIL smoke test that validates daemon handshake, device status, PING, STATS, RECONNECT, DISCONNECT, and CONNECT behavior.
./scripts/quick_test.shThe launcher reuses build_simulation.sh --no-tests if runtime artifacts are missing, then opens three terminals in dependency order:
- OBC/STM32 simulator on
127.0.0.1:9000; - GS daemon on IPC
127.0.0.1:7777, connected to the simulator; - GS UI connected to the daemon.
It waits for the simulator and daemon listeners before starting the next process. Supported terminals are gnome-terminal, konsole, kitty, and xterm. Set TERMINAL=<name> to force one or BUILD_DIR=<path> to use another build tree.
./build/sim/stm32_sim --verboseIt currently listens on 127.0.0.1:9000.
Against the simulator:
./build/daemon/exn_gsd \
--listen 127.0.0.1:7777 \
--port tcp://127.0.0.1:9000 \
--verboseAgainst a Serial device:
./build/daemon/exn_gsd \
--listen 127.0.0.1:7777 \
--port /dev/ttyACM0 \
--baud 115200 \
--verboseThe daemon may open the configured device transport automatically, but it sends no application traffic by itself.
./build/ui/exn_gsui --connect 127.0.0.1:7777UI keys:
c— open command bar;h— help while command mode is closed;q— quit while command/help is closed;Esc— close command/help.
When command mode is open it owns character input, so command text such as HK_ENABLE is not intercepted by global shortcuts.
Daemon commands:
CONNECTDISCONNECTRECONNECTPINGSTATUSSTATS
UI-owned application tasks:
HK_ENABLE— enable the two-second System HK schedule;HK_DISABLE— disable it;HK_REQ— send one System HK request immediately when the device is connected.
Transport connection state and HK task state are independent. CONNECT does not implicitly enable HK, and HK_ENABLE does not attempt to open the device link.
./build/tools/gsdctl/exn_gsdctl ping
./build/tools/gsdctl/exn_gsdctl status
./build/tools/gsdctl/exn_gsdctl stats
./build/tools/gsdctl/exn_gsdctl reconnect
./build/tools/gsdctl/exn_gsdctl raw <complete_space_packet_hex>gsdctl waits for the daemon response instead of exiting immediately after transmitting the IPC request. raw sends a complete Space Packet through the same direction-agnostic PacketSend path as other clients.
Runtime logs, build trees, and IDE state are ignored. They are not source assets and should not be committed.