tmdl

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 29, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// FHPNoPacketStart means no packet begins in this data field.
	FHPNoPacketStart uint16 = 0x07FF
	// FHPOnlyIdleData marks an OID frame: the data field is entirely idle.
	FHPOnlyIdleData uint16 = 0x07FE
)

FirstHeaderPtr values with a meaning of their own, from CCSDS 132.0-B-3 §4.1.2.7.6 and ECSS-E-ST-50-03C 5.2.7.6f and g.

The two are not interchangeable. A frame whose data field simply continues a packet started earlier says NoPacketStart; a frame that is nothing but fill says OnlyIdleData. Telling them apart is the whole reason there are two codes: the first still carries payload, the second can be dropped.

View Source
const IdleFrameVCID uint8 = 7

IdleFrameVCID is the fallback virtual channel for idle frames when the caller knows no better. CCSDS 132.0-B-3 §4.1.4.6.3 requires the VCID of an OID frame to be one of the VCIDs used for transferring packets, so MasterChannel picks a registered packet VCID instead; this constant is used only when no virtual channel is registered at all, where no conformant choice exists.

View Source
const MaxFrameLength = 2048

MaxFrameLength is the longest TM Transfer Frame ECSS-E-ST-50-03C 5.1b allows, in octets.

CCSDS 132.0-B-3 sets no such ceiling; this is the European profile constraining it. A mission following CCSDS alone may exceed it, so the limit is checked by Validate rather than enforced silently.

View Source
const MaxSecondaryHeaderSize = 64

MaxSecondaryHeaderSize is the largest Transfer Frame Secondary Header, counting the identification octet: CCSDS 132.0-B-3 §4.1.3.2 and ECSS-E-ST-50-03C 5.3.1c both cap it at 64 octets.

Variables

View Source
var (
	// ErrDataTooShort indicates the provided data is too short for decoding.
	ErrDataTooShort = errors.New("provided data is too short to decode")

	// ErrInvalidVersion indicates the version number is not 0 for TM Transfer Frame.
	ErrInvalidVersion = errors.New("invalid version: must be 0 for TM Transfer Frame")

	// ErrInvalidSpacecraftID indicates the spacecraft ID is out of range.
	ErrInvalidSpacecraftID = errors.New("invalid spacecraft ID: must be in range 0-1023 (10 bits)")

	// ErrInvalidVCID indicates the virtual channel ID is out of range.
	ErrInvalidVCID = errors.New("invalid virtual channel ID: must be in range 0-7 (3 bits)")

	// ErrInvalidPacketOrderFlag indicates the packet order flag is set when sync flag is 0.
	ErrInvalidPacketOrderFlag = errors.New("invalid packet order flag: must be 0 when sync flag is 0")

	// ErrInvalidSegmentLengthID indicates the segment length ID is invalid for the current sync flag.
	ErrInvalidSegmentLengthID = errors.New("invalid segment length ID: must be 3 (0b11) when sync flag is 0")

	// ErrInvalidFirstHeaderPtr indicates the first header pointer is out of range or inconsistent.
	ErrInvalidFirstHeaderPtr = errors.New("invalid first header pointer: must be in range 0-2047 (11 bits)")

	// ErrInvalidSecondaryHeaderVersion indicates the secondary header version is not 0.
	ErrInvalidSecondaryHeaderVersion = errors.New("invalid secondary header version: must be 0 for Version 1")

	// ErrFrameTooLong indicates a frame length past the 2048-octet maximum of
	// ECSS-E-ST-50-03C 5.1b.
	ErrFrameTooLong = errors.New("frame length exceeds the 2048-octet ECSS maximum")

	// ErrInvalidHeaderLength indicates the secondary header length is out of range.
	ErrInvalidHeaderLength = errors.New("invalid header length: must be in range 0-63 (6 bits)")

	// ErrCRCMismatch indicates the received CRC does not match the computed CRC.
	ErrCRCMismatch = errors.New("CRC mismatch: received CRC does not match computed CRC")

	// ErrDataTooLarge indicates the data field exceeds the maximum frame length.
	ErrDataTooLarge = errors.New("data field exceeds maximum frame length")

	// ErrEmptyData indicates that the provided data is empty.
	ErrEmptyData = errors.New("data cannot be empty")

	// ErrNoFramesAvailable aliases sdl.ErrNoFramesAvailable.
	ErrNoFramesAvailable = sdl.ErrNoFramesAvailable

	// ErrBufferFull aliases sdl.ErrBufferFull.
	ErrBufferFull = sdl.ErrBufferFull

	// ErrSCIDMismatch indicates the frame SCID does not match the master channel SCID.
	ErrSCIDMismatch = errors.New("frame SCID does not match master channel SCID")

	// ErrSizeMismatch indicates the data size does not match the expected fixed size.
	ErrSizeMismatch = errors.New("data size does not match expected fixed size")

	// ErrServiceNotFound aliases sdl.ErrServiceNotFound.
	ErrServiceNotFound = sdl.ErrServiceNotFound

	// ErrMasterChannelNotFound aliases sdl.ErrMasterChannelNotFound.
	ErrMasterChannelNotFound = sdl.ErrMasterChannelNotFound

	// ErrNoVirtualChannels aliases sdl.ErrNoChannels.
	ErrNoVirtualChannels = sdl.ErrNoChannels

	// ErrVirtualChannelNotFound indicates no virtual channel exists for the given VCID.
	ErrVirtualChannelNotFound = errors.New("virtual channel not found for specified VCID")

	// ErrDataFieldTooSmall indicates the data field capacity is too small for framing.
	ErrDataFieldTooSmall = errors.New("data field capacity too small")

	// ErrNoPacketSizer indicates no PacketSizer has been set on the VCP service.
	ErrNoPacketSizer = errors.New("no PacketSizer configured: call SetPacketSizer before Receive")

	// ErrNoMasterChannels aliases sdl.ErrNoMasterChannels.
	ErrNoMasterChannels = sdl.ErrNoMasterChannels

	// ErrInvalidOCFLength indicates the Operational Control Field is not exactly 4 bytes.
	ErrInvalidOCFLength = errors.New("operational control field must be exactly 4 bytes when OCF flag is set")

	// ErrFrameLengthMismatch indicates a frame whose encoded length differs
	// from the fixed ChannelConfig.FrameLength of its physical channel.
	ErrFrameLengthMismatch = errors.New("frame length does not match the fixed channel frame length")

	// ErrFSHNotPresent indicates an FSH_SDU was supplied for a channel whose
	// frames carry no Transfer Frame Secondary Header. Set
	// ChannelConfig.FSHDataLength so the frames have a header to fill.
	ErrFSHNotPresent = errors.New("frame secondary header service configured but frames carry no secondary header")

	// ErrOCFNotPresent indicates an OCF_SDU was supplied for a channel whose
	// frames carry no Operational Control Field. Set ChannelConfig.HasOCF.
	ErrOCFNotPresent = errors.New("operational control field service configured but frames carry no OCF")

	// ErrFSHSizeMismatch indicates an FSH_SDU whose length differs from the
	// channel's fixed ChannelConfig.FSHDataLength. CCSDS 132.0-B-3 §4.1.3.1.6
	// fixes the secondary header length for the channel, so a differently
	// sized SDU cannot be carried.
	ErrFSHSizeMismatch = errors.New("FSH_SDU length does not match the channel's fixed secondary header length")
)

