Minimal, embedded-optimized implementation of the SpaceWire packet and network layers (ECSS-E-ST-50-12C) carrying the CCSDS Packet Transfer Protocol (ECSS-E-ST-50-53C).
- ECSS-E-ST-50-12C Rev.1: SpaceWire — links, nodes, routers and networks
- ECSS-E-ST-50-53C: SpaceWire — CCSDS packet transfer protocol
- ECSS-E-ST-50-51C: SpaceWire — protocol identification (Protocol ID
0x02) - CCSDS 133.0-B-2: Space Packet Protocol — the packet being carried; supplied by the application through the payload adapter, not implemented here
- Network layer: SpaceWire packets and routing — path (0–31) and logical (32–254) addressing with header deletion (ECSS-E-ST-50-12C §5.6.8)
- CCSDS Packet Transfer Protocol: encapsulation/extraction of the carried packet with EOP/EEP receive status (ECSS-E-ST-50-53C)
- Payload adapter: the carried packet is reached through three overridable hooks, so the application plugs in its own Space Packet implementation
This is a packet- and network-layer library. The character/signal and data-link levels — character encoding and parity, data-strobe signalling, link initialisation and flow control, and EOP/EEP generation and detection — are provided by the SpaceWire hardware CODEC. EOP/EEP are exchanged with this library as out-of-band metadata, not as bytes within packet buffers.
- Minimal footprint: small static library, no dynamic allocation
- Zero allocation: stack- and caller-owned buffers only
- Standalone: no external dependencies
- Portable: C99; the only compiler-specific item is the weak-symbol
attribute behind
SW_WEAK(GNU-compatible by default, overridable) - Standards-driven: no non-standard framing or checksums on the wire
EmbeddedSpaceWire/
├── include/
│ ├── spacewire.h # SpaceWire packet + network (routing) layer
│ ├── spacewire_ptp.h # CCSDS packet transfer protocol (ECSS-E-ST-50-53C)
│ └── spacewire_payload.h # Payload adapter hooks
├── src/
│ ├── spacewire_spw_packet.c # SpaceWire packet builder
│ ├── spacewire_router.c # Routing decision (address decoding, routing table)
│ ├── spacewire_ptp.c # CCSDS packet transfer protocol
│ └── weak/
│ └── spacewire_payload.c # Default (raw-octet) payload hooks, replaceable
├── docs/
│ └── space_packet_integration.md # Carrying CCSDS Space Packets
├── examples/
│ └── main.c # End-to-end usage
├── tests/
│ ├── cunit.h # Tiny C test helpers
│ ├── test_runners.h # Suite runner declarations
│ ├── test_spw_packet.c # Packet-builder tests
│ ├── test_router.c # Routing tests
│ ├── test_ptp.c # CCSDS PTP tests (+ golden wire vector)
│ ├── test_payload.c # Default payload hook tests
│ ├── test_payload_override.c # Overridden payload hooks (own binary)
│ └── unit_tests.c # Test runner
├── tools/
│ └── coverage_html.sh # HTML coverage report + 100% gate
├── .github/workflows/
│ └── ci.yml # CI: tests, coverage, sanitizers, format
├── .clang-format # Code style
├── Makefile
└── README.md
- A C99 compiler. The build must be warning-free under both gcc and clang; CI checks both.
makeandar- Optional:
gcovrfor coverage,clang-formatfor the format check
Pick the compiler with CC:
make CC=gcc
make CC=clangThe Makefile builds with -Werror and a strict warning set (-Wall -Wextra -Wpedantic -Wconversion -Wshadow and others), so any warning fails the build.
OPT sets the optimisation flags (default -O2), e.g. make OPT="-O0 -g".
Do not set CFLAGS on the command line or in the environment: it replaces the
Makefile's whole flag set, including the include path, -std=c99, -Werror and
the warnings. Use OPT for optimisation or instrumentation flags instead.
make allmake lib
# Produces: build/lib/libspacewire.a (static) and build/lib/libspacewire.so (shared)make example
./build/bin/spacewire_examplemake testTwo binaries are built and run: build/bin/spacewire_tests uses the default
payload hooks, and build/bin/spacewire_override_tests replaces them with its
own.
make sanitize
make sanitize CC=clangRebuilds the library, both test binaries and the example with AddressSanitizer
and UndefinedBehaviorSanitizer (leak detection on, every report fatal), runs
them, and prints one result line per binary. Program output is shown only on
failure. The instrumented build goes to build/sanitize/ and is removed
afterwards.
make coverage-htmlRequires gcovr. Runs make clean first, so any existing build/ output is
removed. It then builds instrumented tests in build/coverage-build/, runs
both test binaries, and writes the report to build/coverage/index.html.
Coverage of src/ must be 100% line and 100% branch; below that the
command still writes the report, then exits non-zero.
Code style is defined in .clang-format. Check every C file with:
git ls-files '*.c' '*.h' | xargs clang-format --dry-run --WerrorDrop --dry-run --Werror and add -i to reformat in place.
.github/workflows/ci.yml runs on every push to
main and on every pull request:
| Job | What it checks |
|---|---|
| Unit tests | make with gcc and with clang: libraries, both test binaries, example |
| Coverage | make coverage-html; fails below 100% line or branch; report uploaded as an artifact |
| Sanitizers | make sanitize with gcc and with clang |
| clang-format | Every tracked .c and .h file matches .clang-format |
Run the same checks locally before pushing.
make clean # Remove build/ artifacts
make distclean # Deep clean including object filesSee examples/main.c.
The packet transfer layer never looks inside the packet it carries. It sizes, serialises and parses it through three hooks declared in include/spacewire_payload.h:
| Hook | Purpose |
|---|---|
sw_payload_size() |
Serialised size of a payload object |
sw_payload_serialize() |
Write a payload object into the output buffer |
sw_payload_parse() |
Fill a payload object from a received buffer |
The library ships weak default hooks in src/weak/ that treat the payload as
raw octets (sw_payload_raw_t), so it works on its own. To carry a structured
protocol, define the same three functions in the application; they replace the
defaults at link time. An application that compiles the library sources itself
and overrides all three hooks can leave src/weak/ out of its build.
The overrides must be linked as an object file. Overrides that exist only inside a static library are silently ignored by the linker.
Because the hooks are resolved at link time, one program carries one payload
type: every sw_ptp_encode() and sw_ptp_decode() call in it uses the same
three hooks. Carrying two different protocols in one image would need the
application to dispatch on its own payload object inside the hooks.
docs/space_packet_integration.md shows the overrides for CCSDS Space Packets using EmbeddedSpacePacket.
Figures for x86-64, gcc -O2:
- Library code: ~2.3 KB (
.text, default payload hooks included); no dynamic allocation, all buffers caller-owned - Static data: 20 bytes (
.bss), the CCSDS PTP statistics block sw_ptp_frame_t: 16 bytes (CCSDS PTP addressing fields)sw_router_t: 784 bytes — a 256-entry routing table (3 B/entry) plus counters
Packet and routing operations work entirely on caller-owned state passed
by pointer and take no internal locks, so independent objects can be used from
independent tasks. The one shared item is the library's statistics block:
sw_ptp_encode and sw_ptp_decode update a process-global counter (read
via sw_ptp_get_statistics, cleared via sw_ptp_reset_statistics), which is not
thread-safe. In a multi-task system, serialise the encode/decode/statistics
calls or confine them to a single task.
The same block is shared by every link: a node with more than one SpaceWire link, such as a nominal and a redundant one, cannot read per-link figures from it and has to count per link itself.
The library implements the packet and network layers; the following are out of scope or not yet implemented:
- Character/signal and data-link levels — provided by the SpaceWire hardware CODEC
- Building and validating the carried CCSDS Space Packet — provided by the application through the payload adapter
- Time-codes, broadcast codes and distributed interrupts (ECSS-E-ST-50-12C §5.6.3–5.6.5)
- Packet forwarding: the router makes the routing decision (output port, and whether to delete the leading address); moving the packet is left to the caller or the hardware. Wormhole routing and arbitration (§5.6.8.7–5.6.8.8) are therefore out of scope
- Group adaptive routing (§5.6.8.9): one output port per logical address
- Packet multicast (§5.6.8.10)
- Routing switch reset and port time-out (§5.6.8.11–5.6.8.12)
- Guaranteed delivery — per ECSS-E-ST-50-53C the service is unconfirmed and incomplete (no acknowledgement, retransmission or QoS)
These can be added as needed for specific mission requirements.
- ECSS-E-ST-50-12C Rev.1 — SpaceWire: links, nodes, routers and networks
- ECSS-E-ST-50-53C — SpaceWire: CCSDS packet transfer protocol
- ECSS-E-ST-50-51C — SpaceWire: protocol identification
- CCSDS 133.0-B-2 — Space Packet Protocol
- https://www.spacewire.esa.int — SpaceWire website
See LICENSE file.