ccsds_packet_services

The ccsds_packet_services library provides service-aware helpers that sit above the raw ccsds_packets and ccsds_frames codec libraries.

The current implementation supports telemetry and advanced orbiting systems packet-zone handling above the raw ccsds_frames payload bridge:

  • splitting a packet-zone byte sequence using a TM transfer frame first header pointer

  • parsing the complete packets that start in that zone

  • preserving any leading continuation bytes and trailing incomplete bytes

  • rebuilding a packet zone and reinserting it into a TM transfer frame

  • splitting an AOS M_PDU packet-service data field into its first-header-pointer header and packet zone

  • representing AOS idle-only packet zones distinctly from AOS no-start packet zones using the same packet_zone/3 term

  • rebuilding an AOS M_PDU packet-service data field and reinserting it into an AOS transfer frame

  • carrying trailing packet fragments across multiple TM or AOS frames using an explicit packet reassembly state term

  • reassembling complete packets across frame sequences while preserving any still-incomplete trailing fragment for the next batch

  • tracking TM and AOS reassembly state per frame type, spacecraft identifier, and virtual channel identifier

  • detecting dropped or out-of-order TM and AOS frames by checking the expected virtual-channel frame counts during reassembly

  • applying configurable discontinuity recovery policies at the frame level, choosing between throwing an error, dropping the discontinuous frame, or resynchronizing on the current frame

  • returning explicit recovery event streams from the richer frame reassembly predicates so callers can observe dropped fragments, skipped frames, and resynchronization points

Representation

Packet zones are represented using the compound term:

packet_zone(PrefixData, Packets, SuffixData)

Where:

  • PrefixData is a list of bytes preceding the first complete packet

  • Packets is a list of complete ccsds_packet(...) terms

  • SuffixData is a list of bytes trailing the last complete packet

When a telemetry transfer frame first header pointer indicates that no packet starts in the frame data field, the full data field is represented as:

packet_zone(DataField, [], [])

For AOS packet service data fields, the same term is used after decoding the two-octet M_PDU first header pointer:

  • packet_zone(PrefixData, [], []) corresponds to first header pointer 2047 and means that no packet starts in this frame packet zone

  • packet_zone([], [], SuffixData) corresponds to first header pointer 2046 and means that the packet zone contains idle data only

Cross-frame packet reassembly state is represented using the compound term:

packet_reassembly_state(PendingData)

Where PendingData is a list of bytes belonging to an incomplete packet whose header started in an earlier frame and whose remaining bytes are expected in a later frame.

Frame-channel reassembly state is represented using the compound term:

channel_reassembly_state(Channels)

Where Channels is a list of terms of the form:

reassembly_channel(FrameType, SpacecraftId, VirtualChannelId, CounterModulus, ExpectedFrameCount, PendingData)

The FrameType argument is either tm or aos. The keyed state is used by the frame-level reassembly predicates so that interleaved virtual channels and TM versus AOS streams do not collide.

Discontinuity recovery policies are represented by the atoms:

throw
drop
resynchronize

The policies have the following meaning when a frame-count discontinuity is detected for a keyed channel:

  • throw: raise a domain_error/2 exception and leave recovery to the caller

  • drop: discard any buffered fragment for that keyed channel and skip the discontinuous frame payload entirely

  • resynchronize: discard any buffered fragment for that keyed channel but still process the current frame, ignoring any pre-pointer continuation bytes

Recovery event streams are returned by the seven-argument TM and AOS frame reassembly predicates as lists of terms of the form:

dropped_fragment(FrameType, SpacecraftId, VirtualChannelId, Reason, PendingData)
skipped_frame(FrameType, SpacecraftId, VirtualChannelId, Discontinuity)
resynchronized(FrameType, SpacecraftId, VirtualChannelId, Discontinuity)

Where Reason is either:

  • discontinuity(StoredCounterModulus, CounterModulus, ExpectedFrameCount, VirtualChannelFrameCount)

  • idle_only(VirtualChannelFrameCount) for AOS idle-only M_PDUs that clear a buffered fragment

Packet-zone helpers

To split a packet zone using a first header pointer and parse the complete packets that start there:

