Expand description
§Space Packet
Simple and generic Rust implementation of the Consultative Committee for Space Data Systems (CCSDS) Space Packet Protocol, as defined in CCSDS 133.0-B-2.
Written to be fully no_std and without unsafe blocks: this makes it suitable for usage in high-assurance embedded environments.
The Kani model checker is used to formally prove the absence of certain classes of errors: parsing of byte sequences and creation of Space Packets shall succeed for all possible inputs without panicking. Violation of preconditions shall be handled gracefully by returning an error.
§Usage
Reading Space Packets from some given byte buffer may be done as follows:
use space_packet::*;
// Constructs a simple packet with pre-determined values.
let bytes = &[
0b0001_1000u8, // Packet version 0, telecommand packet
0b0000_0000u8, // APID 0
0b1100_0000u8, // Unsegmented packet
0b0000_0000u8, // Packet sequence count 0
0b0000_0000u8, // Packet data length 1
0b0000_0000u8,
0b0000_0000u8, // One-byte data field
];
// Parses the given byte buffer into a fully type-safe wrapper struct. No copies are made, the
// returned struct is a direct, type-safe view into the byte buffer.
let packet = SpacePacket::parse(bytes).unwrap();
// Check that the packet contains the expected values.
assert_eq!(packet.packet_version(), PacketVersionNumber::version1_ccsds_packet());
assert_eq!(packet.packet_type(), PacketType::Telecommand);
assert_eq!(packet.apid(), Apid::new(0));
assert_eq!(packet.sequence_flag(), SequenceFlag::Unsegmented);
assert_eq!(packet.packet_sequence_count(), PacketSequenceCount::new());
assert_eq!(packet.packet_data_length(), 1);
assert_eq!(packet.packet_data_field(), &[0b0000_0000u8]);Note the use of accessor functions to conveniently read off the Space Packet primary header fields. Rather than raw bytes, typed wrappers are returned to represent the stored header data.
Vice versa, Space Packets may be constructed directly on a pre-allocated byte buffer.
use space_packet::*;
// A pre-allocated buffer must be used.
let buffer = &mut [0u8; 128];
// Construction happens in-place on this buffer: a `SpacePacket` is returned, or an appropriate
// error to indicate construction failure.
let packet = SpacePacket::construct(
buffer.as_mut(),
PacketType::Telemetry,
SecondaryHeaderFlag::Absent,
Apid::new(42),
SequenceFlag::Unsegmented,
PacketSequenceCount::new(),
8
).unwrap();
// Initializes the packet data field with some arbitrary values.
for (index, byte) in packet.packet_data_field_mut().iter_mut().enumerate() {
*byte = index as u8;
}
// The returned packet may be queried for its header fields.
assert_eq!(packet.packet_version(), PacketVersionNumber::version1_ccsds_packet());
assert_eq!(packet.packet_type(), PacketType::Telemetry);
assert_eq!(packet.apid(), Apid::new(42));
assert_eq!(packet.sequence_flag(), SequenceFlag::Unsegmented);
assert_eq!(packet.packet_sequence_count(), PacketSequenceCount::new());
assert_eq!(packet.packet_data_length(), 8);
assert_eq!(packet.packet_data_field(), &[0u8, 1, 2, 3, 4, 5, 6, 7]);This crate strictly follows the CCSDS Space Packet Protocol standard: not all byte sequences are valid Space Packets. In such cases, an appropriate error is returned to the caller, such that they can determine the appropriate course of action. This applies both to parsing and construction of Space Packets: once a SpacePacket is obtained, it must be a semantically valid Space Packet. Examples of failure cases:
use space_packet::*;
// This Space Packet stores a packet data length of 8 bytes, which cannot actually be contained in
// this byte buffer. Either the packet is incomplete, or it is erroneous.
let bytes = &[
0b0001_1000u8,
0b0000_0000u8,
0b1100_0000u8,
0b0000_0000u8,
0b0000_0000u8,
7u8, // Packet data length 8
0b0000_0000u8, // One-byte data field
];
// Returns an error indicating that the given byte slice contains only a partial packet.
let result = SpacePacket::parse(bytes);
assert_eq!(result, Err(InvalidSpacePacket::PartialPacket { packet_size: 14, buffer_size: 7 }));
// This Space Packet is an idle packet; such packets may not contain a secondary header field.
let bytes = &[
0b0001_1111u8, // Secondary header flag is 1,
0b1111_1111u8, // but APID is 'all ones' (idle)
0b1100_0000u8,
0b0000_0000u8,
0b0000_0000u8,
0b0000_0000u8,
0b0000_0000u8,
];
// Returns an error indicating that the given byte slice contains only a partial packet.
let result = SpacePacket::parse(bytes);
assert_eq!(result, Err(InvalidSpacePacket::IdlePacketWithSecondaryHeader));Generic implementation of the CCSDS 133.0-B-2 Space Packet Protocol (SPP). That is, this crate concerns itself only with parsing and construction of CCSDS Space Packets, as that is independent of the precise implementation. Endpoint functionality, i.e., actually consuming and responding to the packet contents is implementation specific, and hence out of scope.
Readers of the code are advised to start with the PacketAssembly, PacketTransfer,
PacketReception and PacketExtraction traits. These describe the interfaces that application
processes supporting the Space Packet Protocol are expected to expose.
Tested and formally-verified implementations of the underlying parsing and semantic checking
functionality needed to handle Space Packets is found in the actual SpacePacket
implementation. This functionality is included in the hope that it helps write simple and
robust SPP implementations.
Structs§
- Apid
- Returns the application process ID stored in the packet. The actual meaning of this APID field may differ per implementation: technically, it only represents “some” data path. In practice, it will often be a identifier for: a data channel, the packet source, or the packet destination.
- Packet
Sequence Count - The packet sequence count is unique per APID and denotes the sequential binary count of each Space Packet (generated per APID). For telecommands (i.e., with packet type 1) this may also be a “packet name” that identifies the telecommand packet within its communications session.
- Packet
Version Number - The packet version number represents the version of the Space Packet protocol that is used. In the version presently implemented, this is defined to be zeroes.
- Space
Packet - Space packets are implemented as dynamically-sized structs that contain the primary header as their first field, followed by the packet data as pure byte array. In this manner, deserialization can be reduced to a simple byte cast followed by interpretation of the primary header - without any data copies needed. This is useful for high-throughput applications, and ensures that no allocation or significant additional memory is needed to consume Space Packets.
- Space
Packet Primary Header - Representation of only the fixed-size primary header part of a space packet. Used to construct generic space packets, but mostly useful in permitting composition of derived packet types, like PUS packets; otherwise, the dynamically-sized data field member would get in the way of including the primary header directly in derived packets.
Enums§
- Invalid
Packet Data Length - This error may be returned when setting the data field of some newly-constructed Space Packet if the requested packet data length is 0 (which is generally illegal) or if the requested packet data length does not fit in the buffer on which the packet must be stored.
- Invalid
Space Packet - Representation of the set of errors that may be encountered while deserializing a Space Packet. Marked as non-exhaustive to permit extension with additional semantic errors in the future without breaking API.
- Packet
Assembly Error - Representation of the set of errors that may be encountered while constructing a Space Packet. Marked as non-exhaustive to permit extension with additional semantic errors in the future without breaking API.
- Packet
Type - The packet type denotes whether a packet is a telecommand (request) or telemetry (report) packet. Note that the exact definition of telecommand and telemetry may differ per system, and indeed the “correct” value here may differ per project.
- Secondary
Header Flag - Denotes whether the packet contains a secondary header. If no user field is present, the secondary header is mandatory (presumably, to ensure that some data is always transferred, considering the Space Packet header itself contains no meaningful data).
- Sequence
Flag - Sequence flags may be used to indicate that the data contained in a packet is only part of a larger set of application data.
Traits§
- Packet
Assembly - The
PacketAssemblytrait describes the “Packet Assembly” function from the CCSDS 133.0-B-2 Space Packet Protocol recommended standard. This function concerns the ability of some protocol entity to build Space Packets from octet strings (packet data fields). It is the sending counterpart of thePacketExtractiontrait. - Packet
Extraction - The
PacketExtractiontrait describes the “Packet Extraction” function from the CCSDS 133.0-B-2 Space Packet Protocol recommended standard. It concerns the ability to unpack Space Packets that have been received from some underlying subnetwork into the transmitted octet strings. - Packet
Reception - The
PacketReceptiontrait describes the “Packet Reception” function from the CCSDS 133.0-B-2 Space Packet Protocol recommended standard. It concerns the ability to receive new Space Packets from some underlying subnetwork layer. - Packet
Transfer - The
PacketTransfertrait describes the “Packet Transfer” function from the CCSDS 133.0-B-2 Space Packet Protocol recommended standard. It concerns the ability of some protocol entity to transfer packets towards the appropriate managed data path. It is the sending counterpart of thePacketReceptiontrait.