Functions

func IsIdleFrame

func IsIdleFrame(frame *TMTransferFrame) bool

IsIdleFrame reports whether the frame is an OID frame: a data field holding nothing but idle data, per ECSS-E-ST-50-03C 5.2.7.6g.

FHPNoPacketStart is deliberately not accepted here. A frame carrying the continuation of a packet started in an earlier frame also has no packet header in it, and discarding that as idle would lose real payload.

Types

type ChannelConfig

type ChannelConfig struct {
	FrameLength int  // Total frame length in octets (fixed per physical channel)
	HasOCF      bool // Whether Operational Control Field (4 bytes) is present
	HasFEC      bool // Whether Frame Error Control (2-byte CRC) is present

	// FSHDataLength is the length in octets of the Transfer Frame Secondary
	// Header Data Field carried by every frame on the channel, or 0 when the
	// channel carries no secondary header. CCSDS 132.0-B-3 §4.1.3.1.6 fixes
	// the secondary header length for the associated channel throughout a
	// Mission Phase, which is why it is channel configuration rather than a
	// per-frame choice. The encoded header adds one identification octet, so
	// a value of N costs N+1 octets of frame space. Range 1 to 63.
	//
	// Services fill the header from their FSH supplier (the VC_FSH service of
	// §3.5) or with zeros when none is installed; MasterChannel's supplier
	// (the MC_FSH service of §3.8) overwrites it at frame release.
	FSHDataLength int
}

ChannelConfig defines the fixed parameters of a physical channel per CCSDS 132.0-B-3. All frames on a physical channel share the same fixed length and optional field configuration.

func (ChannelConfig) DataFieldCapacity

func (c ChannelConfig) DataFieldCapacity(secondaryHeaderLen int) int

DataFieldCapacity returns the maximum data field size available in frames on this physical channel. secondaryHeaderLen is the length of the secondary header data field (0 if not present); when present, the encoded secondary header adds 1 prefix byte plus secondaryHeaderLen data bytes.

func (ChannelConfig) Validate added in v0.3.0

func (c ChannelConfig) Validate() error

Validate checks the configuration against the profile limits.

It is not called automatically: a CCSDS-only mission may legitimately run frames longer than the ECSS ceiling. Call it when conformance to ECSS-E-ST-50-03C matters.

type FrameCounter

type FrameCounter struct {
	// contains filtered or unexported fields
}

FrameCounter manages 8-bit MC and VC frame counts per CCSDS 132.0-B-3. Share a single FrameCounter across all services for the same spacecraft so the Master Channel count increments correctly.

func NewFrameCounter

func NewFrameCounter() *FrameCounter

NewFrameCounter creates a new FrameCounter.

func (*FrameCounter) Next

func (fc *FrameCounter) Next(vcid uint8) (mc, vc uint8)