| ?- ccsds_packet_services::split_packet_zone([0xAA,0xBB,0x00,0x00,0xC0,0x00,0x00,0x00,0x42,0xCC], 2, 0, PacketZone).

To rebuild a packet zone and recover the corresponding first header pointer:

| ?- ccsds_packet_services::join_packet_zone(packet_zone([0xAA,0xBB], [ccsds_packet(0,0,0,0,3,0,none,[0x42])], [0xCC]), 0, Bytes, FirstHeaderPointer).

Telemetry transfer frame helpers

To extract a packet zone from a telemetry transfer frame term:

| ?- ccsds_packet_services::extract_tm_packets(tm_transfer_frame(0, 42, 3, 0, 16, 32, 0, 0, 0, 3, 2, none, [0xAA,0xBB,0x00,0x00,0xC0,0x00,0x00,0x00,0x42,0xCC], none, none), 0, PacketZone).

To update a telemetry transfer frame from a packet zone term:

| ?- ccsds_packet_services::insert_tm_packets(packet_zone([0xAA,0xBB], [ccsds_packet(0,0,0,0,3,0,none,[0x42])], [0xCC]), 0, tm_transfer_frame(0, 42, 3, 0, 16, 32, 0, 0, 0, 3, 0, none, [], none, none), UpdatedFrame).

If the input TM frame already carries a fecf/1 term, insert_tm_packets/4 refreshes it from the updated frame bytes. Frames with none keep none.

Advanced orbiting systems helpers

To split an AOS M_PDU packet-service data field:

| ?- ccsds_packet_services::split_aos_packet_zone([0x00,0x02,0xAA,0xBB,0x00,0x00,0xC0,0x00,0x00,0x00,0x42,0xCC], 0, PacketZone).

To rebuild an AOS M_PDU packet-service data field from a packet zone term:

| ?- ccsds_packet_services::join_aos_packet_zone(packet_zone([0xAA,0xBB], [ccsds_packet(0,0,0,0,3,0,none,[0x42])], [0xCC]), 0, Bytes).

To extract a packet zone from an AOS transfer frame term:

| ?- ccsds_packet_services::extract_aos_packets(aos_transfer_frame(1, 42, 3, 16, signaling_field(0,0,0,0), none, [0x00,0x02,0xAA,0xBB,0x00,0x00,0xC0,0x00,0x00,0x00,0x42,0xCC], none, none), 0, PacketZone).

To update an AOS transfer frame from a packet zone term:

| ?- ccsds_packet_services::insert_aos_packets(packet_zone([0xAA,0xBB], [ccsds_packet(0,0,0,0,3,0,none,[0x42])], [0xCC]), 0, aos_transfer_frame(1, 42, 3, 16, signaling_field(0,0,0,0), none, [], none, none), UpdatedFrame).

If the input AOS frame already carries a fecf/1 term, insert_aos_packets/4 refreshes it from the updated frame bytes. Frames with none keep none.

Cross-frame packet reassembly

To get the initial low-level packet reassembly state:

| ?- ccsds_packet_services::initial_reassembly_state(State).

To get the initial keyed frame-channel reassembly state:

| ?- ccsds_packet_services::initial_channel_reassembly_state(State).

To reassemble a packet zone against a prior trailing fragment:

| ?- ccsds_packet_services::reassemble_packet_zone(packet_zone([0x00,0x00,0x42], [ccsds_packet(0,0,0,0,3,1,none,[0x43])], []), 0, packet_reassembly_state([0x00,0x00,0xC0,0x00]), Packets, UpdatedState).

To reassemble complete packets across a sequence of telemetry transfer frames:

| ?- ccsds_packet_services::reassemble_tm_frames([tm_transfer_frame(0, 42, 3, 0, 16, 32, 0, 0, 0, 3, 0, none, [0x00,0x00,0xC0,0x00], none, none), tm_transfer_frame(0, 42, 3, 0, 16, 33, 0, 0, 0, 3, 3, none, [0x00,0x00,0x42,0x00,0x00,0xC0,0x01,0x00,0x00,0x43], none, none)], 0, channel_reassembly_state([]), Packets, UpdatedState).

To reassemble telemetry transfer frames while resynchronizing automatically on a detected discontinuity:

