From b14693314cfa94f16be23a3f389ffc537c7b946b Mon Sep 17 00:00:00 2001 From: Michal Pogorzelec Date: Sun, 21 Jun 2026 18:45:17 +0200 Subject: [PATCH 1/3] add example --- Makefile | 18 ++- example/obc_example.c | 285 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 example/obc_example.c diff --git a/Makefile b/Makefile index 6e07145..5d40830 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,9 @@ CFLAGS ?= -O2 -std=c11 \ -Wcast-align -Wcast-qual -Wpointer-arith -Wformat=2 \ -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wundef -BUILD_DIR = build -CTEST_PATH = $(BUILD_DIR)/tests/ctest +BUILD_DIR = build +CTEST_PATH = $(BUILD_DIR)/tests/ctest +EXAMPLE_PATH = $(BUILD_DIR)/example/obc_example SRC_FILES = $(wildcard src/*.c) TEST_FILES = $(wildcard tests/*.c) @@ -14,7 +15,7 @@ TEST_FILES = $(wildcard tests/*.c) SRC_OBJS = $(patsubst src/%.c, $(BUILD_DIR)/src/%.o, $(SRC_FILES)) TEST_OBJS = $(patsubst tests/%.c, $(BUILD_DIR)/tests/%.o, $(TEST_FILES)) -.PHONY: all ctest clean +.PHONY: all ctest example clean all: ctest @@ -33,6 +34,17 @@ $(BUILD_DIR)/tests/%.o: tests/%.c mkdir -p $(dir $@) $(CC) $(CFLAGS) -c -o $@ $< +example: $(EXAMPLE_PATH) + $(EXAMPLE_PATH) + +$(EXAMPLE_PATH): $(SRC_OBJS) $(BUILD_DIR)/example/obc_example.o + mkdir -p $(dir $@) + $(CC) $(CFLAGS) -o $@ $^ + +$(BUILD_DIR)/example/%.o: example/%.c + mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c -o $@ $< + clean: rm -rf $(BUILD_DIR) diff --git a/example/obc_example.c b/example/obc_example.c new file mode 100644 index 0000000..5b3514f --- /dev/null +++ b/example/obc_example.c @@ -0,0 +1,285 @@ +/* + * EmbeddedPUS example — small satellite OBC + * + * Scenario: a CubeSat OBC receives TC commands over a UART link and sends TM + * packets back over the same link (half-duplex). This file shows how to wire + * up all five PUS services in a realistic but self-contained program. + * + * Services used: + * ST[01] Request Verification — emitted automatically by pus_tc_process() + * ST[03] Housekeeping — periodic temperature + battery report + * ST[05] Event Reporting — mode-change and low-battery alerts + * ST[17] Test (are-you-alive) — handled automatically after register + * ST[20] Parameter Management — ground can read/set an alert threshold + * + * All memory is statically allocated; no heap is used. + */ + +#include "pus.h" +#include "pus_service_3.h" +#include "pus_service_5.h" +#include "pus_service_17.h" +#include "pus_service_20.h" +#include "pus_services.h" + +#include +#include +#include /* printf — replace with your platform output */ + +/* ----------------------------------------------------------------------- + * Platform stubs — replace these with real hardware drivers + * ----------------------------------------------------------------------- */ + +static uint32_t platform_uptime_seconds(void *ud) +{ + /* Real OBC: read the mission elapsed time counter. */ + (void)ud; + static uint32_t t = 0u; + return t++; +} + +static int16_t platform_read_temperature_c10(void) +{ + /* Real OBC: read ADC, convert to 1/10 °C units (e.g. 235 = 23.5 °C). */ + return 235; +} + +static uint16_t platform_read_battery_mv(void) +{ + /* Real OBC: read battery monitor register. */ + return 7400u; +} + +static void platform_uart_send(const uint8_t *data, uint16_t len) +{ + /* Real OBC: DMA-transfer data to the UART transmit buffer. */ + printf("[TM %3u bytes] ", (unsigned)len); + for (uint16_t i = 0u; i < len && i < 16u; i++) { + printf("%02X ", data[i]); + } + if (len > 16u) { printf("..."); } + printf("\n"); +} + +/* ----------------------------------------------------------------------- + * TM sink: called by pus_tm_build() for every outgoing TM packet + * ----------------------------------------------------------------------- */ + +static pus_status_t tm_sink(void *ud, const uint8_t *data, uint16_t len) +{ + (void)ud; + platform_uart_send(data, len); + return PUS_STATUS_OK; +} + +/* ----------------------------------------------------------------------- + * Mission constants + * ----------------------------------------------------------------------- */ + +#define OBC_SOURCE_ID 0x0001u /* this OBC's APID */ +#define GROUND_DEST_ID 0x0010u /* default ground station APID */ + +/* HK structure IDs (ST[03]) */ +#define SID_POWER_HK 0x0001u +#define SID_THERMAL_HK 0x0002u + +/* Event IDs (ST[05]) */ +#define EVID_MODE_NOMINAL 0x0101u +#define EVID_BATTERY_LOW 0x0201u + +/* Parameter IDs (ST[20]) */ +#define PID_BATT_ALERT_MV 0x0001u /* battery low-alert threshold [mV] */ + +/* ----------------------------------------------------------------------- + * Parameter store — the actual values that ST[20] reads and writes + * ----------------------------------------------------------------------- */ + +static uint16_t g_batt_alert_mv = 6800u; /* alert below 6.8 V */ + +static pus_status_t getter_batt_alert(uint16_t pid, uint8_t *buf, + uint16_t cap, void *ud) +{ + (void)pid; (void)cap; (void)ud; + buf[0] = (uint8_t)(g_batt_alert_mv >> 8u); + buf[1] = (uint8_t)(g_batt_alert_mv & 0xFFu); + return PUS_STATUS_OK; +} + +static pus_status_t setter_batt_alert(uint16_t pid, const uint8_t *buf, + uint16_t len, void *ud) +{ + (void)pid; (void)len; (void)ud; + g_batt_alert_mv = (uint16_t)((uint16_t)(buf[0] << 8u) | buf[1]); + return PUS_STATUS_OK; +} + +/* ----------------------------------------------------------------------- + * HK providers — called by pus_service_3_emit_hk() when TM[3,25] is due + * ----------------------------------------------------------------------- */ + +static pus_status_t hk_power_provider(uint16_t sid, uint8_t *buf, + uint16_t cap, uint16_t *out_len, + void *ud) +{ + (void)sid; (void)cap; (void)ud; + uint16_t mv = platform_read_battery_mv(); + buf[0] = (uint8_t)(mv >> 8u); + buf[1] = (uint8_t)(mv & 0xFFu); + *out_len = 2u; + return PUS_STATUS_OK; +} + +static pus_status_t hk_thermal_provider(uint16_t sid, uint8_t *buf, + uint16_t cap, uint16_t *out_len, + void *ud) +{ + (void)sid; (void)cap; (void)ud; + int16_t temp = platform_read_temperature_c10(); + buf[0] = (uint8_t)((uint16_t)temp >> 8u); + buf[1] = (uint8_t)((uint16_t)temp & 0xFFu); + *out_len = 2u; + return PUS_STATUS_OK; +} + +/* ----------------------------------------------------------------------- + * EmbeddedPUS contexts — statically allocated + * ----------------------------------------------------------------------- */ + +static pus_context_t g_pus; +static pus_service_3_ctx_t g_s3; +static pus_service_20_ctx_t g_s20; + +/* ----------------------------------------------------------------------- + * Initialisation + * ----------------------------------------------------------------------- */ + +static void pus_app_init(void) +{ + /* --- Core context --- */ + pus_config_t cfg; + memset(&cfg, 0, sizeof(cfg)); + cfg.default_source_id = OBC_SOURCE_ID; + cfg.default_destination_id = GROUND_DEST_ID; + cfg.tm_sink = tm_sink; + cfg.time_source = platform_uptime_seconds; + pus_init_with_config(&g_pus, &cfg); + + /* --- ST[17]: auto-respond to TC[17,1] are-you-alive --- */ + pus_service_17_register_handlers(&g_pus); + + /* --- ST[03]: housekeeping structures --- */ + pus_service_3_init(&g_s3); + pus_service_3_register_hk(&g_s3, SID_POWER_HK, hk_power_provider, NULL); + pus_service_3_register_hk(&g_s3, SID_THERMAL_HK, hk_thermal_provider, NULL); + + /* --- ST[20]: on-board parameters --- */ + pus_service_20_init(&g_s20); + pus_service_20_register_param(&g_s20, PID_BATT_ALERT_MV, 2u, + getter_batt_alert, setter_batt_alert, NULL); + pus_service_20_register_handlers(&g_pus, &g_s20); + + /* Announce nominal mode via ST[05] */ + pus_service_5_emit(&g_pus, PUS_SUBTYPE_EVENT_INFO, + EVID_MODE_NOMINAL, NULL, 0u); +} + +/* ----------------------------------------------------------------------- + * Periodic housekeeping downlink (call every HK cycle, e.g. every 10 s) + * ----------------------------------------------------------------------- */ + +static void pus_app_send_housekeeping(void) +{ + pus_service_3_emit_hk(&g_pus, &g_s3, SID_THERMAL_HK); + pus_service_3_emit_hk(&g_pus, &g_s3, SID_POWER_HK); + + /* Low-battery check: emit ST[05] alert if below threshold */ + if (platform_read_battery_mv() < g_batt_alert_mv) { + uint8_t aux[2]; + uint16_t mv = platform_read_battery_mv(); + aux[0] = (uint8_t)(mv >> 8u); + aux[1] = (uint8_t)(mv & 0xFFu); + pus_service_5_emit(&g_pus, PUS_SUBTYPE_EVENT_HIGH_SEVERITY, + EVID_BATTERY_LOW, aux, sizeof(aux)); + } +} + +/* ----------------------------------------------------------------------- + * TC receive path (call when a raw TC frame arrives from the uplink) + * ----------------------------------------------------------------------- */ + +static void pus_app_receive_tc(const uint8_t *raw, uint16_t len) +{ + /* + * pus_tc_process() decodes the TC secondary header, looks up the + * handler registered for (service, subtype), calls it, and emits + * TM[1,x] verification reports according to the TC ack_flags. + * + * Unrecognised commands receive a TM[1,10] routing failure report. + */ + pus_tc_process(&g_pus, raw, len); +} + +/* ----------------------------------------------------------------------- + * Demo main — simulates a few loop iterations without real hardware + * ----------------------------------------------------------------------- */ + +int main(void) +{ + pus_app_init(); + + printf("\n--- HK cycle 1 ---\n"); + pus_app_send_housekeeping(); + + /* + * Simulate an incoming TC[17,1] are-you-alive. + * Wire format: version=1 in top nibble, ack_flags=0, svc=17, sub=1, + * source_id=0x0010 (ground station), rest zeroed. + */ + static const uint8_t tc_17_1[] = { + 0x10, /* (version=1 << 4) | ack=0 */ + 17u, /* service */ + 1u, /* subtype */ + 0x00, 0x10, /* source_id = 0x0010 */ + 0x00, 0x00, 0x00, 0x00, 0x00 /* time + spare */ + }; + printf("\n--- Ground TC[17,1] are-you-alive ---\n"); + pus_app_receive_tc(tc_17_1, sizeof(tc_17_1)); + + /* + * Simulate TC[20,1] — request parameter report for PID_BATT_ALERT_MV. + * Payload: N=1, PID=0x0001 + */ + static const uint8_t tc_20_1[] = { + 0x10, /* version=1, no ack */ + 20u, /* service */ + 1u, /* subtype */ + 0x00, 0x10, /* source_id */ + 0x00, 0x00, 0x00, 0x00, 0x00, /* time + spare */ + 0x01, /* N = 1 parameter */ + 0x00, 0x01 /* PID = 0x0001 */ + }; + printf("\n--- Ground TC[20,1] request parameter report ---\n"); + pus_app_receive_tc(tc_20_1, sizeof(tc_20_1)); + + /* + * Simulate TC[20,3] — set PID_BATT_ALERT_MV to 7000 mV (0x1B58). + * Payload: N=1, PID=0x0001, value=0x1B58 + */ + static const uint8_t tc_20_3[] = { + 0x1F, /* version=1, all ack flags set */ + 20u, /* service */ + 3u, /* subtype */ + 0x00, 0x10, /* source_id */ + 0x00, 0x00, 0x00, 0x00, 0x00, /* time + spare */ + 0x01, /* N = 1 parameter */ + 0x00, 0x01, /* PID = 0x0001 */ + 0x1B, 0x58 /* new value = 7000 mV */ + }; + printf("\n--- Ground TC[20,3] set battery alert threshold to 7000 mV ---\n"); + pus_app_receive_tc(tc_20_3, sizeof(tc_20_3)); + + printf("\n--- HK cycle 2 (threshold now 7000 mV, 7400 mV battery is OK) ---\n"); + pus_app_send_housekeeping(); + + return 0; +} From 399eff6ce71b7a126311027f13aa8c83d1887155 Mon Sep 17 00:00:00 2001 From: Michal Pogorzelec Date: Sun, 21 Jun 2026 18:53:23 +0200 Subject: [PATCH 2/3] update readme --- README.md | 204 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 117 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index 74b9e98..d522949 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # EmbeddedPUS -Minimal ECSS Packet Utilisation Standard (PUS) protocol implementation in C for small-scale space missions. - +Minimal ECSS Packet Utilisation Standard (PUS) implementation in C, designed for small-scale academic space missions. ## Standards Compliance @@ -8,143 +7,174 @@ Minimal ECSS Packet Utilisation Standard (PUS) protocol implementation in C for ## Features -### Core Protocol Implementation +### Implemented Services +| Service | Name | Subtypes | +|---------|------|----------| +| ST[01] | Request Verification | Acceptance, Start, Progress, Completion (success & failure), Routing failure | +| 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 | ### Design Principles +- **No heap** — all memory is caller-supplied or statically declared +- **No global state** — everything lives in a `pus_context_t` you own +- **Composable** — each service has its own context struct; mix and match what you need +- **Portable C** — no platform-specific dependencies ## Project Structure ``` -EmbeddedSpacePacket/ -├── include/ -│ └── -├── src/ -│ └── -├── examples/ -│ └── +EmbeddedPUS/ +├── include/ # Public API headers +├── src/ # Library source files +├── example/ +│ └── obc_example.c # CubeSat OBC usage example ├── tests/ -│ ├── cunit.h # Minimal test framework -│ └── unit_tests.c # Unit tests +│ ├── cunit.h # Minimal test framework +│ └── unit_tests.c # Test entry point ├── tools/ -│ └── coverage_html.sh # Coverage report -├── build/ # Build artifacts +│ └── coverage_html.sh # Coverage report generator +├── build/ # Build artifacts (generated) ├── Makefile └── README.md ``` ## Building -### Build Everything - -```bash -make -``` - -Builds the static library, the example binary and the test binary in `build/`. - -### Build Library Only - ```bash -make lib -# Produces: build/ +make # build and run tests +make example # build and run the OBC example +make clean # remove build artifacts ``` -### Build Example - -```bash -make example -./build/examples/example -``` +### Coverage Report -### Run Tests - -```bash -make ctest -``` - -### Coverage (HTML) - -Requires `gcovr` installed in your system: +Requires `gcovr`: ```bash sudo apt install gcovr -``` - -Generate coverage report: - -```bash make coverage-html -``` - -Output report: - -```bash -build/coverage/index.html -``` - -### Clean - -```bash -make clean +# Output: build/coverage/index.html ``` ## Quick Start -### Step 1 - -```c - -``` - -### Step 2 - ```c - -``` - -### Step X - +#include "pus.h" +#include "pus_service_17.h" +#include "pus_service_3.h" +#include "pus_service_5.h" +#include "pus_service_20.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, 0x0001); + + /* 8. Emit an event */ + pus_service_5_emit(&g_pus, PUS_SUBTYPE_EVENT_INFO, 0x0101, NULL, 0); +} +``` + +See [example/obc_example.c](example/obc_example.c) for a more complete scenario covering all five services. ## API Reference ### Lifecycle ```c - +pus_status_t pus_init(pus_context_t *ctx); +pus_status_t pus_init_with_config(pus_context_t *ctx, const pus_config_t *config); +pus_status_t pus_set_tm_sink(pus_context_t *ctx, pus_tm_sink_t sink, void *user_data); ``` -### Building a Packet +### TC / TM ```c +/* Decode a raw TC buffer into a packet view (zero-copy) */ +pus_status_t pus_tc_decode(const uint8_t *data, uint16_t len, pus_tc_packet_t *tc); -``` - -### Utilities - -```c +/* Decode, route, and process a TC; emits ST[01] verification automatically */ +pus_status_t pus_tc_process(pus_context_t *ctx, const uint8_t *data, uint16_t len); +/* Build and emit a TM packet; calls the configured TM sink */ +pus_status_t pus_tm_build(pus_context_t *ctx, pus_service_t service, + pus_subtype_t subtype, uint16_t destination_id, + const uint8_t *payload, uint16_t payload_len, + uint8_t *out, uint16_t out_capacity, uint16_t *out_len); ``` -### Types +### Handler Registration ```c - +/* Register a TC handler callback for (service, subtype) */ +pus_status_t pus_handler_register(pus_context_t *ctx, + pus_service_t service, pus_subtype_t subtype, + pus_tc_handler_t handler, void *user_data); ``` -## Memory Usage (Estimated) - -- **Library (stripped)**: -- **Serialization buffer**: -- **No heap usage**: all allocations are caller-supplied +## Memory -## CCSDS XXX — Notes +- **Code size**: ~7.7 kB (text segment, all services, unstripped) +- **Per-context RAM**: `sizeof(pus_context_t)` — handler table + counters +- **No heap**: zero dynamic allocation; all buffers are caller-supplied ## Limitations +- No CCSDS Space Packet primary header (library operates on the PUS secondary header and payload layer only) +- Single-threaded: `pus_context_t` is 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`) + ## References +- ECSS-E-ST-70-41C — *Telemetry and Telecommand Packet Utilization*, European Cooperation for Space Standardization + ## License -See LICENSE file. \ No newline at end of file +See [LICENSE](LICENSE). From 226ec45d1d17c6088f69c23fc1d359e762839386 Mon Sep 17 00:00:00 2001 From: Michal Pogorzelec Date: Sun, 21 Jun 2026 19:04:48 +0200 Subject: [PATCH 3/3] update doxygen --- include/pus.h | 47 +++++++++++++++++---- include/pus_codec.h | 54 +++++++++++++++++++++--- include/pus_config.h | 12 +++--- include/pus_context.h | 91 +++++++++++++++++++++++++++++----------- include/pus_handler.h | 20 +++++++-- include/pus_service_1.h | 54 +++++++++++++++++++----- include/pus_service_17.h | 27 +++++++++--- include/pus_service_20.h | 75 ++++++++++++++++++++++++++------- include/pus_service_3.h | 80 ++++++++++++++++++++++++++++------- include/pus_service_5.h | 14 ++++--- include/pus_services.h | 78 +++++++++++++++++++--------------- include/pus_types.h | 82 ++++++++++++++++++++---------------- 12 files changed, 464 insertions(+), 170 deletions(-) diff --git a/include/pus.h b/include/pus.h index 902dc06..9281fb3 100644 --- a/include/pus.h +++ b/include/pus.h @@ -10,8 +10,13 @@ #include "pus_handler.h" /** - * Decode a raw TC secondary header and expose a payload view. - * No bytes are copied; tc->payload points into the caller's buffer. + * @brief Decode a raw TC secondary header and expose a zero-copy payload view. + * + * @param[in] data Input byte buffer. + * @param[in] len Buffer length in bytes. + * @param[out] tc Decoded packet; payload points into data. + * + * @return PUS_STATUS_NULL, PUS_STATUS_BAD_LENGTH, PUS_STATUS_BAD_VERSION, or PUS_STATUS_OK. */ pus_status_t pus_tc_decode( const uint8_t *data, @@ -19,8 +24,15 @@ pus_status_t pus_tc_decode( pus_tc_packet_t *tc); /** - * Decode, route, and process a raw TC buffer. - * Emits Service 1 verification reports via the context TM sink based on ACK flags. + * @brief Decode, route, and process a raw TC buffer. + * Emits ST[01] verification reports according to the TC ack_flags. + * Unrecognised commands receive a TM[1,10] routing failure report. + * + * @param[in,out] ctx Active PUS context. + * @param[in] data Incoming TC byte buffer. + * @param[in] len Buffer length in bytes. + * + * @return Handler return value, or PUS_STATUS_NO_HANDLER if no match was found. */ pus_status_t pus_tc_process( pus_context_t *ctx, @@ -28,8 +40,21 @@ pus_status_t pus_tc_process( uint16_t len); /** - * Build an encoded TM secondary header plus payload into a caller-owned buffer. - * Increments the context message counter and forwards the packet to the TM sink. + * @brief Build an encoded TM packet into a caller-owned buffer and forward it to ctx->tm_sink. + * Increments the message counter on success. + * @note If payload is NULL and payload_len > 0, the payload region is zero-filled. + * + * @param[in,out] ctx Active PUS context. + * @param[in] service Service type identifier. + * @param[in] subtype Service subtype identifier. + * @param[in] destination_id Destination APID written into the TM header. + * @param[in] payload Application payload bytes (may be NULL to zero-fill). + * @param[in] payload_len Payload length in bytes. + * @param[out] out Caller-supplied output buffer. + * @param[in] out_capacity Output buffer size in bytes. + * @param[out] out_len Receives the number of bytes written. + * + * @return PUS_STATUS_NULL, PUS_STATUS_BUFFER_TOO_SMALL, or PUS_STATUS_OK. */ pus_status_t pus_tm_build( pus_context_t *ctx, @@ -42,7 +67,15 @@ pus_status_t pus_tm_build( uint16_t out_capacity, uint16_t *out_len); -/** Set or replace the TM sink. Pass NULL to disable automatic forwarding. */ +/** + * @brief Set or replace the TM sink. Pass NULL to disable forwarding. + * + * @param[in,out] ctx Active PUS context. + * @param[in] sink New TM sink callback (may be NULL). + * @param[in] user_data Opaque pointer forwarded to the sink on every call. + * + * @return PUS_STATUS_NULL if ctx is NULL, PUS_STATUS_OK otherwise. + */ pus_status_t pus_set_tm_sink( pus_context_t *ctx, pus_tm_sink_t sink, diff --git a/include/pus_codec.h b/include/pus_codec.h index a7320ef..bb34262 100644 --- a/include/pus_codec.h +++ b/include/pus_codec.h @@ -7,12 +7,16 @@ #include "pus_types.h" #include "pus_context.h" -/* - * Fill TM secondary header fields that are common to every outgoing TM packet. - * msg_type_counter is read from ctx->tm_counter but NOT incremented here — - * callers must do ctx->tm_counter++ only after all error paths are cleared and - * the packet is confirmed emitted. This single definition replaces the - * duplicated 8-line block that previously appeared in every service file. +/** + * @brief Populate a TM secondary header with fields common to every outgoing packet. + * @note msg_type_counter is read from ctx->tm_counter but NOT incremented here; + * callers must increment after all error paths are cleared. + * + * @param[in] ctx Active PUS context (provides counter and time source). + * @param[out] hdr Header struct to fill. + * @param[in] service Service type identifier. + * @param[in] subtype Service subtype identifier. + * @param[in] dest_id Destination APID. */ static inline void pus_tm_hdr_fill( pus_context_t *ctx, @@ -32,22 +36,60 @@ static inline void pus_tm_hdr_fill( hdr->spare = 0u; } +/** + * @brief Decode a raw TC secondary header from a byte buffer. + * + * @param[in] data Input byte buffer. + * @param[in] len Buffer length in bytes (must be >= PUS_TC_SEC_HEADER_LEN). + * @param[out] header Output struct. + * + * @return PUS_STATUS_NULL, PUS_STATUS_BAD_LENGTH, PUS_STATUS_BAD_VERSION, or PUS_STATUS_OK. + */ pus_status_t pus_tc_sec_header_decode( const uint8_t *data, uint16_t len, pus_tc_sec_header_t *header); +/** + * @brief Encode a TC secondary header into a byte buffer. + * + * @param[in] header Header struct to encode. + * @param[out] out Output byte buffer. + * @param[in] out_capacity Output buffer size (must be >= PUS_TC_SEC_HEADER_LEN). + * @param[out] out_len Receives the number of bytes written. + * + * @return PUS_STATUS_NULL, PUS_STATUS_BUFFER_TOO_SMALL, or PUS_STATUS_OK. + */ pus_status_t pus_tc_sec_header_encode( const pus_tc_sec_header_t *header, uint8_t *out, uint16_t out_capacity, uint16_t *out_len); +/** + * @brief Decode a raw TM secondary header from a byte buffer. + * + * @param[in] data Input byte buffer. + * @param[in] len Buffer length in bytes (must be >= PUS_TM_SEC_HEADER_LEN). + * @param[out] header Output struct. + * + * @return PUS_STATUS_NULL, PUS_STATUS_BAD_LENGTH, or PUS_STATUS_OK. + */ pus_status_t pus_tm_sec_header_decode( const uint8_t *data, uint16_t len, pus_tm_sec_header_t *header); +/** + * @brief Encode a TM secondary header into a byte buffer. + * + * @param[in] header Header struct to encode. + * @param[out] out Output byte buffer. + * @param[in] out_capacity Output buffer size (must be >= PUS_TM_SEC_HEADER_LEN). + * @param[out] out_len Receives the number of bytes written. + * + * @return PUS_STATUS_NULL, PUS_STATUS_BUFFER_TOO_SMALL, or PUS_STATUS_OK. + */ pus_status_t pus_tm_sec_header_encode( const pus_tm_sec_header_t *header, uint8_t *out, diff --git a/include/pus_config.h b/include/pus_config.h index c8ebf36..de47052 100644 --- a/include/pus_config.h +++ b/include/pus_config.h @@ -1,33 +1,33 @@ #ifndef PUS_CONFIG_H #define PUS_CONFIG_H +/** @brief PUS version written into every outgoing TM packet. */ #ifndef PUS_VERSION -/** @brief PUS version value written into every outgoing TM packet. */ #define PUS_VERSION 1u #endif +/** @brief Maximum TC handler entries per context. Override with -DPUS_MAX_TC_HANDLERS=N. */ #ifndef PUS_MAX_TC_HANDLERS -/** @brief Maximum registered TC handler entries per context. */ #define PUS_MAX_TC_HANDLERS 16u #endif +/** @brief Maximum TM application payload length in bytes. Override with -DPUS_MAX_TM_PAYLOAD_LEN=N. */ #ifndef PUS_MAX_TM_PAYLOAD_LEN -/** @brief Maximum TM application payload length in bytes. */ #define PUS_MAX_TM_PAYLOAD_LEN 256u #endif +/** @brief Maximum TC application payload length in bytes. Override with -DPUS_MAX_TC_PAYLOAD_LEN=N. */ #ifndef PUS_MAX_TC_PAYLOAD_LEN -/** @brief Maximum TC application payload length in bytes. */ #define PUS_MAX_TC_PAYLOAD_LEN 256u #endif +/** @brief Maximum HK/diagnostic structures per ST[03] context. Override with -DPUS_SERVICE_3_MAX_STRUCTURES=N. */ #ifndef PUS_SERVICE_3_MAX_STRUCTURES -/** @brief Maximum number of HK+diagnostic structures per Service 3 context. */ #define PUS_SERVICE_3_MAX_STRUCTURES 8u #endif +/** @brief Maximum registered parameters per ST[20] context. Override with -DPUS_SERVICE_20_MAX_PARAMS=N. */ #ifndef PUS_SERVICE_20_MAX_PARAMS -/** @brief Maximum number of registered parameters per Service 20 context. */ #define PUS_SERVICE_20_MAX_PARAMS 16u #endif diff --git a/include/pus_context.h b/include/pus_context.h index cf342a1..7cc957f 100644 --- a/include/pus_context.h +++ b/include/pus_context.h @@ -8,56 +8,97 @@ /** @brief Forward declaration so callbacks can reference the context type. */ typedef struct pus_context pus_context_t; -/** @brief Handler callback invoked by pus_tc_process() for a matched TC. */ +/** + * @brief TC handler callback invoked by pus_tc_process() for a matched command. + * + * @param[in,out] ctx Active PUS context. + * @param[in] tc Decoded TC packet. + * @param[in,out] user_data Opaque pointer supplied at registration. + * + * @return PUS_STATUS_OK on success; any other value triggers a completion failure report. + */ typedef pus_status_t (*pus_tc_handler_t)( pus_context_t *ctx, const pus_tc_packet_t *tc, void *user_data); -/** @brief Sink callback that receives every encoded TM packet from pus_tm_build(). */ +/** + * @brief TM sink callback that receives every encoded TM packet from pus_tm_build(). + * + * @param[in,out] user_data Opaque pointer supplied at registration. + * @param[in] data Encoded packet bytes. + * @param[in] len Packet length in bytes. + * + * @return PUS_STATUS_OK on success. + */ typedef pus_status_t (*pus_tm_sink_t)( void *user_data, const uint8_t *data, uint16_t len); /** - * Optional time source callback. Returns a 32-bit timestamp (seconds or - * mission ticks). If NULL, pus_tm_build() writes zero into the time field. + * @brief Optional time source callback. + * + * @param[in,out] user_data Opaque pointer supplied at registration. + * + * @return Current mission time (seconds or ticks). Zero is written when NULL. */ typedef uint32_t (*pus_time_source_t)(void *user_data); /** @brief One entry in the TC handler dispatch table. */ typedef struct { - pus_service_t service; - pus_subtype_t subtype; - pus_tc_handler_t handler; - void *user_data; - uint8_t is_used; + pus_service_t service; /**< Service type identifier. */ + pus_subtype_t subtype; /**< Service subtype identifier. */ + pus_tc_handler_t handler; /**< Handler function pointer. */ + void *user_data; /**< Opaque pointer forwarded to the handler. */ + uint8_t is_used; /**< Non-zero when the slot is occupied. */ } pus_handler_entry_t; -/** @brief Optional configuration passed to pus_init_with_config(). */ +/** + * @brief Optional configuration passed to pus_init_with_config(). + * Zero-initialise and set only the fields you need. + */ typedef struct { - uint16_t default_source_id; - uint16_t default_destination_id; - pus_tm_sink_t tm_sink; - void *tm_sink_user_data; - pus_time_source_t time_source; - void *time_source_user_data; + uint16_t default_source_id; /**< APID of this node. */ + uint16_t default_destination_id; /**< Default ground station APID. */ + pus_tm_sink_t tm_sink; /**< TM output callback (may be NULL). */ + void *tm_sink_user_data; /**< Forwarded to tm_sink. */ + pus_time_source_t time_source; /**< Timestamp callback (may be NULL). */ + void *time_source_user_data; /**< Forwarded to time_source. */ } pus_config_t; -/** @brief Runtime state for an EmbeddedPUS instance. Allocate statically. */ +/** + * @brief Runtime state for one EmbeddedPUS instance. + * Allocate statically or on the stack; do not share across threads without a mutex. + */ struct pus_context { - pus_handler_entry_t handler_table[PUS_MAX_TC_HANDLERS]; - uint16_t tm_counter; - uint16_t default_source_id; - uint16_t default_destination_id; - pus_tm_sink_t tm_sink; - void *tm_sink_user_data; - pus_time_source_t time_source; - void *time_source_user_data; + pus_handler_entry_t handler_table[PUS_MAX_TC_HANDLERS]; /**< TC dispatch table. */ + uint16_t tm_counter; /**< Outgoing TM message counter. */ + uint16_t default_source_id; /**< APID of this node. */ + uint16_t default_destination_id; /**< Default destination APID. */ + pus_tm_sink_t tm_sink; /**< TM output callback. */ + void *tm_sink_user_data; /**< Forwarded to tm_sink. */ + pus_time_source_t time_source; /**< Timestamp callback. */ + void *time_source_user_data; /**< Forwarded to time_source. */ }; +/** + * @brief Initialise a context with all-zero defaults and no TM sink. + * + * @param[out] ctx Context to initialise. + * + * @return PUS_STATUS_NULL if ctx is NULL, PUS_STATUS_OK otherwise. + */ pus_status_t pus_init(pus_context_t *ctx); + +/** + * @brief Initialise a context and copy fields from a configuration struct. + * + * @param[out] ctx Context to initialise. + * @param[in] config Configuration to copy from. + * + * @return PUS_STATUS_NULL if either pointer is NULL, PUS_STATUS_OK otherwise. + */ pus_status_t pus_init_with_config(pus_context_t *ctx, const pus_config_t *config); #endif /* PUS_CONTEXT_H */ diff --git a/include/pus_handler.h b/include/pus_handler.h index a55bb37..e76f172 100644 --- a/include/pus_handler.h +++ b/include/pus_handler.h @@ -4,8 +4,16 @@ #include "pus_context.h" /** - * Register or update a TC handler for a (service, subtype) pair. - * Updating an existing pair replaces the handler and user_data in place. + * @brief Register or update a TC handler for a (service, subtype) pair. + * If the pair is already registered, the handler and user_data are replaced. + * + * @param[in,out] ctx Active PUS context. + * @param[in] service Service type identifier. + * @param[in] subtype Service subtype identifier. + * @param[in] handler Callback invoked when a matching TC is received. + * @param[in] user_data Opaque pointer forwarded to the handler. + * + * @return PUS_STATUS_NULL, PUS_STATUS_TABLE_FULL, or PUS_STATUS_OK. */ pus_status_t pus_handler_register( pus_context_t *ctx, @@ -15,7 +23,13 @@ pus_status_t pus_handler_register( void *user_data); /** - * Return the table index of a registered handler, or -1 if not found. + * @brief Return the handler table index for a (service, subtype) pair. + * + * @param[in] ctx Active PUS context. + * @param[in] service Service type identifier. + * @param[in] subtype Service subtype identifier. + * + * @return Table index (>= 0) if found, -1 if not registered. */ int pus_handler_find( const pus_context_t *ctx, diff --git a/include/pus_service_1.h b/include/pus_service_1.h index 71b1251..177e040 100644 --- a/include/pus_service_1.h +++ b/include/pus_service_1.h @@ -5,15 +5,25 @@ #include "pus_context.h" #include "pus_types.h" -/** ACK flag bits in TC secondary header ack_flags. */ -#define PUS_ACK_ACCEPTANCE 0x08u -#define PUS_ACK_START 0x04u -#define PUS_ACK_PROGRESS 0x02u -#define PUS_ACK_COMPLETION 0x01u +/** @defgroup ack_flags TC secondary header ACK flag bits */ +/** @{ */ +#define PUS_ACK_ACCEPTANCE 0x08u /**< Request acceptance verification report. */ +#define PUS_ACK_START 0x04u /**< Request start of execution verification report. */ +#define PUS_ACK_PROGRESS 0x02u /**< Request progress verification report. */ +#define PUS_ACK_COMPLETION 0x01u /**< Request completion verification report. */ +/** @} */ /** - * Build an encoded Service 1 success report (TM[1,1], TM[1,3], TM[1,7]) - * into a caller-provided buffer. Use subtype constants from pus_services.h. + * @brief Build a ST[01] success report into a caller-provided buffer. + * + * @param[in,out] ctx Active PUS context. + * @param[in] tc The TC being verified. + * @param[in] subtype Subtype constant from pus_services.h (e.g. PUS_SUBTYPE_VERIFICATION_ACCEPTANCE_SUCCESS). + * @param[out] out Output byte buffer. + * @param[in] capacity Output buffer size in bytes. + * @param[out] out_len Receives the number of bytes written. + * + * @return PUS_STATUS_NULL, PUS_STATUS_BUFFER_TOO_SMALL, or PUS_STATUS_OK. */ pus_status_t pus_service_1_build_success( pus_context_t *ctx, @@ -24,8 +34,17 @@ pus_status_t pus_service_1_build_success( uint16_t *out_len); /** - * Build an encoded Service 1 failure report (TM[1,2], TM[1,4], TM[1,8], TM[1,10]) - * into a caller-provided buffer. + * @brief Build a ST[01] failure report into a caller-provided buffer. + * + * @param[in,out] ctx Active PUS context. + * @param[in] tc The TC being verified. + * @param[in] subtype Failure subtype (e.g. PUS_SUBTYPE_VERIFICATION_ROUTING_FAILURE). + * @param[in] failure_code Application-defined 2-byte failure code appended to the payload. + * @param[out] out Output byte buffer. + * @param[in] capacity Output buffer size in bytes. + * @param[out] out_len Receives the number of bytes written. + * + * @return PUS_STATUS_NULL, PUS_STATUS_BUFFER_TOO_SMALL, or PUS_STATUS_OK. */ pus_status_t pus_service_1_build_failure( pus_context_t *ctx, @@ -37,8 +56,14 @@ pus_status_t pus_service_1_build_failure( uint16_t *out_len); /** - * Build and forward a success report to ctx->tm_sink. + * @brief Build and forward a success report to ctx->tm_sink. * Returns PUS_STATUS_OK silently when no sink is configured. + * + * @param[in,out] ctx Active PUS context. + * @param[in] tc The TC being verified. + * @param[in] subtype Success subtype constant. + * + * @return PUS_STATUS_NULL or PUS_STATUS_OK. */ pus_status_t pus_service_1_emit_success( pus_context_t *ctx, @@ -46,8 +71,15 @@ pus_status_t pus_service_1_emit_success( pus_subtype_t subtype); /** - * Build and forward a failure report to ctx->tm_sink. + * @brief Build and forward a failure report to ctx->tm_sink. * Returns PUS_STATUS_OK silently when no sink is configured. + * + * @param[in,out] ctx Active PUS context. + * @param[in] tc The TC being verified. + * @param[in] subtype Failure subtype constant. + * @param[in] failure_code 2-byte failure code appended to the payload. + * + * @return PUS_STATUS_NULL or PUS_STATUS_OK. */ pus_status_t pus_service_1_emit_failure( pus_context_t *ctx, diff --git a/include/pus_service_17.h b/include/pus_service_17.h index bec4966..3237ec0 100644 --- a/include/pus_service_17.h +++ b/include/pus_service_17.h @@ -6,16 +6,27 @@ #include "pus_types.h" /** - * Emit TM[17,2] are-you-alive connection test report. - * Payload: empty (ECSS §8.17.3.2). + * @brief Emit TM[17,2] are-you-alive report (ECSS §8.17.3.2). + * Payload is empty. + * + * @param[in,out] ctx Active PUS context (provides TM sink). + * @param[in] destination_id Destination APID for the report. + * + * @return PUS_STATUS_NULL or PUS_STATUS_OK. */ pus_status_t pus_service_17_emit_alive_report( pus_context_t *ctx, uint16_t destination_id); /** - * Emit TM[17,4] on-board connection test report. - * Payload: tested application process ID (2 bytes, ECSS §8.17.3.4). + * @brief Emit TM[17,4] on-board connection test report (ECSS §8.17.3.4). + * Payload: tested application process APID (2 bytes). + * + * @param[in,out] ctx Active PUS context (provides TM sink). + * @param[in] apid Tested application process ID echoed in the payload. + * @param[in] destination_id Destination APID for the report. + * + * @return PUS_STATUS_NULL or PUS_STATUS_OK. */ pus_status_t pus_service_17_emit_connection_report( pus_context_t *ctx, @@ -23,8 +34,12 @@ pus_status_t pus_service_17_emit_connection_report( uint16_t destination_id); /** - * Register TC[17,1] and TC[17,3] handlers with the main context. - * Handlers reply directly to the TC source_id. + * @brief Register TC[17,1] and TC[17,3] handlers with the PUS context. + * Handlers reply directly to the source_id of the incoming TC. + * + * @param[in,out] ctx Active PUS context. + * + * @return PUS_STATUS_NULL, PUS_STATUS_TABLE_FULL, or PUS_STATUS_OK. */ pus_status_t pus_service_17_register_handlers(pus_context_t *ctx); diff --git a/include/pus_service_20.h b/include/pus_service_20.h index b373f9d..0950a60 100644 --- a/include/pus_service_20.h +++ b/include/pus_service_20.h @@ -7,8 +7,14 @@ #include "pus_types.h" /** - * Read the current value of a parameter into buf. - * capacity is guaranteed to be >= the registered value_len. + * @brief Parameter getter callback; reads the current value of a parameter. + * + * @param[in] param_id Parameter ID being read. + * @param[out] buf Output buffer (guaranteed to be >= registered value_len bytes). + * @param[in] capacity Output buffer size in bytes. + * @param[in,out] user_data Opaque pointer supplied at registration. + * + * @return PUS_STATUS_OK on success; any other value aborts the emit. */ typedef pus_status_t (*pus_param_getter_t)( uint16_t param_id, @@ -17,8 +23,14 @@ typedef pus_status_t (*pus_param_getter_t)( void *user_data); /** - * Write a new value for a parameter from buf. - * len equals the registered value_len. + * @brief Parameter setter callback; writes a new value for a parameter. + * + * @param[in] param_id Parameter ID being written. + * @param[in] buf New value bytes. + * @param[in] len Value length in bytes (equals the registered value_len). + * @param[in,out] user_data Opaque pointer supplied at registration. + * + * @return PUS_STATUS_OK on success; any other value is reported as a completion failure. */ typedef pus_status_t (*pus_param_setter_t)( uint16_t param_id, @@ -26,24 +38,41 @@ typedef pus_status_t (*pus_param_setter_t)( uint16_t len, void *user_data); +/** @brief One entry in the ST[20] parameter table. */ typedef struct { - uint16_t param_id; - uint16_t value_len; /* fixed wire size of the parameter value */ - pus_param_getter_t getter; - pus_param_setter_t setter; /* NULL = read-only */ - void *user_data; - uint8_t is_used; + uint16_t param_id; /**< Parameter ID. */ + uint16_t value_len; /**< Fixed wire size of the parameter value in bytes. */ + pus_param_getter_t getter; /**< Read callback. */ + pus_param_setter_t setter; /**< Write callback; NULL means read-only. */ + void *user_data; /**< Forwarded to getter and setter. */ + uint8_t is_used; /**< Non-zero when the slot is occupied. */ } pus_param_entry_t; +/** @brief ST[20] service context. Allocate statically. */ typedef struct { - pus_param_entry_t params[PUS_SERVICE_20_MAX_PARAMS]; + pus_param_entry_t params[PUS_SERVICE_20_MAX_PARAMS]; /**< Parameter table. */ } pus_service_20_ctx_t; +/** + * @brief Initialise an ST[20] context. + * + * @param[out] s20 Context to initialise. + * + * @return PUS_STATUS_NULL if s20 is NULL, PUS_STATUS_OK otherwise. + */ pus_status_t pus_service_20_init(pus_service_20_ctx_t *s20); /** - * Register a parameter. Registering the same param_id again updates - * its callbacks in place. setter may be NULL for read-only parameters. + * @brief Register a parameter. Re-registering the same param_id updates the entry in place. + * + * @param[in,out] s20 ST[20] context. + * @param[in] param_id Parameter ID. + * @param[in] value_len Fixed wire size of the parameter value in bytes. + * @param[in] getter Read callback (required). + * @param[in] setter Write callback; pass NULL for a read-only parameter. + * @param[in] user_data Forwarded to getter and setter. + * + * @return PUS_STATUS_NULL, PUS_STATUS_TABLE_FULL, or PUS_STATUS_OK. */ pus_status_t pus_service_20_register_param( pus_service_20_ctx_t *s20, @@ -54,8 +83,15 @@ pus_status_t pus_service_20_register_param( void *user_data); /** - * Build and emit TM[20,2] for the given list of parameter IDs. - * Can be called on demand as well as from the TC[20,1] handler. + * @brief Build and emit TM[20,2] for the given list of parameter IDs. + * + * @param[in,out] ctx Active PUS context (provides TM sink). + * @param[in] s20 ST[20] context. + * @param[in] param_ids Array of parameter IDs to include in the report. + * @param[in] count Number of entries in param_ids. + * + * @return PUS_STATUS_NULL, PUS_STATUS_NO_HANDLER, getter error, PUS_STATUS_BUFFER_TOO_SMALL, + * or PUS_STATUS_OK. */ pus_status_t pus_service_20_emit_report( pus_context_t *ctx, @@ -63,7 +99,14 @@ pus_status_t pus_service_20_emit_report( const uint16_t *param_ids, uint8_t count); -/** Register TC[20,1] and TC[20,3] handlers with the main context. */ +/** + * @brief Register TC[20,1] and TC[20,3] handlers with the PUS context. + * + * @param[in,out] ctx Active PUS context. + * @param[in] s20 ST[20] context passed to the handlers as user_data. + * + * @return PUS_STATUS_NULL, PUS_STATUS_TABLE_FULL, or PUS_STATUS_OK. + */ pus_status_t pus_service_20_register_handlers( pus_context_t *ctx, pus_service_20_ctx_t *s20); diff --git a/include/pus_service_3.h b/include/pus_service_3.h index 900e785..0497864 100644 --- a/include/pus_service_3.h +++ b/include/pus_service_3.h @@ -6,12 +6,19 @@ #include "pus_context.h" #include "pus_types.h" -#define PUS_SERVICE_3_KIND_HK 0u -#define PUS_SERVICE_3_KIND_DIAG 1u +#define PUS_SERVICE_3_KIND_HK 0u /**< Housekeeping structure kind. */ +#define PUS_SERVICE_3_KIND_DIAG 1u /**< Diagnostic structure kind. */ /** - * Provider callback: write parameter data for the given SID into buf. - * Called by emit functions; must not include the SID itself. + * @brief HK data provider callback, called by the emit functions. + * + * @param[in] sid Structure ID being collected. + * @param[out] buf Output buffer to write parameter data into. + * @param[in] capacity Buffer size in bytes. + * @param[out] out_len Receives the number of bytes written (must be <= capacity). + * @param[in,out] user_data Opaque pointer supplied at registration. + * + * @return PUS_STATUS_OK on success; any other value aborts the emit. */ typedef pus_status_t (*pus_hk_provider_t)( uint16_t sid, @@ -20,41 +27,86 @@ typedef pus_status_t (*pus_hk_provider_t)( uint16_t *out_len, void *user_data); +/** @brief One entry in the ST[03] structure table. */ typedef struct { - uint16_t sid; - uint8_t kind; - pus_hk_provider_t provider; - void *user_data; - uint8_t is_used; + uint16_t sid; /**< Structure ID. */ + uint8_t kind; /**< PUS_SERVICE_3_KIND_HK or PUS_SERVICE_3_KIND_DIAG. */ + pus_hk_provider_t provider; /**< Data provider callback. */ + void *user_data; /**< Forwarded to provider. */ + uint8_t is_used; /**< Non-zero when the slot is occupied. */ } pus_hk_entry_t; +/** @brief ST[03] service context. Allocate statically. */ typedef struct { - pus_hk_entry_t structures[PUS_SERVICE_3_MAX_STRUCTURES]; + pus_hk_entry_t structures[PUS_SERVICE_3_MAX_STRUCTURES]; /**< Structure table. */ } pus_service_3_ctx_t; +/** + * @brief Initialise an ST[03] context. + * + * @param[out] s3 Context to initialise. + * + * @return PUS_STATUS_NULL if s3 is NULL, PUS_STATUS_OK otherwise. + */ pus_status_t pus_service_3_init(pus_service_3_ctx_t *s3); -/** Register a housekeeping structure provider for the given SID. */ +/** + * @brief Register a housekeeping structure provider. + * Re-registering the same SID updates the entry in place. + * + * @param[in,out] s3 ST[03] context. + * @param[in] sid Structure ID to register. + * @param[in] provider Data provider callback. + * @param[in] user_data Forwarded to provider. + * + * @return PUS_STATUS_NULL, PUS_STATUS_TABLE_FULL, or PUS_STATUS_OK. + */ pus_status_t pus_service_3_register_hk( pus_service_3_ctx_t *s3, uint16_t sid, pus_hk_provider_t provider, void *user_data); -/** Register a diagnostic structure provider for the given SID. */ +/** + * @brief Register a diagnostic structure provider. + * Re-registering the same SID updates the entry in place. + * + * @param[in,out] s3 ST[03] context. + * @param[in] sid Structure ID to register. + * @param[in] provider Data provider callback. + * @param[in] user_data Forwarded to provider. + * + * @return PUS_STATUS_NULL, PUS_STATUS_TABLE_FULL, or PUS_STATUS_OK. + */ pus_status_t pus_service_3_register_diag( pus_service_3_ctx_t *s3, uint16_t sid, pus_hk_provider_t provider, void *user_data); -/** Build and emit TM[3,25] for a registered HK structure SID. */ +/** + * @brief Build and emit TM[3,25] for a registered HK structure. + * + * @param[in,out] ctx Active PUS context (provides TM sink). + * @param[in] s3 ST[03] context. + * @param[in] sid Structure ID to report. + * + * @return PUS_STATUS_NULL, PUS_STATUS_NO_HANDLER, provider error, or PUS_STATUS_OK. + */ pus_status_t pus_service_3_emit_hk( pus_context_t *ctx, pus_service_3_ctx_t *s3, uint16_t sid); -/** Build and emit TM[3,26] for a registered diagnostic structure SID. */ +/** + * @brief Build and emit TM[3,26] for a registered diagnostic structure. + * + * @param[in,out] ctx Active PUS context (provides TM sink). + * @param[in] s3 ST[03] context. + * @param[in] sid Structure ID to report. + * + * @return PUS_STATUS_NULL, PUS_STATUS_NO_HANDLER, provider error, or PUS_STATUS_OK. + */ pus_status_t pus_service_3_emit_diag( pus_context_t *ctx, pus_service_3_ctx_t *s3, diff --git a/include/pus_service_5.h b/include/pus_service_5.h index 7f43844..6a44cfa 100644 --- a/include/pus_service_5.h +++ b/include/pus_service_5.h @@ -6,14 +6,16 @@ #include "pus_types.h" /** - * Emit a Service 5 event report TM packet. + * @brief Build and emit a ST[05] event report (TM[5,x]). + * Returns PUS_STATUS_OK silently when no TM sink is configured. * - * subtype — one of PUS_SUBTYPE_EVENT_* from pus_services.h - * event_id — ECSS Event Definition ID (EVID), 2 bytes on the wire - * aux_data — optional auxiliary data appended after the event ID (may be NULL) - * aux_len — length of aux_data in bytes (0 when aux_data is NULL) + * @param[in,out] ctx Active PUS context (provides TM sink). + * @param[in] subtype Event severity; one of PUS_SUBTYPE_EVENT_* from pus_services.h. + * @param[in] event_id ECSS Event Definition ID (EVID), written as 2 bytes on the wire. + * @param[in] aux_data Optional auxiliary data appended after the event ID (may be NULL). + * @param[in] aux_len Length of aux_data in bytes; must be 0 when aux_data is NULL. * - * Returns PUS_STATUS_OK silently when no TM sink is configured. + * @return PUS_STATUS_NULL, PUS_STATUS_BUFFER_TOO_SMALL, or PUS_STATUS_OK. */ pus_status_t pus_service_5_emit( pus_context_t *ctx, diff --git a/include/pus_services.h b/include/pus_services.h index aaa655b..bf26474 100644 --- a/include/pus_services.h +++ b/include/pus_services.h @@ -1,43 +1,55 @@ #ifndef PUS_SERVICES_H #define PUS_SERVICES_H -/* ---- Service identifiers ---- */ -#define PUS_SERVICE_REQUEST_VERIFICATION 1u -#define PUS_SERVICE_HOUSEKEEPING 3u -#define PUS_SERVICE_EVENT_REPORTING 5u -#define PUS_SERVICE_TEST 17u -#define PUS_SERVICE_PARAMETER_MANAGEMENT 20u +/** @defgroup services PUS Service identifiers */ +/** @{ */ +#define PUS_SERVICE_REQUEST_VERIFICATION 1u /**< ST[01] Request Verification. */ +#define PUS_SERVICE_HOUSEKEEPING 3u /**< ST[03] Housekeeping. */ +#define PUS_SERVICE_EVENT_REPORTING 5u /**< ST[05] Event Reporting. */ +#define PUS_SERVICE_TEST 17u /**< ST[17] Test. */ +#define PUS_SERVICE_PARAMETER_MANAGEMENT 20u /**< ST[20] Parameter Management. */ +/** @} */ -/* ---- Service 1: request verification subtypes ---- */ -#define PUS_SUBTYPE_VERIFICATION_ACCEPTANCE_SUCCESS 1u -#define PUS_SUBTYPE_VERIFICATION_ACCEPTANCE_FAILURE 2u -#define PUS_SUBTYPE_VERIFICATION_START_SUCCESS 3u -#define PUS_SUBTYPE_VERIFICATION_START_FAILURE 4u -#define PUS_SUBTYPE_VERIFICATION_PROGRESS_SUCCESS 5u -#define PUS_SUBTYPE_VERIFICATION_PROGRESS_FAILURE 6u -#define PUS_SUBTYPE_VERIFICATION_COMPLETION_SUCCESS 7u -#define PUS_SUBTYPE_VERIFICATION_COMPLETION_FAILURE 8u -#define PUS_SUBTYPE_VERIFICATION_ROUTING_FAILURE 10u +/** @defgroup subtypes_st01 ST[01] Request Verification subtypes */ +/** @{ */ +#define PUS_SUBTYPE_VERIFICATION_ACCEPTANCE_SUCCESS 1u /**< TM[1,1] Acceptance success. */ +#define PUS_SUBTYPE_VERIFICATION_ACCEPTANCE_FAILURE 2u /**< TM[1,2] Acceptance failure. */ +#define PUS_SUBTYPE_VERIFICATION_START_SUCCESS 3u /**< TM[1,3] Start of execution success. */ +#define PUS_SUBTYPE_VERIFICATION_START_FAILURE 4u /**< TM[1,4] Start of execution failure. */ +#define PUS_SUBTYPE_VERIFICATION_PROGRESS_SUCCESS 5u /**< TM[1,5] Progress success. */ +#define PUS_SUBTYPE_VERIFICATION_PROGRESS_FAILURE 6u /**< TM[1,6] Progress failure. */ +#define PUS_SUBTYPE_VERIFICATION_COMPLETION_SUCCESS 7u /**< TM[1,7] Completion success. */ +#define PUS_SUBTYPE_VERIFICATION_COMPLETION_FAILURE 8u /**< TM[1,8] Completion failure. */ +#define PUS_SUBTYPE_VERIFICATION_ROUTING_FAILURE 10u /**< TM[1,10] Routing failure. */ +/** @} */ -/* ---- Service 3: housekeeping subtypes ---- */ -#define PUS_SUBTYPE_HOUSEKEEPING_PARAMETER_REPORT 25u -#define PUS_SUBTYPE_HOUSEKEEPING_DIAGNOSTIC_REPORT 26u +/** @defgroup subtypes_st03 ST[03] Housekeeping subtypes */ +/** @{ */ +#define PUS_SUBTYPE_HOUSEKEEPING_PARAMETER_REPORT 25u /**< TM[3,25] HK parameter report. */ +#define PUS_SUBTYPE_HOUSEKEEPING_DIAGNOSTIC_REPORT 26u /**< TM[3,26] Diagnostic report. */ +/** @} */ -/* ---- Service 5: event reporting subtypes ---- */ -#define PUS_SUBTYPE_EVENT_INFO 1u -#define PUS_SUBTYPE_EVENT_LOW_SEVERITY 2u -#define PUS_SUBTYPE_EVENT_MEDIUM_SEVERITY 3u -#define PUS_SUBTYPE_EVENT_HIGH_SEVERITY 4u +/** @defgroup subtypes_st05 ST[05] Event Reporting subtypes */ +/** @{ */ +#define PUS_SUBTYPE_EVENT_INFO 1u /**< TM[5,1] Informative event. */ +#define PUS_SUBTYPE_EVENT_LOW_SEVERITY 2u /**< TM[5,2] Low-severity anomaly. */ +#define PUS_SUBTYPE_EVENT_MEDIUM_SEVERITY 3u /**< TM[5,3] Medium-severity anomaly. */ +#define PUS_SUBTYPE_EVENT_HIGH_SEVERITY 4u /**< TM[5,4] High-severity anomaly. */ +/** @} */ -/* ---- Service 17: test subtypes ---- */ -#define PUS_SUBTYPE_TEST_ARE_YOU_ALIVE 1u -#define PUS_SUBTYPE_TEST_ARE_YOU_ALIVE_REPORT 2u -#define PUS_SUBTYPE_TEST_ON_BOARD_CONNECTION 3u -#define PUS_SUBTYPE_TEST_ON_BOARD_CONNECTION_REPORT 4u +/** @defgroup subtypes_st17 ST[17] Test subtypes */ +/** @{ */ +#define PUS_SUBTYPE_TEST_ARE_YOU_ALIVE 1u /**< TC[17,1] Are-you-alive test. */ +#define PUS_SUBTYPE_TEST_ARE_YOU_ALIVE_REPORT 2u /**< TM[17,2] Are-you-alive report. */ +#define PUS_SUBTYPE_TEST_ON_BOARD_CONNECTION 3u /**< TC[17,3] On-board connection test. */ +#define PUS_SUBTYPE_TEST_ON_BOARD_CONNECTION_REPORT 4u /**< TM[17,4] Connection test report. */ +/** @} */ -/* ---- Service 20: parameter management subtypes ---- */ -#define PUS_SUBTYPE_PARAMETER_REPORT_VALUES 1u -#define PUS_SUBTYPE_PARAMETER_VALUE_REPORT 2u -#define PUS_SUBTYPE_PARAMETER_SET_VALUES 3u +/** @defgroup subtypes_st20 ST[20] Parameter Management subtypes */ +/** @{ */ +#define PUS_SUBTYPE_PARAMETER_REPORT_VALUES 1u /**< TC[20,1] Request parameter value report. */ +#define PUS_SUBTYPE_PARAMETER_VALUE_REPORT 2u /**< TM[20,2] Parameter value report. */ +#define PUS_SUBTYPE_PARAMETER_SET_VALUES 3u /**< TC[20,3] Set parameter values. */ +/** @} */ #endif /* PUS_SERVICES_H */ diff --git a/include/pus_types.h b/include/pus_types.h index 6c22ad1..8776523 100644 --- a/include/pus_types.h +++ b/include/pus_types.h @@ -15,60 +15,68 @@ typedef uint8_t pus_subtype_t; /** @brief Encoded wire length of a TM secondary header in bytes. */ #define PUS_TM_SEC_HEADER_LEN 12u -/** @brief Return codes for all public EmbeddedPUS functions. */ +/** + * @brief Return codes for all public EmbeddedPUS functions. + */ typedef enum { - PUS_STATUS_OK = 0, - PUS_STATUS_NULL, - PUS_STATUS_BAD_LENGTH, - PUS_STATUS_BAD_VERSION, - PUS_STATUS_BAD_SERVICE, - PUS_STATUS_NO_HANDLER, - PUS_STATUS_HANDLER_FAILED, - PUS_STATUS_BUFFER_TOO_SMALL, - PUS_STATUS_TABLE_FULL + PUS_STATUS_OK = 0, /**< Operation succeeded. */ + PUS_STATUS_NULL, /**< A required pointer argument was NULL. */ + PUS_STATUS_BAD_LENGTH, /**< Buffer length is too short for decoding. */ + PUS_STATUS_BAD_VERSION, /**< PUS version field is not 1. */ + PUS_STATUS_BAD_SERVICE, /**< Service type is not recognised. */ + PUS_STATUS_NO_HANDLER, /**< No handler registered for (service, subtype). */ + PUS_STATUS_HANDLER_FAILED, /**< Registered handler returned an error. */ + PUS_STATUS_BUFFER_TOO_SMALL,/**< Output buffer capacity is insufficient. */ + PUS_STATUS_TABLE_FULL /**< Registration table has no free entries. */ } pus_status_t; /** - * Decoded TM secondary header. Never serialise this struct directly; - * use pus_tm_sec_header_encode() for wire encoding. + * @brief Decoded TM secondary header fields. + * @note Do not serialise this struct directly; use pus_tm_sec_header_encode(). */ typedef struct { - uint8_t version; /* PUS version (4-bit field) */ - uint8_t time_ref_status; /* time reference status (4-bit field) */ - uint8_t service_type_id; - uint8_t subtype_id; - uint16_t msg_type_counter; - uint16_t destination_id; - uint32_t time; - uint8_t spare; + uint8_t version; /**< PUS version (4-bit field). */ + uint8_t time_ref_status; /**< Time reference status (4-bit field). */ + uint8_t service_type_id; /**< Service type identifier. */ + uint8_t subtype_id; /**< Service subtype identifier. */ + uint16_t msg_type_counter; /**< Message type counter. */ + uint16_t destination_id; /**< Destination application process ID. */ + uint32_t time; /**< Packet timestamp (mission seconds or ticks). */ + uint8_t spare; /**< Spare byte (shall be zero). */ } pus_tm_sec_header_t; /** - * Decoded TC secondary header. Never serialise this struct directly; - * use pus_tc_sec_header_encode() for wire encoding. + * @brief Decoded TC secondary header fields. + * @note Do not serialise this struct directly; use pus_tc_sec_header_encode(). */ typedef struct { - uint8_t version; /* PUS version (4-bit field) */ - uint8_t ack_flags; /* acceptance/start/progress/completion bits */ - uint8_t service_type_id; - uint8_t subtype_id; - uint16_t source_id; - uint32_t time; - uint8_t spare; + uint8_t version; /**< PUS version (4-bit field). */ + uint8_t ack_flags; /**< Acceptance/start/progress/completion bits. */ + uint8_t service_type_id; /**< Service type identifier. */ + uint8_t subtype_id; /**< Service subtype identifier. */ + uint16_t source_id; /**< Source application process ID. */ + uint32_t time; /**< Packet timestamp. */ + uint8_t spare; /**< Spare byte (shall be zero). */ } pus_tc_sec_header_t; -/** @brief Decoded TC packet view. Payload borrows from the caller's buffer. */ +/** + * @brief Decoded TC packet. + * @note payload borrows from the caller's buffer; no data is copied. + */ typedef struct { - pus_tc_sec_header_t sec_header; - const uint8_t *payload; - uint16_t payload_len; + pus_tc_sec_header_t sec_header; /**< Decoded secondary header. */ + const uint8_t *payload; /**< Pointer into caller's buffer. */ + uint16_t payload_len;/**< Payload length in bytes. */ } pus_tc_packet_t; -/** @brief Decoded TM packet view. Payload borrows from the caller's buffer. */ +/** + * @brief Decoded TM packet. + * @note payload borrows from the caller's buffer; no data is copied. + */ typedef struct { - pus_tm_sec_header_t sec_header; - const uint8_t *payload; - uint16_t payload_len; + pus_tm_sec_header_t sec_header; /**< Decoded secondary header. */ + const uint8_t *payload; /**< Pointer into caller's buffer. */ + uint16_t payload_len;/**< Payload length in bytes. */ } pus_tm_packet_t; #endif /* PUS_TYPES_H */