Next returns the current MC and VC frame counts for the given VCID, then increments both counters.

type FrameGapDetector

type FrameGapDetector struct {
	// contains filtered or unexported fields
}

FrameGapDetector tracks Master Channel and Virtual Channel frame counts to detect gaps caused by lost frames during transmission. Per CCSDS 132.0-B-3, MCFrameCount and VCFrameCount are 8-bit counters that wrap from 255 to 0.

func NewFrameGapDetector

func NewFrameGapDetector() *FrameGapDetector

NewFrameGapDetector creates a new detector. The first frame seen initializes the expected counts (no gap reported).

func (*FrameGapDetector) MCFrameGap

func (d *FrameGapDetector) MCFrameGap() int

MCFrameGap returns the MC gap detected by the last Track call. 0 means no gap (or first frame).

func (*FrameGapDetector) Track

func (d *FrameGapDetector) Track(frame *TMTransferFrame) (mcGap, vcGap int)

Track examines the frame's MC and VC counts and records any gaps. A gap of N means N frames were lost between the previous frame and this one. Returns the MC gap and VC gap for convenience.

func (*FrameGapDetector) VCFrameGap

func (d *FrameGapDetector) VCFrameGap() int

VCFrameGap returns the VC gap detected by the last Track call. 0 means no gap (or first frame for that VCID).

type MasterChannel

type MasterChannel struct {
	// contains filtered or unexported fields
}

MasterChannel manages TM Transfer Frames for a Master Channel identified by SCID.

func NewMasterChannel

func NewMasterChannel(scid uint16, config ChannelConfig) *MasterChannel

NewMasterChannel creates a new Master Channel for the given spacecraft ID.

func (*MasterChannel) AddFrame

func (mc *MasterChannel) AddFrame(frame *TMTransferFrame) error

AddFrame routes an inbound frame to the appropriate Virtual Channel.

Before routing, the Master Channel Reception Function of CCSDS 132.0-B-3 §4.3.5 decommutates the frame: the secondary header and operational control field SDUs are recorded and readable from LastFSH and LastOCF, which is the delivery path of MC_FSH.indication and MC_OCF.indication.

func (*MasterChannel) AddVirtualChannel

func (mc *MasterChannel) AddVirtualChannel(vc *VirtualChannel, priority int)

AddVirtualChannel registers a Virtual Channel with this Master Channel.

func (*MasterChannel) GetNextFrame

func (mc *MasterChannel) GetNextFrame() (*TMTransferFrame, error)

GetNextFrame retrieves the next frame from the multiplexer, applying the Master Channel Generation Function of CCSDS 132.0-B-3 §4.2.5: the MC_FSH and MC_OCF SDUs, when suppliers are installed, are placed into the frame before it is released.

func (*MasterChannel) GetNextFrameOrIdle

func (mc *MasterChannel) GetNextFrameOrIdle() (*TMTransferFrame, error)

GetNextFrameOrIdle returns the next frame or an idle (OID) frame if none is available, which is the Virtual Channel Multiplexing Function's duty under CCSDS 132.0-B-3 §4.2.4.4: keep the transmitted stream continuous.

Idle frames are stamped from the FrameCounter installed with SetFrameCounter, so their MC and VC frame counts continue the channel's sequence (§4.1.2.5); without a counter they carry zeros. Their data field is filled from the channel's persistent PN generator (§4.1.4.6.2) and their VCID is one that carries packets (§4.1.4.6.3). MC_FSH and MC_OCF SDUs are applied to them like any other released frame.

func (*MasterChannel) HasPendingFrames

func (mc *MasterChannel) HasPendingFrames() bool

HasPendingFrames checks if any Virtual Channel has pending frames.

func (*MasterChannel) LastFSH added in v0.3.0

func (mc *MasterChannel) LastFSH() []byte

LastFSH returns the FSH_SDU carried by the most recently received frame, or nil when none has carried one. It is the MC_FSH.indication of §3.8.3.3; pair it with MCFrameGap for the optional FSH_SDU Loss Flag.

func (*MasterChannel) LastOCF added in v0.3.0

func (mc *MasterChannel) LastOCF() []byte

LastOCF returns the OCF_SDU carried by the most recently received frame, or nil when none has carried one. It is the MC_OCF.indication of §3.9.3.3; pair it with MCFrameGap for the optional OCF_SDU Loss Flag.

func (*MasterChannel) MCFrameGap

func (mc *MasterChannel) MCFrameGap() int

MCFrameGap returns the MC gap from the last AddFrame call.

func (*MasterChannel) SCID

func (mc *MasterChannel) SCID() uint16

SCID returns the Spacecraft Identifier for this Master Channel.

func (*MasterChannel) SetFSHSupplier added in v0.3.0

func (mc *MasterChannel) SetFSHSupplier(supplier func() []byte)

SetFSHSupplier installs the MC_FSH service user (CCSDS 132.0-B-3 §3.8): a callback whose FSH_SDU is placed into the Transfer Frame Secondary Header of every frame released through this Master Channel, per the Master Channel Generation Function of §4.2.5.2. The SDU must be exactly the channel's ChannelConfig.FSHDataLength octets, and frames must carry a secondary header for it to fill — set FSHDataLength on the channel configuration.

