Minimal ECSS Packet Utilisation Standard (PUS) implementation in C, designed for small-scale academic space missions.
Zero dynamic allocation, no global state, C99 with C++-compatible headers — and 100% line & branch test coverage.
- ECSS-E-ST-70-41C: Packet Utilisation Standard (PUS)
| Service | Name | Subtypes |
|---|---|---|
| ST[01] | Request Verification | Acceptance, Start, Completion (success & failure), Routing failure; Progress reports must be emitted manually by the handler |
| ST[03] | Housekeeping | TM[3,25] HK report, TM[3,26] diagnostic report |
| ST[05] | Event Reporting | Info, Low/Medium/High severity |
| ST[17] | Test | TC[17,1] are-you-alive, TC[17,3] on-board connection test |
| ST[20] | Parameter Management | TC[20,1] request report, TC[20,3] set values, TM[20,2] value report |
- Transport-agnostic — a pure PUS layer operating on the secondary header and application data; wrap its packets in a CCSDS Space Packet primary header or carry them in CCSDS SDLP TC/TM transfer frames
- No heap — all memory is caller-supplied or statically declared
- No global state — everything lives in a
pus_context_tyou own - Composable — each service has its own context struct; mix and match what you need
- Portable C — no platform-specific dependencies
- C99, C++-friendly — compiles as C99; every public header is wrapped in
extern "C"for direct use from C++
EmbeddedPUS/
├── include/ # Public API headers
├── src/ # Library source + internal headers
├── example/
│ └── obc_example.c # Minimum OBC usage example
├── tests/ # Unit tests (single file per module) + minimal framework
├── tools/
│ └── coverage_html.sh # Coverage report generator
├── docs/ # ECSS-E-ST-70-41C reference (PDF)
├── Makefile
├── LICENSE
└── README.md
make # build and run tests
make example # build and run the OBC example
make clean # remove build artifactsmake compiles and runs the full unit-test suite under a strict warning set
(-Wall -Wextra -Wpedantic -Wconversion and more). Coverage is maintained at 100% of
lines and branches; regenerate the report with gcovr:
sudo apt install gcovr
make coverage-html
# Prints a console summary and writes an HTML report to build/coverage/index.html#include "pus.h"
#include "pus_service_17.h"
#include "pus_service_3.h"
#include "pus_service_5.h"
/* 1. Allocate contexts statically */
static pus_context_t g_pus;
static pus_service_3_ctx_t g_s3;
/* 2. TM sink — called for every outgoing packet */
static pus_status_t uart_send(void *ud, const uint8_t *data, uint16_t len)
{
(void)ud;
/* write data[0..len] to your UART / radio */
return PUS_STATUS_OK;
}
/* 3. HK provider — fill the housekeeping buffer on demand */
static pus_status_t hk_provider(uint16_t sid, uint8_t *buf,
uint16_t cap, uint16_t *out_len, void *ud)
{
(void)sid; (void)cap; (void)ud;
buf[0] = read_temperature();
*out_len = 1u;
return PUS_STATUS_OK;
}
void app_init(void)
{
/* 4. Initialise */
pus_config_t cfg = {0};
cfg.default_source_id = 0x0001;
cfg.tm_sink = uart_send;
pus_init_with_config(&g_pus, &cfg);
/* 5. Register service handlers */
pus_service_17_register_handlers(&g_pus); /* auto-respond to ping */
pus_service_3_init(&g_s3);
pus_service_3_register_hk(&g_s3, 0x0001, hk_provider, NULL);
}
void app_on_tc_received(const uint8_t *raw, uint16_t len)
{
/* 6. Decode, route, verify — all in one call */
pus_tc_process(&g_pus, raw, len);
}
void app_periodic(void)
{
/* 7. Emit periodic housekeeping */
pus_service_3_emit_hk(&g_pus, &g_s3, 0x0001u);
/* 8. Emit an event */
pus_service_5_emit(&g_pus, PUS_5_1_EVENT_INFO, 0x0101u, NULL, 0u);
}See example/obc_example.c for a more complete scenario covering all five services.
- Code size: ~7.8 kB
.textfor all services (x86-64-O2, unstripped; varies by target and flags) - Per-context RAM:
sizeof(pus_context_t)— handler table + counters - No heap: zero dynamic allocation; all buffers are caller-supplied
- Single-threaded:
pus_context_tis not thread-safe; protect with a mutex if used from multiple tasks - Fixed-capacity tables: handler slots and service contexts are bounded by
PUS_MAX_TC_HANDLERS,PUS_SERVICE_3_MAX_STRUCTURES,PUS_SERVICE_20_MAX_PARAMS(all overridable at compile time via-D)
- ECSS-E-ST-70-41C — Telemetry and Telecommand Packet Utilization, European Cooperation for Space Standardization (local copy)
Licensed under the Apache License 2.0. See LICENSE.