| ?- ccsds_packet_services::reassemble_tm_packets(tm_transfer_frame(0, 42, 3, 0, 16, 34, 0, 0, 0, 3, 3, none, [0x00,0x00,0x42,0x00,0x00,0xC0,0x02,0x00,0x00,0x44], none, none), 0, resynchronize, channel_reassembly_state([reassembly_channel(tm,42,3,256,33,[0x00,0x00,0xC0,0x00])]), Packets, UpdatedState).

To reassemble a telemetry transfer frame and also receive explicit recovery events:

| ?- ccsds_packet_services::reassemble_tm_packets(tm_transfer_frame(0, 42, 3, 0, 16, 34, 0, 0, 0, 3, 3, none, [0x00,0x00,0x42,0x00,0x00,0xC0,0x02,0x00,0x00,0x44], none, none), 0, resynchronize, channel_reassembly_state([reassembly_channel(tm,42,3,256,33,[0x00,0x00,0xC0,0x00])]), Packets, UpdatedState, Events).

To reassemble complete packets across a sequence of AOS transfer frames:

| ?- ccsds_packet_services::reassemble_aos_frames([aos_transfer_frame(1, 42, 3, 16, signaling_field(0,0,0,0), none, [0x00,0x00,0x00,0x00,0xC0,0x00], none, none), aos_transfer_frame(1, 42, 3, 17, signaling_field(0,0,0,0), none, [0x00,0x03,0x00,0x00,0x42,0x00,0x00,0xC0,0x01,0x00,0x00,0x43], none, none)], 0, channel_reassembly_state([]), Packets, UpdatedState).

To reassemble AOS transfer frames while dropping a discontinuous frame and resetting the keyed buffered fragment:

| ?- ccsds_packet_services::reassemble_aos_packets(aos_transfer_frame(1, 42, 3, 18, signaling_field(0,0,0,0), none, [0x00,0x03,0x00,0x00,0x42,0x00,0x00,0xC0,0x02,0x00,0x00,0x44], none, none), 0, drop, channel_reassembly_state([reassembly_channel(aos,42,3,16777216,17,[0x00,0x00,0xC0,0x00])]), Packets, UpdatedState).

To reassemble AOS transfer frames and receive explicit recovery events across a frame sequence:

| ?- ccsds_packet_services::reassemble_aos_frames([aos_transfer_frame(1, 42, 3, 16, signaling_field(0,0,0,0), none, [0x00,0x00,0x00,0x00,0xC0,0x00], none, none), aos_transfer_frame(1, 42, 3, 18, signaling_field(0,0,0,0), none, [0x00,0x03,0x00,0x00,0x42,0x00,0x00,0xC0,0x02,0x00,0x00,0x44], none, none)], 0, drop, channel_reassembly_state([]), Packets, UpdatedState, Events).

To inspect the currently buffered keyed pending fragments:

| ?- ccsds_packet_services::pending_fragments(channel_reassembly_state([reassembly_channel(tm,42,3,256,33,[0x00,0x00,0xC0,0x00])]), PendingFragments).

For AOS packet service, idle-only M_PDUs clear any pending fragment state. This matches the packet-zone interpretation where first header pointer 2046 denotes idle data rather than continuation bytes.

If a TM or AOS frame arrives with a virtual-channel frame count different from the keyed state expected count, the frame-level reassembly predicates apply the selected discontinuity recovery policy. The five-argument variants default to the throw policy. The seven-argument variants additionally report the recovery decisions as an explicit event stream.

Scope

This milestone covers TM transfer frame packet zones, AOS packet-service M_PDUs, low-level packet-fragment stitching, and keyed TM/AOS cross-frame packet reassembly with continuity checks and configurable discontinuity recovery. Future milestones can extend the same library with segmentation policies, idle packet generation, richer per-channel recovery controls, and higher level packetization policies.

API documentation

Open the ../../apis/library_index.html#ccsds_packet_services link in a web browser.

Loading

To load all entities in this library, load the loader.lgt file:

| ?- logtalk_load(ccsds_packet_services(loader)).

Testing

To test this library predicates, load the tester.lgt file:

| ?- logtalk_load(ccsds_packet_services(tester)).