func (*MasterChannel) SetFrameCounter added in v0.3.0

func (mc *MasterChannel) SetFrameCounter(counter *FrameCounter)

SetFrameCounter installs the shared FrameCounter used to stamp the MC and VC frame counts of idle frames created by GetNextFrameOrIdle. Pass the same counter the channel's services use, so idle frames continue the master channel count per CCSDS 132.0-B-3 §4.1.2.5 instead of carrying zeros.

func (*MasterChannel) SetIdleVCID added in v0.3.0

func (mc *MasterChannel) SetIdleVCID(vcid uint8)

SetIdleVCID pins the VCID that idle (OID) frames from GetNextFrameOrIdle are emitted on. CCSDS 132.0-B-3 §4.1.4.6.3 requires it to be one of the VCIDs used for transferring packets. Without an explicit choice, the lowest registered Virtual Channel's VCID is used.

func (*MasterChannel) SetOCFSupplier added in v0.3.0

func (mc *MasterChannel) SetOCFSupplier(supplier func() []byte)

SetOCFSupplier installs the MC_OCF service user (CCSDS 132.0-B-3 §3.9): a callback whose 4-octet OCF_SDU is placed into the Operational Control Field of every frame released through this Master Channel, per §4.2.5.3. Frames must carry an OCF for it to fill — set HasOCF on the channel configuration.

func (*MasterChannel) VCFrameGap

func (mc *MasterChannel) VCFrameGap() int

VCFrameGap returns the VC gap from the last AddFrame call.

type OIDSequence added in v0.3.0

type OIDSequence = pn.OIDSequence

OIDSequence generates the mandatory Pseudo Noise (PN) sequence that fills the data field of OID Transfer Frames (CCSDS 132.0-B-3 §4.1.4.6.2, annex D): a 32-cell Fibonacci-form Linear Feedback Shift Register with polynomial D0 + D1 + D2 + D22 + D32, initialized to the 'all ones' state at device start-up and never restarted for subsequent frames. The first octets of the stream are FF FF FF FF 6D B6 D8 61 45 1F. It is safe for concurrent use.

USLP mandates the same generator (CCSDS 732.1-B-3 §4.1.4.1.10), so the implementation is shared with pkg/usdl rather than copied.

func NewOIDSequence added in v0.3.0

func NewOIDSequence() *OIDSequence

NewOIDSequence returns a PN generator in the 'all ones' start-up state. Keep one generator per channel for the life of the device; §4.1.4.6.2.1 forbids restarting the sequence across OID frames.

type PacketSizer

type PacketSizer = sdl.PacketSizer

PacketSizer returns the total length in bytes of the packet starting at data[0], or -1 if the data is too short to determine length.

type PhysicalChannel

type PhysicalChannel struct {
	Name string // Channel identifier (e.g., "X-band")
	// contains filtered or unexported fields
}

PhysicalChannel represents a single physical communication link that carries one or more Master Channels. It handles MC-level multiplexing (send path) and demultiplexing (receive path) per CCSDS 132.0-B-3. For sync-layer operations (ASM, randomization, CADU wrapping), use the tmsc package (CCSDS 131.0-B-4).

func NewPhysicalChannel

func NewPhysicalChannel(name string, config ChannelConfig) *PhysicalChannel

NewPhysicalChannel creates a physical channel with the given configuration.

func (*PhysicalChannel) AddFrame

func (pc *PhysicalChannel) AddFrame(frame *TMTransferFrame) error

AddFrame demultiplexes an inbound frame to the appropriate Master Channel based on the Spacecraft ID in the frame header.

func (*PhysicalChannel) AddMasterChannel

func (pc *PhysicalChannel) AddMasterChannel(mc *MasterChannel, priority int)

AddMasterChannel registers a Master Channel with a priority weight for the MC multiplexing scheme. Priority must be at least 1.

func (*PhysicalChannel) GetNextFrame

func (pc *PhysicalChannel) GetNextFrame() (*TMTransferFrame, error)

GetNextFrame selects the next frame for transmission using weighted round-robin MC multiplexing across registered Master Channels.

func (*PhysicalChannel) GetNextFrameOrIdle

func (pc *PhysicalChannel) GetNextFrameOrIdle() (*TMTransferFrame, error)

GetNextFrameOrIdle returns the next frame from MC multiplexing, or an idle frame if no Master Channel has pending data.

The idle frame comes from a deterministically chosen Master Channel — the lowest registered SCID — which builds it per CCSDS 132.0-B-3 §4.2.6.4: on a packet-carrying VCID, counted by the channel's FrameCounter, filled from its persistent PN generator, and carrying its MC_FSH/MC_OCF SDUs when suppliers are installed. With no Master Channel registered at all, a bare idle frame is produced with SCID 0 and the fallback IdleFrameVCID, drawing on the physical channel's own PN generator.

func (*PhysicalChannel) HasPendingFrames

func (pc *PhysicalChannel) HasPendingFrames() bool

