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)).