Skip to content

The ground link — CCSDS / PUS

Inside the spacecraft everything is CAN. The ground link carries CCSDS Space Packets (6-octet primary header) with ECSS PUS-C secondary headers and a CRC-16-CCITT Packet Error Control trailer. Space packets are self-delimiting via the primary-header length field, so the link needs no sync word.

Source: include/pus.h — header-only and FreeRTOS-free, so the DHS, the framing side of TTC, the plain-POSIX EGSE relay and the ground tools all share exactly one definition of the wire format: pusTmEncode/pusDecode in the DHS, pusFrame for TTC and the relay (boundaries only), pusTcEncode/pusDecode for the tools.


1. Who does what

The DHS is the CAN↔PUS boundary; TTC is the link layer that moves whole packets.

  • Downlink — the DHS builds each PUS TM packet, stamps it with on-board time, stores it in the mass memory unit and hands it to TTC over CAN_FUNC_PKT. The producing subsystem’s CAN address becomes the APID (provenance), and the CAN function selects the service (HK/science → 3, ACK → verification 1, file readout → large-data 13); recorded occurrences go out as service-5 events.
  • Uplink — TTC frames each PUS TC off the TCP stream (pusFrame, boundaries only, no decode) and forwards the whole packet to the DHS, which decodes it, routes a CAN command to the subsystem named by the TC’s APID (time-set is always the DHS, which owns the clock), and answers with service 1 request verification.

2. Services

DownlinkPUS service, subtype
HK / science3, 25 (housekeeping report)
On-board occurrence5, 1..4 (event report, by severity)
TC accepted / rejected1, 1 / 1, 2 (acceptance report, +code)
TC started / failed to start1, 3 / 1, 4 (start-of-execution report, +code)
TC completed / failed1, 7 / 1, 8 (completion report, +code)
Reassembled payload file13, 1 / 13, 2 (large data)
Scheduled activities11, 17 (schedule detail report)
Parameter values20, 2 (parameter values report)
File attributes23, 4 (file attribute report)
Repository contents23, 13 (repository content summary report)
UplinkPUS service, subtype
Ping17, 1 (connection test)
HK request3, 27 (one-shot report)
Mission command8, 1 (perform function)
High-priority command (bypasses the DHS)8, 2 (perform function)
Set clock9, 128 (time management)
Arm / hold the command schedule11, 1 / 11, 2 (time-based scheduling)
Reset the schedule11, 3
Insert / delete an activity11, 4 / 11, 5
Report the schedule11, 16
Report / set parameters20, 1 / 20, 3 (parameter management)
Define / delete parameter20, 133 / 20, 134 (mission-specific)
Create / delete a file23, 1 / 23, 2 (file management)
Report file attributes23, 3
Summary-report a repository23, 12
Copy a file23, 14 — the mission data link’s trigger

The full telemetry inventory is in Telemetry generated.


3. Request verification (service 1)

A telecommand the ground uplinks is verified in two stages: the DHS first judges acceptance — is the service/subtype/parameters something it can carry out? — answering TM[1,1] (accepted) or TM[1,2] (rejected); then, on acceptance, it carries the command out and answers completion with TM[1,7] (done) or TM[1,8] (failed).

A telecommand the on-board schedule releases is verified in three, with a start-of-execution report between them: TM[1,3] when the activity begins, TM[1,4] + reason when it cannot. That stage exists because a scheduled command splits acceptance from execution across arbitrary time, so the moment execution began is a fact the ground can learn no other way; for an immediate command the two instants coincide, so the direct-uplink path never emits them. See Time-based scheduling.

Every report opens with a 4-octet request identifier echoing the TC’s primary header, so the ground pairs report to command; the failure reports append a 2-octet error code (see pusVerifErrName in pus.h). For a scheduled activity the identifier is that of the embedded telecommand, and it stays the same from the acceptance of the TC[11,4] that lodged it through to the completion of the command it eventually runs.

The acceptance rules, the three completion paths and the pending-request table are in Telecommand handling.


4. The high-priority bypass

A telecommand marked high-priority (service 8 / subtype PUS_ST_FUNC_PERFORM_HP) is recognised by TTC and handed straight to the addressed subsystem instead of being forwarded to the DHS. That is what makes an OBC switch commandable with the DHS down, and it is why redundancy state is a board strap rather than DHS-distributed database content. See Redundancy.


5. Time in packets — CCSDS CUC

The DHS is the clock master. On boot no absolute time exists, so every node’s clock free-runs from zero on its own FreeRTOS tick and telemetry is flagged unsynchronized — the CUC “spacecraft time reference status” nibble in each PUS TM header, surfaced on the ground as +Ns (unsynced).

The ground sets the clock with one telecommand:

TC DHS TIME NOW                     # the operator host's current UTC
TC DHS TIME 2026-07-16T12:00:00     # an explicit UTC instant
TC DHS TIME 2163017200              # raw CCSDS seconds, for scripting

That TC travels as PUS service 9 / subtype 128 to the DHS, which latches its clock and then broadcasts the time on the CAN bus (CMD_SET_TIME, re-sent every few seconds). ADCS, EPS, PAYLOAD and TTC each discipline their own on-board-time module (common/obt.c) to that broadcast, so all five nodes agree on one clock.

Time is carried everywhere in CCSDS CUC form — 32-bit coarse seconds from the CCSDS epoch (1958-01-01) plus 16-bit fine sub-seconds — representing UTC, and that last word is load-bearing. A 1958 epoch conventionally implies TAI, 37 s ahead of UTC today and gaining a second at each leap; this clock is not TAI (cucFromUnix() is plain Unix seconds plus CCSDS_EPOCH_UNIX_OFFSET, and obt.c just counts). The epoch bridge lives only at the ground edge, and a ground system that assumes TAI sits 37 s away from the spacecraft — see mdb.md for how the mission database declares it.

Timestamps are captured where the packet is built, not where the datum was sampled (On-board time). Two consequences: TRIAD attitude determination is gated on obtIsSynced(), so fine determination needs egse_tc DHS TIME NOW first (adcs.md); and a node reboot resets its clock, so telemetry from a freshly switched board reads (free) again.


6. Mass memory and events

Every generated packet passes through the DHS’s mass memory unit before downlink, and each on-board occurrence is downlinked as a PUS service-5 report at its severity subtype (TC DHS EVENTS replays the log). Both stores, the event catalogue and the overwrite policy are in dhs.md §7.

TODO — no octet-level layout here yet: the primary header fields, the PUS-C TM/TC secondary header layouts and the PEC computation are only in pus.h and in the XTCE (mdb.md).

Last updated on