HasPendingFrames checks if any Master Channel has pending frames.

func (*PhysicalChannel) Len

func (pc *PhysicalChannel) Len() int

Len returns the number of registered Master Channels.

type PrimaryHeader

type PrimaryHeader struct {
	VersionNumber    uint8  // 2 bits (0-1)   - Transfer Frame Version Number (00 for TM)
	SpacecraftID     uint16 // 10 bits (2-11) - Spacecraft Identifier
	VirtualChannelID uint8  // 3 bits (12-14) - Virtual Channel Identifier
	OCFFlag          bool   // 1 bit (15)     - Operational Control Field Flag
	MCFrameCount     uint8  // 8 bits (16-23) - Master Channel Frame Count
	VCFrameCount     uint8  // 8 bits (24-31) - Virtual Channel Frame Count
	FSHFlag          bool   // 1 bit (32)     - Frame Secondary Header Flag
	SyncFlag         bool   // 1 bit (33)     - Synchronization Flag
	PacketOrderFlag  bool   // 1 bit (34)     - Packet Order Flag
	SegmentLengthID  uint8  // 2 bits (35-36) - Segment Length Identifier
	FirstHeaderPtr   uint16 // 11 bits (37-47) - First Header Pointer
}

PrimaryHeader represents the CCSDS TM Transfer Frame Primary Header.

func (*PrimaryHeader) Decode

func (h *PrimaryHeader) Decode(data []byte) error

Decode parses a byte slice into the PrimaryHeader.

func (*PrimaryHeader) Encode

func (h *PrimaryHeader) Encode() ([]byte, error)

Encode packs the PrimaryHeader fields into a byte slice.

func (*PrimaryHeader) GVCID

func (h *PrimaryHeader) GVCID() uint16

GVCID returns the Global Virtual Channel Identifier.

func (*PrimaryHeader) Humanize

func (h *PrimaryHeader) Humanize() string

Humanize generates a human-readable representation of the PrimaryHeader.

func (*PrimaryHeader) MCID

func (h *PrimaryHeader) MCID() uint16

MCID returns the Master Channel Identifier (MCID) for the TM Transfer Frame.

func (*PrimaryHeader) Validate

func (h *PrimaryHeader) Validate() error

Validate checks if the header values are within valid ranges.

With the Synchronization Flag set, the Packet Order Flag, Segment Length Identifier, and First Header Pointer are undefined by CCSDS 132.0-B-3 (notes under §4.1.2.7.4 through §4.1.2.7.6), and §3.4.2.3 hands those bits to the VCA service user as the VCA Status Fields — so any value passes here. With the flag clear, the Packet Order Flag must be '0' and the Segment Length Identifier '11'.

type SecondaryHeader

type SecondaryHeader struct {
	VersionNumber uint8 // 2 bits (0-1) - Always `00` for Version 1
	// HeaderLength is the field of bits 2-7. CCSDS 132.0-B-3 §4.1.3.2.2.3 and
	// ECSS-E-ST-50-03C 5.3.2.3c define it as the TOTAL secondary header length
	// in octets minus one — the total being this identification octet plus the
	// data field. So for an N-octet data field the value is N, not N-1.
	HeaderLength uint8
	DataField    []byte // Transfer Frame Secondary Header Data
}

SecondaryHeader represents the Transfer Frame Secondary Header as per CCSDS 132.0-B-3.

func (*SecondaryHeader) Decode

func (sh *SecondaryHeader) Decode(data []byte) error

Decode deserializes a byte slice into the SecondaryHeader.

func (*SecondaryHeader) Encode

func (sh *SecondaryHeader) Encode() ([]byte, error)

Encode serializes the SecondaryHeader into a byte slice.

func (*SecondaryHeader) Humanize

func (sh *SecondaryHeader) Humanize() string

Humanize generates a human-readable representation of the SecondaryHeader.

func (*SecondaryHeader) SetDataField added in v0.3.0

func (sh *SecondaryHeader) SetDataField(data []byte) error

SetDataField installs the data field and derives HeaderLength from it, which is the safe way to build a secondary header by hand.

func (*SecondaryHeader) TotalLength added in v0.3.0

func (sh *SecondaryHeader) TotalLength() int

TotalLength returns the encoded size of the secondary header in octets.

func (*SecondaryHeader) Validate

func (sh *SecondaryHeader) Validate() error

Validate checks if the header values are within valid ranges.

type Service

type Service = sdl.Service

Service is the interface for all TM Data Link services.

type ServiceType

type ServiceType int

ServiceType defines the types of TM services available.

const (
	VCP ServiceType = iota // Virtual Channel Packet Service
	VCA                    // Virtual Channel Access Service
	VCF                    // Virtual Channel Frame Service
)

type TMServiceManager

type TMServiceManager = sdl.ServiceManager[ServiceType, *TMTransferFrame]

TMServiceManager manages multiple TM services and Master Channels, wiring the pipeline: Service → VirtualChannel → Mux → MasterChannel.

func NewTMServiceManager

func NewTMServiceManager() *TMServiceManager

NewTMServiceManager creates a new TM Service Manager.

