Documentation
¶
Overview ¶
Package pxdl implements the Proximity-1 Space Data Link Protocol per CCSDS 211.0-B-6 (July 2020), Data Link Layer.
Proximity-1 is the short-range link protocol: orbiter to lander, orbiter to rover, spacecraft to spacecraft. It is what the Mars relay network runs on.
It differs from the long-haul data link protocols this library also ships ( TM, TC, AOS, USLP) in ways that follow from the short range. Frames are small, at most 2048 octets. The header is five octets with no error control field, because the coding layer below handles that. And a single frame type carries both user data and the protocol's own supervisory traffic, distinguished by one bit.
U-frame: header │ user data (packets, segments, or raw) P-frame: header │ supervisory PDUs (link control words, directives)
This package implements the Version-3 Transfer Frame and its data field constructions. The coding and synchronization layer, CCSDS 211.2-B-3, lives in pkg/pxsc.
Index ¶
- Constants
- Variables
- func EncodeSPDUs(spdus []SPDU) ([]byte, error)
- type DFCID
- type FrameOption
- type Header
- type ManagedParameters
- type PDUType
- type PLCW
- type QoS
- type Reassembler
- type RoutingID
- type SPDU
- type Segment
- type SegmentHeader
- type SequenceFlags
- type SourceOrDest
- type TransferFrame
- type VariableSPDU
Constants ¶
const ( // MaxDataFieldSize is the largest Transfer Frame Data field. MaxDataFieldSize = 2043 // MinFrameSize is the smallest legal frame: header only. MinFrameSize = HeaderSize // MaxFrameSize is the largest frame the 11-bit length field can describe. MaxFrameSize = 2048 )
Frame size bounds, per clause 3.2.1 and clause 3.2.2.10.2.
const ( // SPDUFormatVariable marks a variable-length SPDU ('0'). SPDUFormatVariable uint8 = 0 // SPDUFormatFixed marks a 16-bit fixed-length SPDU ('1'). SPDUFormatFixed uint8 = 1 )
SPDU format identifiers, per clause 3.2.4.2.
const ( // FixedTypePLCW identifies a Proximity Link Control Word ('0'). FixedTypePLCW uint8 = 0 // FixedTypeReserved is reserved for future CCSDS specification ('1'). FixedTypeReserved uint8 = 1 )
Fixed-length SPDU type identifiers, per table 3-5.
const DefaultMaxPacketSize = 64 << 10
DefaultMaxPacketSize bounds an accumulating packet when Reassembler leaves MaxPacketSize at zero: 64 KiB.
The standard sets no ceiling on a reassembled packet. Without one, a stream of "continuing" segments that never ends would grow without limit.
const FixedSPDUSize = 2
FixedSPDUSize is the width of a fixed-length SPDU in octets (clause 3.2.4.2.1).
const HeaderSize = 5
HeaderSize is the width of the Transfer Frame Header in octets (clause 3.2.1 a).
const MaxVariableSPDUData = 15
MaxVariableSPDUData is the largest variable-length SPDU data field, bounded by its 4-bit length field (clause 3.2.4.2.2).
const SegmentHeaderSize = 1
SegmentHeaderSize is the width of a segment header in octets (clause 3.2.3.3.1).
const Version = 2
Version is the Transfer Frame Version Number for a Version-3 frame: binary '10', per CCSDS 211.0-B-6 clause 3.2.2.2.2.
Variables ¶
var ( // ErrDataTooShort indicates the input is shorter than the fields it must contain. ErrDataTooShort = errors.New("data too short for the Proximity-1 field being read") // ErrInvalidVersion indicates a Transfer Frame Version Number other than // binary '10', which CCSDS 211.0-B-6 clause 3.2.2.2.2 requires for Version-3. ErrInvalidVersion = errors.New("invalid transfer frame version: Version-3 requires binary '10'") // ErrInvalidFrameLength indicates a frame length outside the 5 to 2048 // octet range of clause 3.2.2.10.2. ErrInvalidFrameLength = errors.New("invalid frame length: must be 5 to 2048 octets") // ErrDataTooLarge indicates a data field beyond the 2043 octets clause 3.2.1 allows. ErrDataTooLarge = errors.New("data field exceeds the maximum of 2043 octets") // ErrInvalidSCID indicates a spacecraft identifier beyond the 10-bit field. ErrInvalidSCID = errors.New("invalid spacecraft ID: must fit 10 bits") // ErrInvalidPortID indicates a port identifier beyond the 3-bit field. ErrInvalidPortID = errors.New("invalid port ID: must fit 3 bits") // ErrPortIDOnSupervisoryFrame indicates a P-frame carrying a non-zero // Port ID, which CCSDS 211.0-B-6 clause 3.2.2.8.2 forbids. ErrPortIDOnSupervisoryFrame = errors.New("port ID must be zero on a supervisory frame") // ErrInvalidPCID indicates a physical channel identifier beyond one bit. ErrInvalidPCID = errors.New("invalid physical channel ID: must be 0 or 1") // ErrInvalidDFCID indicates a Data Field Construction ID that is reserved, // or non-zero on a P-frame where clause 3.2.2.5.2 requires '00'. ErrInvalidDFCID = errors.New("invalid data field construction ID") // ErrNotUserFrame indicates a user-data operation on a P-frame. ErrNotUserFrame = errors.New("frame carries supervisory data, not user data") // ErrNotSupervisoryFrame indicates a supervisory operation on a U-frame. ErrNotSupervisoryFrame = errors.New("frame carries user data, not supervisory data") // ErrInvalidQoS indicates an SPDU on the Sequence Controlled service. // Clause 3.2.4.1 allows SPDUs only on Expedited. ErrInvalidQoS = errors.New("supervisory PDUs may travel only on the Expedited service") // ErrInvalidSPDU indicates a malformed supervisory PDU. ErrInvalidSPDU = errors.New("invalid supervisory PDU") // ErrSPDUDataTooLarge indicates a variable-length SPDU data field beyond // the 15 octets its 4-bit length field can describe. ErrSPDUDataTooLarge = errors.New("supervisory PDU data field exceeds 15 octets") // ErrInvalidSegment indicates a segment header or reassembly failure. ErrInvalidSegment = errors.New("invalid packet segment") // ErrSegmentOutOfOrder indicates a continuing or last segment arriving // before a first segment for its routing ID (clause 3.2.3.3.5 b). ErrSegmentOutOfOrder = errors.New("segment arrived before the first segment of its packet") // ErrReassemblyTooLarge indicates an accumulating packet beyond the // configured maximum. ErrReassemblyTooLarge = errors.New("reassembled packet exceeds the maximum size") )
Sentinel errors returned by the Proximity-1 data link codecs.
Functions ¶
func EncodeSPDUs ¶
EncodeSPDUs serializes a run of supervisory PDUs into a P-frame data field.
Types ¶
type DFCID ¶
type DFCID uint8
DFCID is the Data Field Construction ID of clause 3.2.2.5, saying how a U-frame's data field is arranged. Table 3-1 gives the four values.
const ( // DFCPackets means an integer number of unsegmented packets. DFCPackets DFCID = 0 // DFCSegment means one complete or segmented packet, behind a segment header. DFCSegment DFCID = 1 // DFCReserved is reserved for future CCSDS definition. DFCReserved DFCID = 2 // DFCUserDefined means the content is defined by the mission. DFCUserDefined DFCID = 3 )
type FrameOption ¶
type FrameOption func(*TransferFrame)
FrameOption configures a frame at construction.
func WithDFCID ¶
func WithDFCID(d DFCID) FrameOption
WithDFCID sets the data field construction for a U-frame.
func WithSequenceNumber ¶
func WithSequenceNumber(n uint8) FrameOption
WithSequenceNumber sets the frame sequence number.
func WithSourceSCID ¶
func WithSourceSCID() FrameOption
WithSourceSCID marks the SCID field as naming the source spacecraft. The default is the destination.
type Header ¶
type Header struct {
// QoS selects the sequence-controlled or expedited service.
QoS QoS
// PDUType distinguishes a U-frame from a P-frame.
PDUType PDUType
// DFCID says how a U-frame's data field is arranged. Clause 3.2.2.5.2 requires
// zero on a P-frame.
DFCID DFCID
// SCID identifies the spacecraft, 10 bits.
SCID uint16
// PCID selects one of two physical channels, 1 bit.
PCID uint8
// PortID identifies the port, 3 bits. Clause 3.2.2.8.2 requires zero on a
// P-frame.
PortID uint8
// SourceOrDest says whether SCID names the source or the destination.
SourceOrDest SourceOrDest
// FrameLength is the total frame length in octets. It travels as a count
// one less than this value (clause 3.2.2.10.2).
FrameLength uint16
// FrameSequenceNumber counts frames per PCID and service (clause 3.2.2.11).
FrameSequenceNumber uint8
}
Header is the Transfer Frame Header of clause 3.2.2, figure 3-3.
Five octets, ten fields:
Octet 0: TFVN(2) | QoS(1) | PDU type(1) | DFC ID(2) | SCID[9:8](2) Octet 1: SCID[7:0](8) Octet 2: PCID(1) | Port ID(3) | Src/Dest(1) | Frame Length[10:8](3) Octet 3: Frame Length[7:0](8) Octet 4: Frame Sequence Number(8)
type ManagedParameters ¶
type ManagedParameters struct {
// LocalSpacecraftID is Local_Spacecraft_ID: the SCID of this node. Used
// to validate a received frame whose Source-or-Destination Identifier
// says the SCID names the destination (clause 3.2.2.9.3).
LocalSpacecraftID uint16
// RemoteSpacecraftID is Remote_Spacecraft_ID: the SCID of the node at
// the far end of the link (clause 3.2.2.9.3).
RemoteSpacecraftID uint16
// SendMaximumFrameLength is Maximum_Frame_Length for the frames this
// node transmits, in octets. Annex C keys the parameter to the frame
// version in use; for Version-3 frames it can be at most 2048.
SendMaximumFrameLength int
// ReceiveMaximumFrameLength is Maximum_Frame_Length for the frames this
// node accepts. The two directions of a Proximity-1 link often run at
// very different data rates, so the negotiated maxima can differ too.
ReceiveMaximumFrameLength int
// MaximumPacketSize is Maximum_Packet_Size: the largest packet the
// segmentation and reassembly process handles, in octets (clause 4.4.2.1).
MaximumPacketSize int
// SynchTimeout is Synch_Timeout: how long the receiving end waits
// without frame synchronization before declaring the link lost.
SynchTimeout time.Duration
// PLCWRepeatInterval is PLCW_Repeat_Interval: how often COP-P repeats
// the current PLCW when nothing has changed (annex C).
PLCWRepeatInterval time.Duration
}
ManagedParameters holds the MIB entries relevant to this layer, named after the annex C parameters they represent.
The zero value is not useful; start from DefaultManagedParameters.
func DefaultManagedParameters ¶
func DefaultManagedParameters() ManagedParameters
DefaultManagedParameters returns parameters with the Version-3 frame bounds and the package's reassembly default. Spacecraft IDs and timing have no meaningful defaults; they come from the mission.
func (*ManagedParameters) Validate ¶
func (m *ManagedParameters) Validate() error
Validate checks the parameters against the Version-3 frame bounds.
type PDUType ¶
type PDUType uint8
PDUType is the PDU Type ID of clause 3.2.2.4: whether the data field carries user data or the protocol's own supervisory traffic.
type PLCW ¶
type PLCW struct {
// RetransmitFlag says the receiver is missing frames and wants them again.
RetransmitFlag bool
// PCID names the physical channel this report covers.
PCID uint8
// ExpeditedFrameCounter counts frames received on the Expedited service,
// 3 bits.
ExpeditedFrameCounter uint8
// ReportValue is V(R): the sequence number the receiver expects next
// (clause 3.2.4.3.2.2.2).
ReportValue uint8
}
PLCW is the Proximity Link Control Word, the Type F1 fixed-length SPDU of Clause 3.2.4.3.2.
It is Proximity-1's acknowledgement: the receiver reports which frame it expects next, so the sender knows what got through. The same job COP-1's CLCW does for TC links.
Sixteen bits, described in figure 3-5 from bit 0:
format ID(1) │ type ID(1) │ retransmit(1) │ PCID(1) │ spare(1) │ expedited frame counter(3) │ report value(8)
This order is verified against CCSDS 211.0-B-6 clause 3.2.4.3.2.1.1, which lists the seven fields from bit 15 up (Report Value, Expedited Frame Counter, Reserved Spare, PCID, Retransmit Flag, SPDU Type Identifier, SPDU Format ID) and clause 3.2.4.3.2.2.1, which puts the Report Value in bits 8-15.
func DecodePLCW ¶
DecodePLCW parses a Proximity Link Control Word.
type Reassembler ¶
type Reassembler struct {
// MaxPacketSize bounds one accumulating packet. Zero selects
// DefaultMaxPacketSize.
MaxPacketSize int
// contains filtered or unexported fields
}
Reassembler rebuilds packets from the segments arriving on a link, per Clause 3.2.3.3.3.
Segments of different packets interleave freely as long as they differ in PCID or Port ID, so the reassembler keeps one buffer per routing ID.
Clause 3.2.3.3.4 is strict: only complete packets are delivered. A stream that starts mid-packet, or grows past the limit, is discarded rather than half-delivered.
A Reassembler is not safe for concurrent use.
func NewReassembler ¶
func NewReassembler() *Reassembler
NewReassembler returns an empty reassembler.
func (*Reassembler) Accept ¶
func (r *Reassembler) Accept(pcid, portID uint8, seg *Segment) ([]byte, error)
Accept folds one segment into the reassembler.
It returns a complete packet when this segment finishes one, and nil when more segments are still needed.
func (*Reassembler) AcceptFrame ¶
func (r *Reassembler) AcceptFrame(f *TransferFrame) ([]byte, error)
AcceptFrame folds a U-frame's segment into the reassembler, taking the PCID and Port ID from the frame header.
func (*Reassembler) Pending ¶
func (r *Reassembler) Pending() int
Pending returns how many partial packets are still accumulating.
type RoutingID ¶
RoutingID identifies the stream a segment belongs to, per clause 1.5.1.2: the physical channel, the port, and the pseudo packet ID together.
Clause 3.2.3.3.2 c) requires all segments of one packet to travel with the same PCID and Port ID, which is what makes this triple sufficient.
type SPDU ¶
type SPDU struct {
PLCW *PLCW
Variable *VariableSPDU
}
SPDU is one supervisory PDU of either shape. Exactly one field is set.
func DecodeSPDUs ¶
DecodeSPDUs parses the run of supervisory PDUs in a P-frame's data field.
Clause 3.2.4.1: SPDUs are self-identifying and self-delimiting, so a decoder can walk them without being told how many there are.
type Segment ¶
type Segment struct {
Header SegmentHeader
Data []byte
}
Segment is one segment data unit: a header and a slice of a packet.
func DecodeSegment ¶
DecodeSegment parses a segment data unit from a U-frame's data field.
func Segmentize ¶
Segmentize cuts a packet into segments whose data fields are at most maxSegmentData octets each, tagged with the given pseudo packet ID.
A packet that fits in one segment comes back as a single unsegmented one, which is what the '11' sequence flag is for.
type SegmentHeader ¶
type SegmentHeader struct {
SequenceFlags SequenceFlags
// PseudoPacketID ties the segments of one packet together, 6 bits.
PseudoPacketID uint8
}
SegmentHeader is the one-octet header of a segment data unit (clause 3.2.3.3.2).
bits 0-1: sequence flags bits 2-7: pseudo packet identifier
func (*SegmentHeader) Decode ¶
func (s *SegmentHeader) Decode(data []byte) error
Decode parses a segment header.
func (*SegmentHeader) Encode ¶
func (s *SegmentHeader) Encode() ([]byte, error)
Encode serializes the segment header.
func (*SegmentHeader) Humanize ¶
func (s *SegmentHeader) Humanize() string
Humanize returns a human-readable summary.
func (*SegmentHeader) Validate ¶
func (s *SegmentHeader) Validate() error
Validate checks the header's field widths.
type SequenceFlags ¶
type SequenceFlags uint8
SequenceFlags say where a segment sits relative to its packet, per table 3-4.
const ( // SegmentContinuing is a middle segment ('00'). SegmentContinuing SequenceFlags = 0 // SegmentFirst starts a packet ('01'). SegmentFirst SequenceFlags = 1 // SegmentLast ends a packet ('10'). SegmentLast SequenceFlags = 2 // SegmentUnsegmented carries a whole packet ('11'). SegmentUnsegmented SequenceFlags = 3 )
type SourceOrDest ¶
type SourceOrDest uint8
SourceOrDest is the Source-or-Destination Identifier of clause 3.2.2.9, saying whether the SCID names the sender or the receiver.
const ( // SCIDIsSource means the SCID field names the source spacecraft ('0'). SCIDIsSource SourceOrDest = 0 // SCIDIsDestination means the SCID field names the destination // spacecraft ('1'). SCIDIsDestination SourceOrDest = 1 )
Polarity per clause 3.2.2.9.2, table 3-2: '0' means the SCID field carries the SCID of the spacecraft sending the frame over this link (the MIB parameter Local_Spacecraft_ID), '1' means it carries the SCID of the spacecraft intended to receive it (Remote_Spacecraft_ID).
type TransferFrame ¶
TransferFrame is a Version-3 Transfer Frame: a five-octet header and a data field of up to 2043 octets (clause 3.2.1).
There is no frame error control field. Proximity-1 leaves error detection to the coding layer below, CCSDS 211.2-B-3.
func DecodeTransferFrame ¶
func DecodeTransferFrame(data []byte) (*TransferFrame, error)
DecodeTransferFrame parses a Version-3 Transfer Frame.
func NewSupervisoryFrame ¶
func NewSupervisoryFrame(scid uint16, portID uint8, spdus []byte, opts ...FrameOption) (*TransferFrame, error)
NewSupervisoryFrame builds a P-frame carrying supervisory PDUs.
Clause 3.2.4.1 restricts SPDUs to the Expedited service and clause 3.2.2.5.2 requires a zero DFC ID, so both are set here rather than left to the caller.
portID must be zero: Clause 3.2.2.8.2 leaves the Port ID unused in a P-frame. It is refused rather than forced, because a caller with a port in hand wanted NewTransferFrame.
func NewTransferFrame ¶
func NewTransferFrame(scid uint16, portID uint8, data []byte, opts ...FrameOption) (*TransferFrame, error)
NewTransferFrame builds a U-frame carrying user data.
func (*TransferFrame) Encode ¶
func (f *TransferFrame) Encode() ([]byte, error)
Encode serializes the whole frame.
func (*TransferFrame) Humanize ¶
func (f *TransferFrame) Humanize() string
Humanize returns a human-readable summary.
func (*TransferFrame) IsSupervisoryFrame ¶
func (f *TransferFrame) IsSupervisoryFrame() bool
IsSupervisoryFrame reports whether this is a P-frame.
func (*TransferFrame) IsUserFrame ¶
func (f *TransferFrame) IsUserFrame() bool
IsUserFrame reports whether this is a U-frame.
func (*TransferFrame) SPDUs ¶
func (f *TransferFrame) SPDUs() ([]SPDU, error)
SPDUs parses the supervisory PDUs a P-frame carries.
func (*TransferFrame) Validate ¶
func (f *TransferFrame) Validate() error
Validate checks the frame.
type VariableSPDU ¶
type VariableSPDU struct {
// TypeID selects the kind of directive or report, 3 bits. Annex B
// specifies the types; this package carries the payload without
// interpreting it.
TypeID uint8
// Data holds one or more directives or reports of that type.
Data []byte
}
VariableSPDU is a variable-length supervisory PDU, per clause 3.2.4.2.2.
One octet of header (a zero format bit, a 3-bit type, and a 4-bit length) then up to 15 octets of directives or status reports, all of the same type.
Note the length field is the actual octet count, not a count-less-one. The standard calls that out explicitly, presumably because everything else in CCSDS goes the other way.
func DecodeVariableSPDU ¶
func DecodeVariableSPDU(data []byte) (*VariableSPDU, int, error)
DecodeVariableSPDU parses a variable-length SPDU from the front of data, returning it and the octets consumed.
func (*VariableSPDU) Encode ¶
func (s *VariableSPDU) Encode() ([]byte, error)
Encode serializes the variable-length SPDU.
func (*VariableSPDU) Humanize ¶
func (s *VariableSPDU) Humanize() string
Humanize returns a human-readable summary.
func (*VariableSPDU) Validate ¶
func (s *VariableSPDU) Validate() error
Validate checks the SPDU's field widths.