type TMTransferFrame

type TMTransferFrame struct {
	Header             PrimaryHeader
	SecondaryHeader    SecondaryHeader
	DataField          []byte // Main telemetry data
	OperationalControl []byte // 4-byte OCF (if used)
	FrameErrorControl  uint16 // 16-bit CRC (Error Control)
}

TMTransferFrame represents a CCSDS TM Space Data Link Protocol Transfer Frame.

func DecodeTMTransferFrame

func DecodeTMTransferFrame(data []byte) (*TMTransferFrame, error)

DecodeTMTransferFrame parses a byte slice into a TM Transfer Frame, treating the last two octets as a Frame Error Control Field and verifying them.

Use DecodeTMTransferFrameWithConfig for a channel that carries no such field, which §5.6.1b permits under Reed-Solomon coding.

func DecodeTMTransferFrameWithConfig added in v0.3.0

func DecodeTMTransferFrameWithConfig(data []byte, config ChannelConfig) (*TMTransferFrame, error)

DecodeTMTransferFrameWithConfig parses a frame, verifying the Frame Error Control Field only when the channel carries one.

When config.FrameLength is set, the input must be exactly that long — frames on a physical channel are fixed-length per CCSDS 132.0-B-3 §2.1.3 — and any other size returns ErrFrameLengthMismatch.

func NewIdleFrame

func NewIdleFrame(scid uint16, vcid uint8, config ChannelConfig) (*TMTransferFrame, error)

NewIdleFrame creates an idle (OID) TM Transfer Frame: a PN-filled data field with the First Header Pointer set to FHPOnlyIdleData, per CCSDS 132.0-B-3 §4.1.2.7.6.5 and §4.1.4.6.

The frame's MC and VC counts are zero and its PN sequence starts fresh. Use NewIdleFrameWithCounter so idle frames continue the master channel sequence and draw from the channel's persistent PN generator.

func NewIdleFrameWithCounter added in v0.3.0

func NewIdleFrameWithCounter(scid uint16, vcid uint8, config ChannelConfig, counter *FrameCounter, fill *OIDSequence) (*TMTransferFrame, error)

NewIdleFrameWithCounter creates an idle (OID) TM Transfer Frame, stamps its MC and VC frame counts from the given counter, and fills its data field from the given PN generator.

Pass the same FrameCounter the channel's services use: CCSDS 132.0-B-3 §4.1.2.5 counts every frame of the master channel, idle frames included, so an unstamped idle frame breaks the MC sequence at any conformant receiver. A nil counter leaves both counts zero.

Pass the channel's persistent OIDSequence: §4.1.4.6.2 mandates the PN fill and forbids restarting the generator between frames. A nil fill starts a fresh sequence for this frame only, which is fine for a single frame but repeats the same octets on every frame of a long-lived sender — MasterChannel keeps one generator for exactly this reason.

When the channel carries a secondary header (config.FSHDataLength > 0) the idle frame includes a zero-filled one: §4.1.2.7.2.3 keeps the Secondary Header Flag static across the channel, and the OID notes under §4.1.4.6 expect the header to stay usable on idle frames. MasterChannel overwrites it from the MC_FSH supplier when one is installed. The same applies to the Operational Control Field under config.HasOCF.

func NewTMTransferFrame

func NewTMTransferFrame(scid uint16, vcid uint8, data []byte, secondaryHeaderData []byte, ocf []byte) (*TMTransferFrame, error)

NewTMTransferFrame initializes a new TM Transfer Frame.

func (*TMTransferFrame) Encode

func (tf *TMTransferFrame) Encode() ([]byte, error)

Encode converts the TM Transfer Frame to a byte slice.

The Frame Error Control Field is computed from the frame's current contents on every call, so header or data changes made after construction are always covered. Use EncodeWithoutFEC to build a frame with a deliberately invalid CRC.

func (*TMTransferFrame) EncodeWithConfig added in v0.3.0

func (tf *TMTransferFrame) EncodeWithConfig(config ChannelConfig) ([]byte, error)

EncodeWithConfig converts the frame to bytes, appending the Frame Error Control Field only when the channel carries one.

CCSDS 132.0-B-3 §4.1.6 and ECSS-E-ST-50-03C 5.6.1b make the field mandatory when the frame is not Reed-Solomon encoded, and optional when it travels inside a code block — the code block already protects it. §5.6.1c then requires the choice to hold for the whole physical channel, which is why it belongs to ChannelConfig rather than to a single frame.

When config.FrameLength is set, the encoded frame must come out exactly that long — CCSDS 132.0-B-3 §2.1.3 fixes the frame length per physical channel — and any other size returns ErrFrameLengthMismatch.

func (*TMTransferFrame) EncodeWithoutFEC

func (tf *TMTransferFrame) EncodeWithoutFEC() ([]byte, error)

EncodeWithoutFEC converts the frame to bytes excluding the CRC field.

type VCAStatus

type VCAStatus struct {
	SyncFlag        bool
	PacketOrderFlag bool
	SegmentLengthID uint8
	FirstHeaderPtr  uint16
}

VCAStatus contains the VCA Status Fields of CCSDS 132.0-B-3 §3.4.2.3: the Packet Order Flag, the Segment Length Identifier, and the First Header Pointer of the Transfer Frame Data Field Status. With the Synchronization Flag set these bits are undefined by CCSDS and belong to the VCA service user, who gives them whatever meaning the mission needs — validity, sequence, or other status of the VCA_SDU. Providing the field is mandatory; the semantics are user-optional.

SyncFlag is reported on receive for completeness. It is not a status field the user sets: §4.1.2.7.3.2 fixes it at '1' for a frame carrying a VCA_SDU, and VirtualChannelAccessService.Send always sets it.

type VirtualChannel

type VirtualChannel = sdl.Channel[*TMTransferFrame]

VirtualChannel is a frame buffer for a single TM virtual channel.

func NewVirtualChannel

func NewVirtualChannel(vcid uint8, bufferSize int) *VirtualChannel

NewVirtualChannel creates a new TM Virtual Channel with the given VCID and buffer capacity.

type VirtualChannelAccessService

type VirtualChannelAccessService struct {
	// contains filtered or unexported fields
}

VirtualChannelAccessService implements the VCA service.

func NewVirtualChannelAccessService

func NewVirtualChannelAccessService(scid uint16, vcid uint8, vcaSize int, vc *VirtualChannel, config ChannelConfig, counter *FrameCounter) *VirtualChannelAccessService

NewVirtualChannelAccessService creates a new VCA service instance.

func (*VirtualChannelAccessService) Flush

Flush is a no-op for VCA service.

func (*VirtualChannelAccessService) LastFSH added in v0.3.0

func (s *VirtualChannelAccessService) LastFSH() []byte

LastFSH returns the FSH_SDU carried by the most recently received frame, or nil when none carried one (the VC_FSH.indication of §3.5.3.3).

func (*VirtualChannelAccessService) LastStatus

func (s *VirtualChannelAccessService) LastStatus() VCAStatus

LastStatus returns the status fields from the most recent Receive.

func (*VirtualChannelAccessService) Receive

func (s *VirtualChannelAccessService) Receive() ([]byte, error)

Receive retrieves the next frame and returns its data field.

func (*VirtualChannelAccessService) Send

func (s *VirtualChannelAccessService) Send(data []byte) error

Send wraps a fixed-length SDU into a TM Transfer Frame.

CCSDS 132.0-B-3 §3.4.2.2 fixes the VCA_SDU length per virtual channel, so data must be exactly vcaSize octets. On a fixed-length channel the SDU must also fit the data field: a vcaSize past DataFieldCapacity returns ErrDataTooLarge, since the padding a larger SDU would force could not be told apart from SDU content by any receiver.

func (*VirtualChannelAccessService) SetFSHSupplier added in v0.3.0

func (s *VirtualChannelAccessService) SetFSHSupplier(supplier func() []byte)

SetFSHSupplier installs the VC_FSH service user (CCSDS 132.0-B-3 §3.5) for this virtual channel; see VirtualChannelPacketService.SetFSHSupplier.

func (*VirtualChannelAccessService) SetOCFSupplier added in v0.3.0

func (s *VirtualChannelAccessService) SetOCFSupplier(supplier func() []byte)

SetOCFSupplier installs a callback that supplies the 4-octet Operational Control Field (typically a CLCW) for every frame emitted on a channel configured with HasOCF. Without a supplier the field is all zeros.

func (*VirtualChannelAccessService) SetSendStatus added in v0.3.0

func (s *VirtualChannelAccessService) SetSendStatus(status VCAStatus)

SetSendStatus sets the VCA Status Fields carried by frames from subsequent Send calls. It is the VCA Status Fields parameter of the VCA.request primitive (CCSDS 132.0-B-3 §3.4.3.2.2), a mandatory parameter whose semantics belong to the service user.

The Synchronization Flag field of the argument is ignored: §4.1.2.7.3.2 fixes it at '1' for a frame carrying a VCA_SDU, and Send always sets it.

type VirtualChannelFrameService

type VirtualChannelFrameService struct {
	// contains filtered or unexported fields
}

VirtualChannelFrameService implements the VCF service.

func NewVirtualChannelFrameService

func NewVirtualChannelFrameService(vcid uint8, vc *VirtualChannel) *VirtualChannelFrameService

NewVirtualChannelFrameService creates a new VCF service instance.

func (*VirtualChannelFrameService) Flush

func (s *VirtualChannelFrameService) Flush() error

Flush is a no-op for VCF service.

func (*VirtualChannelFrameService) Receive

func (s *VirtualChannelFrameService) Receive() ([]byte, error)

Receive retrieves the next frame from the Virtual Channel and returns it as encoded bytes.

func (*VirtualChannelFrameService) Send

func (s *VirtualChannelFrameService) Send(data []byte) error

Send decodes the provided bytes as a TM Transfer Frame and pushes it into the Virtual Channel.

func (*VirtualChannelFrameService) SetChannelConfig added in v0.3.0

func (s *VirtualChannelFrameService) SetChannelConfig(config ChannelConfig)

SetChannelConfig tells the service how its channel is framed, which matters only for HasFEC: a channel carrying no Frame Error Control Field needs the pass-through decode and re-encode to agree with it.

type VirtualChannelMultiplexer

type VirtualChannelMultiplexer = sdl.Multiplexer[*TMTransferFrame]

VirtualChannelMultiplexer is a weighted round-robin frame scheduler for TM Virtual Channels.

func NewMultiplexer

func NewMultiplexer() *VirtualChannelMultiplexer

NewMultiplexer creates a new TM Virtual Channel multiplexer.

type VirtualChannelPacketService

type VirtualChannelPacketService struct {
	// contains filtered or unexported fields
}

VirtualChannelPacketService implements the VCP service. When ChannelConfig is set, packets are packed into fixed-length frames using native CCSDS FirstHeaderPtr for boundary detection, with FHP-based resync on frame loss. A PacketSizer must be set via SetPacketSizer before calling Receive (e.g., spp.PacketSizer for CCSDS Space Packets).

func NewVirtualChannelPacketService

func NewVirtualChannelPacketService(scid uint16, vcid uint8, vc *VirtualChannel, config ChannelConfig, counter *FrameCounter) *VirtualChannelPacketService

NewVirtualChannelPacketService creates a new VCP service instance. Gap-based resync is enabled automatically when a FrameCounter is provided. For pure receivers (counter=nil) that consume externally-stamped frames, call SetGapResync(true) to enable resync on frame loss.

func (*VirtualChannelPacketService) Flush

Flush fills any remaining buffered data up to a frame boundary with an SPP idle packet (APID 0x7FF) and emits the resulting frame(s). Only meaningful when ChannelConfig is set.

CCSDS 132.0-B-3 §4.2.2 and ECSS-E-ST-50-03C 5.4.3.4g require spare data field space to carry idle packets a conformant receiver can parse and discard, not raw fill it would misread as a packet header. When the spare space is under the seven-octet minimum packet size, the idle packet spans into one or more following frames, so Flush may emit more than one frame.

func (*VirtualChannelPacketService) LastFSH added in v0.3.0

func (s *VirtualChannelPacketService) LastFSH() []byte

LastFSH returns the FSH_SDU carried by the most recently received frame, or nil when none carried one. It is the VC_FSH.indication of §3.5.3.3; pair it with the VC frame gap for the optional FSH_SDU Loss Flag.

func (*VirtualChannelPacketService) Receive

func (s *VirtualChannelPacketService) Receive() ([]byte, error)

Receive extracts the next complete packet from frame data. When ChannelConfig is not set, returns the data field of one frame (legacy). When ChannelConfig is set, uses FHP to find packet boundaries and PacketSizer to determine packet length. Resyncs after frame loss.

func (*VirtualChannelPacketService) Send

func (s *VirtualChannelPacketService) Send(data []byte) error

Send appends packet data to the send buffer and generates full frames. When ChannelConfig is set, packs packets into fixed-length frames with proper FirstHeaderPtr. Call Flush() after the last Send() to emit any remaining partial frame, padded with SPP idle packets.

When ChannelConfig is not set, Send creates one variable-length frame per packet. That legacy path violates the fixed-frame-length rule of CCSDS 132.0-B-3 §2.1.3 and exists only for in-process loopback and tests; set ChannelConfig.FrameLength for anything that leaves the process.

func (*VirtualChannelPacketService) SetFSHSupplier added in v0.3.0

func (s *VirtualChannelPacketService) SetFSHSupplier(supplier func() []byte)

SetFSHSupplier installs the VC_FSH service user (CCSDS 132.0-B-3 §3.5): a callback whose FSH_SDU fills the Transfer Frame Secondary Header of every frame this service emits. The SDU must be exactly ChannelConfig.FSHDataLength octets. Without a supplier the header is zero-filled, since §4.1.3.1.5 requires it in every frame of the channel once the channel carries one.

func (*VirtualChannelPacketService) SetGapResync added in v0.3.0

func (s *VirtualChannelPacketService) SetGapResync(enabled bool)

SetGapResync enables or disables gap-based resync on the receive side. When enabled, the receiver discards partially-assembled packets whenever a frame gap is detected. Enable this for pure receivers that consume externally-stamped frames without a local FrameCounter.

func (*VirtualChannelPacketService) SetOCFSupplier added in v0.3.0

func (s *VirtualChannelPacketService) SetOCFSupplier(supplier func() []byte)

SetOCFSupplier installs a callback that supplies the 4-octet Operational Control Field (typically a CLCW) for every frame emitted on a channel configured with HasOCF. Without a supplier the field is all zeros, which a receiver reads as an empty Type-1-Report; per CCSDS 132.0-B-3 §4.1.5 the field content should come from the OCF service user.

func (*VirtualChannelPacketService) SetPacketSizer

func (s *VirtualChannelPacketService) SetPacketSizer(sizer PacketSizer)

SetPacketSizer configures the PacketSizer used by Receive() to detect packet boundaries. Must be set before calling Receive() when ChannelConfig is set (e.g., pass spp.PacketSizer for Space Packets).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL