sle

package
v0.4.0 Latest Latest
Warning

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

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

Documentation

Overview

Package sle implements the foundation of the CCSDS Space Link Extension transfer services: the Internet SLE Protocol One transport, a BER codec for SLE protocol data units, ISP1 credentials, and the association handshake.

SLE is how ground systems move space link data between each other. A mission control centre opens a TCP connection to a ground station and either receives telemetry (frames, channel frames, operational control fields) or sends telecommand transmission units. This library already produces and consumes exactly those payloads: CADUs from pkg/tmsc, CLTUs from pkg/tcsc, CLCWs from pkg/cop. SLE is the wire between ground systems.

The standard numbers

The SLE suite is easy to misattribute, so for the record:

CCSDS 913.1-B-2   ISP1, the transport this package implements
CCSDS 911.1-B-5   Return All Frames
CCSDS 911.2-B-4   Return Channel Frames
CCSDS 911.5-B-4   Return Operational Control Fields
CCSDS 912.1-B-5   Forward CLTU

CCSDS 914.0-M-2 is the SLE Application Program Interface, a Recommended Practice rather than a Blue Book, and is not a wire specification.

Three design decisions

First, this package owns no goroutines and no timers. Every codec is pure and the association state machine is caller-pumped, the same contract as pkg/cop's FOP-1: you feed it inbound messages and ask what to send. ISP1 has a heartbeat and a dead factor; this package tells you when a heartbeat is due and when a peer has gone silent, and your scheduler acts on it. Actual TCP I/O is yours.

Second, the BER codec here is a deliberate subset. Go's encoding/asn1 is DER-oriented and cannot round-trip SLE PDUs: it rejects the context-specific CHOICE tagging the SLE modules rely on. Rather than take a dependency, this package carries just enough BER to encode and decode what SLE actually sends, developed against the ASN.1 modules in the service specifications. It emits definite lengths only, and accepts the indefinite form on decode, because real providers emit it.

Third, ISP1 credentials hash with SHA-256, per CCSDS 913.1-B-2 clause 3.1.2.3. SHA-1 belonged to the previous issue of the standard. A 20-octet legacy digest still decodes (no other length but 20 or 32 does) but it cannot be verified, because this package does not implement the superseded scheme: verification requires SHA-256, and only SHA-256 is ever generated.

What is here

The transport and the handshake: TML message framing, the context and heartbeat messages, BER, credentials, and BIND, UNBIND and PEER-ABORT, including the OBJECT IDENTIFIER form of the service instance identifier and the primitive [104] PEER-ABORT encoding. On top of that, the four transfer services themselves: RAF, RCF, ROCF and FCLTU, each as a caller-pumped user machine and a provider. On the provider side, Production runs the transfer buffer and the production status of clause 3.1.9 and annex B, and Complex serves several service instances and routes an inbound BIND between them. GET-PARAMETER decodes and answers cleanly, and the per-service parameter sets are named: all 50 alternatives across the four services, with integer values read and structured ones left as raw BER. See docs/content/conformance/sle.md for the row-by-row conformance picture.

Index

Constants

View Source
const (
	// ClassUniversal is the class of the built-in ASN.1 types.
	ClassUniversal uint8 = 0x00
	// ClassApplication is the application class.
	ClassApplication uint8 = 0x40
	// ClassContext is the context-specific class, which SLE uses for every
	// CHOICE alternative and every tagged field.
	ClassContext uint8 = 0x80
	// ClassPrivate is the private class.
	ClassPrivate uint8 = 0xC0
)

Tag classes, per X.690 clause 8.1.2.2.

View Source
const (
	TagBoolean          uint8 = 1
	TagInteger          uint8 = 2
	TagBitString        uint8 = 3
	TagOctetString      uint8 = 4
	TagNull             uint8 = 5
	TagObjectIdentifier uint8 = 6
	TagEnumerated       uint8 = 10
	TagSequence         uint8 = 16
	TagSet              uint8 = 17
	TagVisibleString    uint8 = 26
)

Universal tag numbers SLE uses.

View Source
const (
	// FrameVersionTM is a TM Transfer Frame, called Version 1.
	FrameVersionTM uint8 = 0
	// FrameVersionAOS is an AOS Transfer Frame, called Version 2.
	FrameVersionAOS uint8 = 1
	// FrameVersionUSLP is a USLP Transfer Frame, called Version 4.
	FrameVersionUSLP uint8 = 12
)

Transfer frame version numbers as a GVCID carries them, from the GvcId SEQUENCE of CCSDS 911.2-B-4 annex A.

Note USLP is 12, not 4. The value is the four-bit Transfer Frame Version Number as it appears on the wire ('1100' binary) rather than the "Version 4" the protocol is called.

View Source
const (
	MinReportingCycle = 2
	MaxReportingCycle = 600
)

MinReportingCycle and MaxReportingCycle bound a periodic reporting cycle: ReportingCycle ::= INTEGER (2 .. 600), in seconds.

View Source
const (
	// DigestSizeSHA256 is what this package generates.
	DigestSizeSHA256 = 32
	// DigestSizeSHA1 is the legacy size, accepted on receive only.
	DigestSizeSHA1 = 20
)

Digest sizes, per clause 3.2.3 note 2.

View Source
const (
	TagFCLTUBindInvocation                 uint32 = 100
	TagFCLTUBindReturn                     uint32 = 101
	TagFCLTUUnbindInvocation               uint32 = 102
	TagFCLTUUnbindReturn                   uint32 = 103
	TagFCLTUPeerAbortInvocation            uint32 = 104
	TagFCLTUStartInvocation                uint32 = 0
	TagFCLTUStartReturn                    uint32 = 1
	TagFCLTUStopInvocation                 uint32 = 2
	TagFCLTUStopReturn                     uint32 = 3
	TagFCLTUScheduleStatusReportInvocation uint32 = 4
	TagFCLTUScheduleStatusReportReturn     uint32 = 5
	TagFCLTUGetParameterInvocation         uint32 = 6
	TagFCLTUGetParameterReturn             uint32 = 7
	TagFCLTUThrowEventInvocation           uint32 = 8
	TagFCLTUThrowEventReturn               uint32 = 9
	TagFCLTUTransferDataInvocation         uint32 = 10
	TagFCLTUTransferDataReturn             uint32 = 11
	TagFCLTUAsyncNotifyInvocation          uint32 = 12
	TagFCLTUStatusReportInvocation         uint32 = 13
)

FCLTU PDU tags, from the CltuUserToProviderPdu and CltuProviderToUserPdu CHOICEs of annex A2.4 and A2.5.

These are not the return services' numbers. Tags [8] and [9] are THROW-EVENT here, where RAF uses them for TRANSFER-BUFFER and STATUS-REPORT, and FCLTU's STATUS-REPORT sits up at [13]. Decoding an FCLTU PDU with a return-service table would silently name the wrong operation, which is why DecodePDU takes a ServiceKind.

View Source
const (
	TagRAFBindInvocation                 uint32 = 100
	TagRAFBindReturn                     uint32 = 101
	TagRAFUnbindInvocation               uint32 = 102
	TagRAFUnbindReturn                   uint32 = 103
	TagRAFPeerAbortInvocation            uint32 = 104
	TagRAFStartInvocation                uint32 = 0
	TagRAFStartReturn                    uint32 = 1
	TagRAFStopInvocation                 uint32 = 2
	TagRAFStopReturn                     uint32 = 3
	TagRAFScheduleStatusReportInvocation uint32 = 4
	TagRAFScheduleStatusReportReturn     uint32 = 5
	TagRAFGetParameterInvocation         uint32 = 6
	TagRAFGetParameterReturn             uint32 = 7
	TagRAFTransferBuffer                 uint32 = 8
	TagRAFStatusReportInvocation         uint32 = 9
)

RAF PDU tags, from the RafUsertoProviderPdu and RafProviderToUserPdu CHOICEs of annex A2.6 and A2.7.

The BIND family shares tags [100] to [104] across every service; the service-specific operations take the low numbers.

View Source
const Constructed uint8 = 0x20

Constructed is the bit marking a constructed rather than primitive encoding (X.690 clause 8.1.2.5).

View Source
const ContextBodySize = 12

ContextBodySize is the width of a context message body (clause 3.3.2.2.4).

View Source
const DefaultMaxLength = 16 << 20

DefaultMaxLength bounds a decoded BER value when no limit is given: 16 MiB.

A BER length field can name a value far larger than any real SLE PDU. Sizing an allocation from one is a trivial denial of service, so the decoder always works against a ceiling.

View Source
const DefaultMaxMessageSize = 16 << 20

DefaultMaxMessageSize bounds a TML message body when no limit is given: 16 MiB. The length field is 32 bits, so without a cap one message could name four gigabytes.

View Source
const MaxEventQualifier = 1024

MaxEventQualifier is the largest eventQualifier a THROW-EVENT may carry: OCTET STRING (SIZE (1 .. 1024)).

View Source
const MaxRandomNumber = 2147483647

MaxRandomNumber is the upper bound of the randomNumber field, per the HashInput type of figure 3-1: INTEGER (0 .. 2147483647).

View Source
const MaxSpaceLinkDataUnit = 65536

MaxSpaceLinkDataUnit is the largest SpaceLinkDataUnit, per the common types module: OCTET STRING (SIZE (1 .. 65536)).

View Source
const ProtocolVersion uint8 = 1

ProtocolVersion is the version a context message carries (clause 3.3.2.2.4 c).

View Source
const TMLHeaderSize = 8

TMLHeaderSize is the width of a TML message header in octets (clause 3.3.2.2.1).

View Source
const TimeCCSDSPicoSize = 10

TimeCCSDSPicoSize is the width of the picosecond-resolution variant.

View Source
const TimeCCSDSSize = 8

TimeCCSDSSize is the width of the SLE time field in octets.

Variables

View Source
var (
	// ErrDataTooShort indicates the input ended before a field it must contain.
	ErrDataTooShort = errors.New("data too short for the SLE field being read")

	// ErrInvalidTag indicates a BER tag the decoder did not expect here.
	ErrInvalidTag = errors.New("unexpected BER tag")

	// ErrInvalidLength indicates a BER length that is malformed or beyond the
	// bytes available.
	ErrInvalidLength = errors.New("invalid BER length")

	// ErrIndefiniteLength indicates the indefinite-length form on a primitive
	// encoding, which X.690 clause 8.1.3.2 forbids. Constructed indefinite-length
	// encodings are accepted.
	ErrIndefiniteLength = errors.New("indefinite BER length on a primitive encoding")

	// ErrInvalidObjectIdentifier indicates an OBJECT IDENTIFIER that cannot
	// be encoded or decoded.
	ErrInvalidObjectIdentifier = errors.New("invalid object identifier")

	// ErrLengthTooLarge indicates a BER length beyond the configured maximum.
	// A length field can name far more than any real PDU contains, so a cap
	// is what stops one hostile message exhausting memory.
	ErrLengthTooLarge = errors.New("BER length exceeds the maximum this decoder accepts")

	// ErrIntegerOverflow indicates a BER INTEGER too large for the Go type
	// receiving it.
	ErrIntegerOverflow = errors.New("BER integer does not fit")

	// ErrInvalidMessageType indicates a TML message type outside the three of
	// CCSDS 913.1-B-2 table 3-1.
	ErrInvalidMessageType = errors.New("invalid TML message type")

	// ErrInvalidProtocolID indicates a TML context message whose protocol
	// identification is not 'ISP1'.
	ErrInvalidProtocolID = errors.New("invalid TML protocol identification: expected ISP1")

	// ErrInvalidProtocolVersion indicates a TML context message with a
	// protocol version other than 1.
	ErrInvalidProtocolVersion = errors.New("invalid TML protocol version")

	// ErrInvalidContextLength indicates a TML context message body that is not
	// the 12 octets clause 3.3.2.2.4 requires.
	ErrInvalidContextLength = errors.New("TML context message body must be 12 octets")

	// ErrInvalidContextParameters indicates a TML context message whose
	// parameters are out of range: a nonzero heartbeat interval needs a
	// nonzero dead factor.
	ErrInvalidContextParameters = errors.New("invalid TML context parameters")

	// ErrNonEmptyHeartbeat indicates a heartbeat message carrying a body,
	// contrary to clause 3.3.2.2.5.
	ErrNonEmptyHeartbeat = errors.New("TML heartbeat message must have an empty body")

	// ErrMessageTooLarge indicates a TML message body beyond the configured
	// maximum.
	ErrMessageTooLarge = errors.New("TML message body exceeds the maximum this reader accepts")

	// ErrInvalidCredentials indicates credentials that cannot be decoded.
	ErrInvalidCredentials = errors.New("invalid credentials")

	// ErrAuthenticationFailed indicates a credential digest that did not match.
	ErrAuthenticationFailed = errors.New("authentication failed")

	// ErrCredentialsExpired indicates credentials whose time is further from
	// now than the acceptable delay, per clause 3.1.2.2.1.
	ErrCredentialsExpired = errors.New("credentials are outside the acceptable time window")

	// ErrInvalidIdentifier indicates an authority identifier outside the
	// 3-to-16 character range, or one containing a space.
	ErrInvalidIdentifier = errors.New("invalid authority identifier")

	// ErrInvalidVersionNumber indicates a version number outside 1 to 65535.
	ErrInvalidVersionNumber = errors.New("invalid version number: must be 1 to 65535")

	// ErrWrongState indicates an operation the association state does not allow.
	ErrWrongState = errors.New("operation not allowed in the current association state")

	// ErrInvalidProductionConfig indicates a transfer buffer size below one
	// or a negative latency limit.
	ErrInvalidProductionConfig = errors.New("invalid production configuration")

	// ErrProductionNotRunning indicates a frame offered while production is
	// halted or interrupted. A provider in either state has no data to
	// deliver, and buffering one anyway would deliver it late and out of
	// sequence when production resumed.
	ErrProductionNotRunning = errors.New("production is not running")

	// ErrDuplicateInstance indicates two service instances configured with
	// one identifier. A BIND naming it would be ambiguous, and the standard
	// gives no way to disambiguate.
	ErrDuplicateInstance = errors.New("service instance is already configured")

	// ErrUnknownInstance indicates a service instance identifier the complex
	// does not serve.
	ErrUnknownInstance = errors.New("no such service instance")

	// ErrInstanceInUse indicates a BIND to an instance that is already bound.
	ErrInstanceInUse = errors.New("service instance is already in use")

	// ErrVersionNotSupported indicates a BIND asking for a version the
	// instance was not configured for.
	ErrVersionNotSupported = errors.New("service version is not supported by this instance")

	// ErrNotBound indicates an operation requiring an established association.
	ErrNotBound = errors.New("association is not bound")

	// ErrAlreadyBound indicates a BIND on an association that already has one.
	ErrAlreadyBound = errors.New("association is already bound")

	// ErrBindRejected indicates the peer refused the BIND.
	ErrBindRejected = errors.New("peer rejected the bind")

	// ErrInvalidReportingCycle indicates a reporting cycle outside the 2-to-600
	// second range of ReportingCycle.
	ErrInvalidReportingCycle = errors.New("invalid reporting cycle: must be 2 to 600 seconds")

	// ErrNotStarted indicates a data-transfer operation attempted before START.
	ErrNotStarted = errors.New("service instance is not started")

	// ErrAlreadyStarted indicates a START on an already-active service instance.
	ErrAlreadyStarted = errors.New("service instance is already started")

	// ErrUnexpectedPDU indicates a PDU the service state does not allow, which
	// the state tables answer with a PEER-ABORT for protocol error.
	ErrUnexpectedPDU = errors.New("PDU not allowed in the current service state")

	// ErrUnknownInvokeId indicates a return whose invoke identifier matches no
	// outstanding invocation.
	ErrUnknownInvokeId = errors.New("return does not match any outstanding invocation")

	// ErrDuplicateInvokeId indicates an invocation reusing an invoke
	// identifier already seen on this association. The provider machines
	// answer it with the 'duplicate invoke ID' diagnostic.
	ErrDuplicateInvokeId = errors.New("invoke identifier already used on this association")

	// ErrCltuOutOfSequence indicates a CLTU identification that is not the one
	// the provider expects next, per CCSDS 912.1-B-5 clause 3.6.2.5.
	ErrCltuOutOfSequence = errors.New("CLTU identification is out of sequence")
)

Sentinel errors returned by the SLE codecs and the association machine.

View Source
var CCSDSEpoch = time.Date(1958, 1, 1, 0, 0, 0, 0, time.UTC)

CCSDSEpoch is 1958-01-01 00:00:00 UTC, the epoch the day count runs from.

View Source
var ProtocolID = [4]byte{'I', 'S', 'P', '1'}

ProtocolID is the identification field of a context message: the characters 'I' 'S' 'P' '1' (clause 3.3.2.2.4 a).

Functions

func AppendAntennaId

func AppendAntennaId(dst []byte, a AntennaId) []byte

AppendAntennaId writes an AntennaId CHOICE.

func AppendCltuLastOk

func AppendCltuLastOk(dst []byte, c CltuLastOk) []byte

AppendCltuLastOk writes a CltuLastOk CHOICE. As with CltuLastProcessed, the cltuOk alternative's [1] replaces its SEQUENCE tag (implicit tagging), so the fields sit directly under it.

func AppendCltuLastProcessed

func AppendCltuLastProcessed(dst []byte, c CltuLastProcessed) []byte

AppendCltuLastProcessed writes a CltuLastProcessed CHOICE.

The cltuProcessed alternative is [1] IMPLICIT SEQUENCE, and the module is IMPLICIT TAGS: the tag replaces the SEQUENCE's, so the fields sit directly under [1] with no inner SEQUENCE.

func AppendConditionalTime

func AppendConditionalTime(dst []byte, c ConditionalTime) []byte

AppendConditionalTime writes a ConditionalTime CHOICE.

func AppendControlWordType

func AppendControlWordType(dst []byte, c ControlWordType) []byte

AppendControlWordType writes a ControlWordType CHOICE.

func AppendCredentialsChoice

func AppendCredentialsChoice(dst []byte, c *Credentials) ([]byte, error)

AppendCredentialsChoice writes the Credentials CHOICE of the common types module:

Credentials ::= CHOICE
{ unused [0] NULL
, used   [1] OCTET STRING (SIZE (8 .. 256))
}

A nil Credentials takes the unused alternative, which is what an unauthenticated association sends.

func AppendElement

func AppendElement(dst []byte, class uint8, constructed bool, tag uint32, content []byte) []byte

AppendElement writes a complete tag-length-value.

func AppendGVCID

func AppendGVCID(dst []byte, g GVCID) ([]byte, error)

AppendGVCID writes a GvcId SEQUENCE.

func AppendInteger

func AppendInteger(dst []byte, v int64) []byte

AppendInteger writes a universal INTEGER.

BER integers are two's complement and minimally encoded: a leading zero octet appears only when it is needed to keep a positive value from looking negative (X.690 clause 8.3).

func AppendLength

func AppendLength(dst []byte, length int) []byte

AppendLength writes a definite-form length, short or long as needed (X.690 clause 8.1.3).

func AppendNull

func AppendNull(dst []byte) []byte

AppendNull writes a universal NULL, which has no content.

func AppendObjectIdentifier

func AppendObjectIdentifier(dst []byte, oid []uint32) ([]byte, error)

AppendObjectIdentifier writes a universal OBJECT IDENTIFIER (X.690 clause 8.19).

The first two arcs pack into one subidentifier (first*40 + second), then every subidentifier is base-128 with continuation bits. The service instance identifiers of the SLE BIND use this type for their attribute names.

func AppendOctetString

func AppendOctetString(dst []byte, v []byte) []byte

AppendOctetString writes a universal OCTET STRING.

func AppendPDU

func AppendPDU(dst []byte, tag uint32, content []byte) []byte

AppendPDU wraps an operation's content in its service tag.

func AppendSequence

func AppendSequence(dst []byte, content []byte) []byte

AppendSequence writes a universal SEQUENCE around already-encoded content.

func AppendTag

func AppendTag(dst []byte, class uint8, constructed bool, tag uint32) []byte

AppendTag writes a BER identifier octet, or several when the tag number needs the high-tag-number form (X.690 clause 8.1.2.4).

func AppendTaggedInteger

func AppendTaggedInteger(dst []byte, tag uint32, v int64) []byte

AppendTaggedInteger writes an INTEGER under a context-specific tag.

func AppendTimeChoice

func AppendTimeChoice(dst []byte, t Time) []byte

AppendTimeChoice writes an SLE Time CHOICE, taking the [0] ccsdsFormat alternative that the eight-octet form uses.

func AppendVisibleString

func AppendVisibleString(dst []byte, v string) []byte

AppendVisibleString writes a universal VisibleString.

func WriteMessage

func WriteMessage(w io.Writer, m *Message) error

WriteMessage writes one TML message to w.

Types

type Acknowledgement

type Acknowledgement struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// Positive reports whether the operation succeeded.
	Positive bool
	// Diagnostic explains a failure.
	Diagnostic Diagnostics
}

Acknowledgement is the SleAcknowledgement of the common PDUs module: the answer to STOP and to other operations that need only success or failure.

func DecodeAcknowledgement

func DecodeAcknowledgement(data []byte) (*Acknowledgement, error)

DecodeAcknowledgement parses an acknowledgement's content.

func (*Acknowledgement) Encode

func (a *Acknowledgement) Encode() ([]byte, error)

Encode serializes the acknowledgement's content.

func (*Acknowledgement) Humanize

func (a *Acknowledgement) Humanize() string

Humanize returns a human-readable summary.

type AntennaId

type AntennaId struct {
	// Global holds an object identifier when the global form is used.
	Global []byte
	// Local holds a local name, 1 to 16 octets, when the local form is used.
	Local []byte
}

AntennaId names the antenna a frame arrived on.

AntennaId ::= CHOICE
{ globalForm [0] OBJECT IDENTIFIER
, localForm  [1] OCTET STRING (SIZE (1 .. 16))
}

func DecodeAntennaId

func DecodeAntennaId(e *Element) (AntennaId, error)

DecodeAntennaId reads an AntennaId CHOICE.

func (AntennaId) String

func (a AntennaId) String() string

String renders the antenna identifier.

type ApplicationIdentifier

type ApplicationIdentifier int

ApplicationIdentifier names the transfer service a BIND is asking for. Values from the ApplicationIdentifier INTEGER of annex A2.2.

const (
	AppReturnAllFrames     ApplicationIdentifier = 0
	AppReturnInsert        ApplicationIdentifier = 1
	AppReturnChannelFrames ApplicationIdentifier = 2
	AppReturnChannelFSH    ApplicationIdentifier = 3
	AppReturnChannelOCF    ApplicationIdentifier = 4
	AppReturnBitstream     ApplicationIdentifier = 5
	AppReturnSpacePacket   ApplicationIdentifier = 6
	AppForwardAOSSpacePkt  ApplicationIdentifier = 7
	AppForwardAOSVCA       ApplicationIdentifier = 8
	AppForwardBitstream    ApplicationIdentifier = 9
	AppForwardProtoVCDU    ApplicationIdentifier = 10
	AppForwardInsert       ApplicationIdentifier = 11
	AppForwardCVCDU        ApplicationIdentifier = 12
	AppForwardTCSpacePkt   ApplicationIdentifier = 13
	AppForwardTCVCA        ApplicationIdentifier = 14
	AppForwardTCFrame      ApplicationIdentifier = 15
	AppForwardCLTU         ApplicationIdentifier = 16
)

func (ApplicationIdentifier) String

func (a ApplicationIdentifier) String() string

String names the service.

type Association

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

Association tracks one SLE association.

It is safe for concurrent use, though the caller normally drives it from a single loop.

func NewAssociation

func NewAssociation(config AssociationConfig) (*Association, error)

NewAssociation prepares an association.

func (*Association) Abort

func (a *Association) Abort(diagnostic PeerAbortDiagnostic, now time.Time) *PeerAbort

Abort ends the association abruptly, returning the PEER-ABORT to send.

ISP1 maps PEER-ABORT onto the transport twice over (CCSDS 913.1-B-2 clause 3.4): the diagnostic goes out as one octet of TCP urgent data (take it from PeerAbort.UrgentData and write it with MSG_OOB) and then the connection closes. This package owns no socket, so both are the caller's to do after sending the PDU this returns.

func (*Association) AbortDiagnostic

func (a *Association) AbortDiagnostic() *PeerAbortDiagnostic

AbortDiagnostic returns why the association aborted, or nil if it did not.

func (*Association) Bind

func (a *Association) Bind(
	now time.Time,
	randomNumber int32,
	serviceType ApplicationIdentifier,
	version uint16,
	responderPort string,
	instance ServiceInstanceIdentifier,
) (*BindInvocation, error)

Bind builds a BIND invocation and moves to bind-pending.

Only the service user sends BIND. randomNumber seeds the credentials; the caller supplies it rather than this package choosing a randomness source.

func (*Association) Bound

func (a *Association) Bound() bool

Bound reports whether the association is established.

func (*Association) CheckPeerCredentials

func (a *Association) CheckPeerCredentials(c *Credentials, now time.Time) error

CheckPeerCredentials verifies credentials on an incoming service PDU.

The service machines call it from every HandlePDU path. It returns nil unless the association's authentication level is 'all' and a peer password is on file. The two lower levels leave service PDUs unchecked, per the levels of CCSDS 913.1-B-2 clause 3.1. When it does check, missing credentials are as bad as wrong ones: an association configured for authentication must not accept a PDU that simply left the field out.

func (*Association) ContextMessage

func (a *Association) ContextMessage(now time.Time) *Message

ContextMessage builds the TML context message that opens the connection.

Clause 3.3.2.2 makes this the first message on a connection, before any SLE PDU.

func (*Association) HandleBindInvocation

func (a *Association) HandleBindInvocation(b *BindInvocation, now time.Time, randomNumber int32) (*BindReturn, error)

HandleBindInvocation processes an inbound BIND at the provider, returning the answer to send.

func (*Association) HandleBindReturn

func (a *Association) HandleBindReturn(b *BindReturn, now time.Time) error

HandleBindReturn processes the provider's answer at the user.

func (*Association) HandleContextMessage

func (a *Association) HandleContextMessage(body []byte, now time.Time) error

HandleContextMessage records the peer's context message.

The peer's heartbeat interval and dead factor govern what this end must send and how long it waits, so they replace the configured values.

Clause 3.3.2.2 makes the context message the initiator's (the SLE user sends it, the provider receives it) so a user rejects an inbound one. The parameters are range-checked: a nonzero heartbeat interval with a zero dead factor could never declare the peer dead.

func (*Association) HandlePeerAbort

func (a *Association) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort processes an inbound PEER-ABORT.

func (*Association) HandleUnbindInvocation

func (a *Association) HandleUnbindInvocation(u *UnbindInvocation, now time.Time, randomNumber int32) (*UnbindReturn, error)

HandleUnbindInvocation processes an inbound UNBIND, returning the answer.

An UNBIND cannot be refused: the return type of annex A2.2 has only a positive alternative.

func (*Association) HandleUnbindReturn

func (a *Association) HandleUnbindReturn(u *UnbindReturn, now time.Time) error

HandleUnbindReturn processes the answer to our UNBIND.

func (*Association) HandleUrgentData

func (a *Association) HandleUrgentData(octet byte, now time.Time) *PeerAbort

HandleUrgentData processes a peer abort that arrived as TCP urgent data: the single diagnostic octet of CCSDS 913.1-B-2 clause 3.4. A caller reading its socket out of band hands the octet here and gets the decoded abort back; the association closes just as it does for the in-band PDU.

func (*Association) HeartbeatDue

func (a *Association) HeartbeatDue(now time.Time) bool

HeartbeatDue reports whether a heartbeat should go out now.

This package runs no clock. Call it from your loop with the current time.

func (*Association) MakeCredentials

func (a *Association) MakeCredentials(now time.Time, randomNumber int32) (*Credentials, error)

MakeCredentials builds credentials for an outgoing service PDU, or returns nil when the association is unauthenticated.

The BIND family generates its own credentials inside this file. The service operations in raf.go, rcf.go, rocf.go and fcltu.go are built by the state machines in service.go, which call this so every PDU on an authenticated association carries the same identity the BIND did.

func (*Association) NextHeartbeat

func (a *Association) NextHeartbeat() time.Time

NextHeartbeat returns when the next heartbeat is due, so a caller can size a select timeout rather than poll.

func (*Association) PeerDead

func (a *Association) PeerDead(now time.Time) bool

PeerDead reports whether the peer has been silent for longer than the heartbeat interval times the dead factor.

Clause 3.3.3 makes this the signal to abort the association.

func (*Association) RecordReceived

func (a *Association) RecordReceived(now time.Time)

RecordReceived notes that something arrived, which proves the peer is alive.

func (*Association) RecordSent

func (a *Association) RecordSent(now time.Time)

RecordSent notes that something went out, which resets the heartbeat timer.

Clause 3.3.3: a heartbeat is only needed on an idle connection, so any traffic serves the same purpose.

func (*Association) Role

func (a *Association) Role() Role

Role reports which end of the association this is.

func (*Association) ServiceType

func (a *Association) ServiceType() ApplicationIdentifier

ServiceType returns the service the BIND agreed on.

func (*Association) State

func (a *Association) State() AssociationState

State returns the current state.

func (*Association) Unbind

func (a *Association) Unbind(now time.Time, randomNumber int32, reason UnbindReason) (*UnbindInvocation, error)

Unbind builds an UNBIND invocation and moves to unbind-pending.

func (*Association) Version

func (a *Association) Version() uint16

Version returns the version the BIND agreed on.

type AssociationConfig

type AssociationConfig struct {
	// Role is which end this is.
	Role Role

	// LocalIdentifier is this end's authority identifier, 3 to 16 characters.
	LocalIdentifier string
	// PeerIdentifier is the far end's, checked on receipt.
	PeerIdentifier string

	// HeartbeatInterval is how many seconds between heartbeats. Zero disables
	// the heartbeat (clause 3.3.3).
	HeartbeatInterval uint16
	// DeadFactor is how many intervals of silence mean the peer has gone.
	DeadFactor uint16

	// UserName and Password authenticate this end. Leave Password nil for an
	// unauthenticated association.
	UserName string
	Password []byte

	// PeerPassword verifies the far end's credentials.
	PeerPassword []byte

	// AuthLevel says which inbound PDUs are authenticated: the BIND exchange
	// only (the default), nothing, or every PDU. It matters only when
	// PeerPassword is set.
	AuthLevel AuthenticationLevel

	// AcceptableDelay is how far a peer's credential time may be from now
	// before it is rejected (clause 3.1.2.2.1). Zero disables the check.
	AcceptableDelay time.Duration
}

AssociationConfig describes one association.

type AssociationState

type AssociationState int

AssociationState is where an association has got to.

const (
	// StateUnbound means the connection is open but no BIND has succeeded.
	StateUnbound AssociationState = iota
	// StateBindPending means a BIND invocation is out and its return has not
	// come back.
	StateBindPending
	// StateBound means the association is established and PDUs may flow.
	StateBound
	// StateUnbindPending means an UNBIND invocation is out.
	StateUnbindPending
	// StateClosed means the association has ended, by UNBIND or abort.
	StateClosed
)

func (AssociationState) String

func (s AssociationState) String() string

String names the state.

type AuthenticationLevel

type AuthenticationLevel int

AuthenticationLevel says which inbound PDUs must carry verified credentials. CCSDS 913.1-B-2 clause 3.1 names the three levels a service agreement can pick.

const (
	// AuthLevelBind verifies credentials on the BIND exchange only. This is
	// the default, and the level most service agreements pick.
	AuthLevelBind AuthenticationLevel = iota
	// AuthLevelNone verifies nothing, even when a peer password is
	// configured.
	AuthLevelNone
	// AuthLevelAll verifies the credentials on every inbound PDU. The
	// service machines run the check in their HandlePDU paths through
	// CheckPeerCredentials.
	AuthLevelAll
)

func (AuthenticationLevel) String

func (l AuthenticationLevel) String() string

String names the level.

type BindDiagnostic

type BindDiagnostic int

BindDiagnostic explains a refused BIND, from the BindDiagnostic INTEGER of annex A2.2.

const (
	BindAccessDenied                 BindDiagnostic = 0
	BindServiceTypeNotSupported      BindDiagnostic = 1
	BindVersionNotSupported          BindDiagnostic = 2
	BindNoSuchServiceInstance        BindDiagnostic = 3
	BindAlreadyBound                 BindDiagnostic = 4
	BindNotAccessibleToThisInitiator BindDiagnostic = 5
	BindInconsistentServiceType      BindDiagnostic = 6
	BindInvalidTime                  BindDiagnostic = 7
	BindOutOfService                 BindDiagnostic = 8
	BindOtherReason                  BindDiagnostic = 127
)

func (BindDiagnostic) String

func (b BindDiagnostic) String() string

String names the diagnostic.

type BindInvocation

type BindInvocation struct {
	// Credentials authenticate the initiator, or nil for an unauthenticated
	// association.
	Credentials *Credentials
	// InitiatorIdentifier names the sending entity, 3 to 16 characters.
	InitiatorIdentifier string
	// ResponderPortIdentifier names the provider's logical port.
	ResponderPortIdentifier string
	// ServiceType is the transfer service being requested.
	ServiceType ApplicationIdentifier
	// VersionNumber is the service version, 1 to 65535.
	VersionNumber uint16
	// ServiceInstanceIdentifier names the service instance.
	ServiceInstanceIdentifier ServiceInstanceIdentifier
}

BindInvocation is the SleBindInvocation of annex A2.2. The user sends it to open an association.

func DecodeBindInvocation

func DecodeBindInvocation(data []byte) (*BindInvocation, error)

DecodeBindInvocation parses a BIND invocation's content.

func (*BindInvocation) Encode

func (b *BindInvocation) Encode() ([]byte, error)

Encode serializes the BIND invocation content, without the outer service tag that each service module adds.

func (*BindInvocation) Humanize

func (b *BindInvocation) Humanize() string

Humanize returns a human-readable summary.

func (*BindInvocation) Validate

func (b *BindInvocation) Validate() error

Validate checks the invocation against annex A2.2.

type BindReturn

type BindReturn struct {
	Credentials *Credentials
	// ResponderIdentifier names the answering entity.
	ResponderIdentifier string
	// Positive reports whether the bind succeeded.
	Positive bool
	// VersionNumber is the agreed version, meaningful when Positive.
	VersionNumber uint16
	// Diagnostic explains a refusal, meaningful when not Positive.
	Diagnostic BindDiagnostic
}

BindReturn is the SleBindReturn of annex A2.2: the provider's answer.

func DecodeBindReturn

func DecodeBindReturn(data []byte) (*BindReturn, error)

DecodeBindReturn parses a BIND return's content.

func (*BindReturn) Encode

func (b *BindReturn) Encode() ([]byte, error)

Encode serializes the BIND return's content.

func (*BindReturn) Humanize

func (b *BindReturn) Humanize() string

Humanize returns a human-readable summary.

type CltuIdentification

type CltuIdentification uint32

CltuIdentification numbers a CLTU within a service instance. The user assigns it and must keep it ascending; the provider quotes it back. IntUnsignedLong: INTEGER (0 .. 4294967295).

type CltuLastOk

type CltuLastOk struct {
	// Ok reports whether any CLTU has been radiated successfully.
	Ok                 bool
	CltuIdentification CltuIdentification
	RadiationStopTime  Time
}

CltuLastOk says which CLTU was last radiated without trouble.

CltuLastOk ::= CHOICE
{ noCltuOk [0] NULL
, cltuOk   [1] SEQUENCE { cltuIdentification, radiationStopTime }
}

Note that radiationStopTime here is a plain Time, not a ConditionalTime: a CLTU that finished radiating has a stop time by definition.

func DecodeCltuLastOk

func DecodeCltuLastOk(e *Element) (CltuLastOk, error)

DecodeCltuLastOk reads a CltuLastOk CHOICE.

func (CltuLastOk) String

func (c CltuLastOk) String() string

String renders the last good CLTU.

type CltuLastProcessed

type CltuLastProcessed struct {
	// Processed reports whether any CLTU has been processed yet.
	Processed          bool
	CltuIdentification CltuIdentification
	// RadiationStartTime is when radiation began, undefined if it has not.
	RadiationStartTime ConditionalTime
	Status             CltuStatus
}

CltuLastProcessed says what the provider last took off its queue.

CltuLastProcessed ::= CHOICE
{ noCltuProcessed [0] NULL
, cltuProcessed   [1] SEQUENCE
   { cltuIdentification, radiationStartTime, cltuStatus }
}

func DecodeCltuLastProcessed

func DecodeCltuLastProcessed(e *Element) (CltuLastProcessed, error)

DecodeCltuLastProcessed reads a CltuLastProcessed CHOICE.

func (CltuLastProcessed) String

func (c CltuLastProcessed) String() string

String renders what was last processed.

type CltuNotificationKind

type CltuNotificationKind int

CltuNotificationKind says which alternative an ASYNC-NOTIFY took, from the CltuNotification CHOICE of the CLTU structures module.

const (
	// NotifyCltuRadiated reports one CLTU went out.
	NotifyCltuRadiated CltuNotificationKind = 0
	// NotifySlduExpired reports a CLTU's window passed unused.
	NotifySlduExpired CltuNotificationKind = 1
	// NotifyProductionInterrupted reports radiation stopped unexpectedly.
	NotifyProductionInterrupted CltuNotificationKind = 2
	// NotifyProductionHalted reports the channel ended.
	NotifyProductionHalted CltuNotificationKind = 3
	// NotifyProductionOperational reports the channel started radiating.
	NotifyProductionOperational CltuNotificationKind = 4
	// NotifyBufferEmpty reports the provider has run out of CLTUs to send.
	NotifyBufferEmpty CltuNotificationKind = 5
	// NotifyActionListCompleted reports a thrown event's actions all ran.
	NotifyActionListCompleted CltuNotificationKind = 6
	// NotifyActionListNotCompleted reports they did not.
	NotifyActionListNotCompleted CltuNotificationKind = 7
	// NotifyEventConditionEvFalse reports a thrown event's condition was false.
	NotifyEventConditionEvFalse CltuNotificationKind = 8
)

func (CltuNotificationKind) CarriesEventId

func (n CltuNotificationKind) CarriesEventId() bool

CarriesEventId reports whether this notification carries an EventInvocationId rather than a NULL. The last three alternatives do.

func (CltuNotificationKind) String

func (n CltuNotificationKind) String() string

String names the notification.

type CltuStatus

type CltuStatus int

CltuStatus says what became of a CLTU, from the CltuStatus subtype of ForwardDuStatus.

The values are ForwardDuStatus's, and FCLTU uses only five of its seven: 3 is "acknowledged" and 6 is "unsupported transmission mode", both of which belong to the Forward Space Packet service. So the numbering has a hole in it, and 3 is not a value this service ever sends.

const (
	// CltuRadiated means the CLTU went out.
	CltuRadiated CltuStatus = 0
	// CltuExpired means its transmission window passed before it could.
	CltuExpired CltuStatus = 1
	// CltuInterrupted means radiation began and was cut short.
	CltuInterrupted CltuStatus = 2
	// CltuProductionStarted means radiation started.
	CltuProductionStarted CltuStatus = 4
	// CltuProductionNotStarted means radiation did not start.
	CltuProductionNotStarted CltuStatus = 5
)

func (CltuStatus) String

func (c CltuStatus) String() string

String names the status.

func (CltuStatus) Valid

func (c CltuStatus) Valid() bool

Valid reports whether the status is one FCLTU defines.

type Complex added in v0.4.0

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

Complex holds the service instances a provider serves and routes inbound BINDs to them.

It is safe for concurrent use: instances are naturally driven by different connections.

func NewComplex added in v0.4.0

func NewComplex() *Complex

NewComplex prepares a complex with no instances.

func (*Complex) Abort added in v0.4.0

func (c *Complex) Abort()

Abort clears every instance's transfer buffer, for a complex whose underlying connection has gone.

Clause 3.1.9.1.12 requires an aborted association to clear its buffer. An abort usually takes one association, so a caller with a live complex aborts the instance rather than the whole thing; this is for shutdown.

func (*Complex) Add added in v0.4.0

func (c *Complex) Add(config InstanceConfig) (*Instance, error)

Add configures one service instance.

The instance identifier is the key, because that is what a BIND names. Two instances cannot share one: a BIND would be ambiguous, and the standard gives no way to disambiguate.

func (*Complex) DueInstances added in v0.4.0

func (c *Complex) DueInstances(now time.Time) []*Instance

DueInstances lists the instances whose transfer buffer should be released now, in configuration order.

A station serving several instances polls this rather than each buffer, so one loop drives them all.

func (*Complex) Humanize added in v0.4.0

func (c *Complex) Humanize() string

Humanize returns a human-readable summary of the complex.

func (*Complex) Instance added in v0.4.0

func (c *Complex) Instance(name string) (*Instance, error)

Instance returns the instance with this identifier.

func (*Complex) Instances added in v0.4.0

func (c *Complex) Instances() []*Instance

Instances lists the configured instances in configuration order.

func (*Complex) Len added in v0.4.0

func (c *Complex) Len() int

Len reports how many instances are configured.

func (*Complex) NextDeadline added in v0.4.0

func (c *Complex) NextDeadline() (time.Time, bool)

NextDeadline reports the earliest release timer across every instance, and whether any is running.

It is what a single-threaded station waits on: the next moment any buffer needs attention.

func (*Complex) Route added in v0.4.0

func (c *Complex) Route(bind *BindInvocation) (*Instance, BindDiagnostic, error)

Route finds the instance a BIND invocation names and checks it can be bound.

It is the admission decision, and it returns the diagnostic to answer with when the answer is no, so a caller does not have to work out which of the BIND diagnostics applies. The diagnostics are the ones annex A defines for SleBindReturn:

  • an identifier the complex does not know is 'no such service instance'
  • one already bound is 'already bound'
  • a version the instance was not configured for is 'version not supported'

A caller that wants to refuse for a reason outside the instance set (the initiator not being the one the agreement names, or the request arriving outside a provision period) checks that itself and answers with the diagnostic that fits. Those are service-agreement matters, and the complex does not hold an agreement.

type ConditionalTime

type ConditionalTime struct {
	// Known reports whether a time is present.
	Known bool
	Time  Time
}

ConditionalTime is the CHOICE of the common types module: a time that may be absent.

ConditionalTime ::= CHOICE
{ undefined [0] NULL
, known     [1] Time
}

RAF START uses it for the start and stop of a requested time range, where "undefined" means "from now" or "until further notice".

func DecodeConditionalTime

func DecodeConditionalTime(e *Element) (ConditionalTime, error)

DecodeConditionalTime reads a ConditionalTime CHOICE.

type ContextMessage

type ContextMessage struct {
	// HeartbeatInterval is how many seconds pass between heartbeats. Zero
	// disables the heartbeat entirely (clause 3.3.3).
	HeartbeatInterval uint16
	// DeadFactor is how many intervals of silence mean the peer has gone.
	DeadFactor uint16
}

ContextMessage is the body of a TML context message (clause 3.3.2.2.4).

It opens a connection, telling the peer how often to expect a heartbeat and how many missed ones mean the link is dead.

func DecodeContextMessage

func DecodeContextMessage(body []byte) (*ContextMessage, error)

DecodeContextMessage parses a context message body.

func (*ContextMessage) Encode

func (c *ContextMessage) Encode() []byte

Encode serializes the context message body: 'ISP1', three reserved zeros, the version, then the two parameters.

func (*ContextMessage) Humanize

func (c *ContextMessage) Humanize() string

Humanize returns a human-readable summary.

func (*ContextMessage) Message

func (c *ContextMessage) Message() *Message

Message wraps the context body in a TML message.

type ControlWordKind

type ControlWordKind int

ControlWordKind selects which control words to deliver, from the ControlWordType CHOICE of the ROCF structures module.

const (
	// ControlWordAll delivers every operational control field.
	ControlWordAll ControlWordKind = 0
	// ControlWordCLCW delivers only CLCWs, for one telecommand virtual
	// channel or for all of them.
	ControlWordCLCW ControlWordKind = 1
	// ControlWordNotCLCW delivers only fields that are not CLCWs.
	ControlWordNotCLCW ControlWordKind = 2
)

func (ControlWordKind) String

func (c ControlWordKind) String() string

String names the kind.

type ControlWordType

type ControlWordType struct {
	Kind ControlWordKind
	// TCVirtualChannel names one telecommand virtual channel when Kind is
	// ControlWordCLCW and HasTCVirtualChannel is set.
	TCVirtualChannel    uint8
	HasTCVirtualChannel bool
}

ControlWordType is the ROCF filter on which control words to deliver.

ControlWordType ::= CHOICE
{ allControlWords [0] NULL
, clcw            [1] TcVcid
, notClcw         [2] NULL
}

The clcw alternative carries a TcVcid, itself a CHOICE of "no telecommand virtual channel" and a specific one, so a caller can ask for CLCWs from one TC virtual channel, or from any.

func DecodeControlWordType

func DecodeControlWordType(e *Element) (ControlWordType, error)

DecodeControlWordType reads a ControlWordType CHOICE.

func (ControlWordType) String

func (c ControlWordType) String() string

String renders the filter.

type Credentials

type Credentials struct {
	Time         Time
	RandomNumber int32
	// Protected is the message digest, 32 octets from SHA-256 or 20 from the
	// legacy SHA-1.
	Protected []byte
}

Credentials are the ISP1Credentials of figure 3-2: the time and random number that went into a digest, and the digest itself.

func DecodeCredentials

func DecodeCredentials(data []byte) (*Credentials, error)

DecodeCredentials parses an ISP1Credentials SEQUENCE.

func DecodeCredentialsChoice

func DecodeCredentialsChoice(e *Element) (*Credentials, error)

DecodeCredentialsChoice reads a Credentials CHOICE, returning nil for the unused alternative.

func GenerateCredentials

func GenerateCredentials(t time.Time, randomNumber int32, userName string, password []byte) (*Credentials, error)

GenerateCredentials builds credentials for an outgoing PDU, per clause 3.1.2.1.

The caller supplies the random number rather than this package choosing one. A library has no business picking a mission's randomness source, and the value has to be reproducible in tests.

func (*Credentials) Encode

func (c *Credentials) Encode() ([]byte, error)

Encode serializes the ISP1Credentials SEQUENCE of figure 3-2.

func (*Credentials) Humanize

func (c *Credentials) Humanize() string

Humanize returns a human-readable summary. It shows the digest length rather than the digest.

func (*Credentials) Verify

func (c *Credentials) Verify(now time.Time, acceptableDelay time.Duration, userName string, password []byte) error

Verify checks credentials received from a peer, per clause 3.1.2.2.

now is the current time and acceptableDelay is how far the credential time may be from it. userName and password are the peer's, which the receiver already knows.

The digest comparison is constant time. A timing oracle on a MAC comparison is a real attack, and it costs nothing to avoid.

type Decoder

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

Decoder walks a BER-encoded buffer.

It is a value type over a slice, so a Decoder over a SEQUENCE's content is just another Decoder. That is how nesting works here: no reader interface, no allocation per level.

func NewDecoder

func NewDecoder(data []byte) *Decoder

NewDecoder returns a decoder over data.

func NewDecoderWithLimit

func NewDecoderWithLimit(data []byte, maxLength int) *Decoder

NewDecoderWithLimit returns a decoder with an explicit value ceiling.

func (*Decoder) Empty

func (d *Decoder) Empty() bool

Empty reports whether the decoder has consumed everything.

func (*Decoder) Nested

func (d *Decoder) Nested(e *Element) *Decoder

Nested returns a decoder over a constructed element's content, carrying the same length ceiling.

func (*Decoder) Next

func (d *Decoder) Next() (*Element, error)

Next reads the next element.

func (*Decoder) Remaining

func (d *Decoder) Remaining() int

Remaining returns how many octets are left.

type DeliveryMode

type DeliveryMode int

DeliveryMode says how a service instance delivers data.

const (
	DeliveryReturnTimelyOnline   DeliveryMode = 0
	DeliveryReturnCompleteOnline DeliveryMode = 1
	DeliveryReturnOffline        DeliveryMode = 2
	DeliveryForwardOnline        DeliveryMode = 3
	DeliveryForwardOffline       DeliveryMode = 4
)

func (DeliveryMode) AllowsDiscard

func (d DeliveryMode) AllowsDiscard() bool

AllowsDiscard reports whether the provider may throw data away to keep up. Only timely online may: state table row 14 of CCSDS 911.1-B-5 clause 4.2.2 is the only cell that sends a 'data discarded' sync notification.

func (DeliveryMode) AllowsPastStartTime

func (d DeliveryMode) AllowsPastStartTime() bool

AllowsPastStartTime reports whether START may name a time range that has already happened. Only offline delivery reads from a store, so only offline can be asked for yesterday.

func (DeliveryMode) AllowsPeriodicStatusReport

func (d DeliveryMode) AllowsPeriodicStatusReport() bool

AllowsPeriodicStatusReport reports whether SCHEDULE-STATUS-REPORT may ask for periodic reports. Offline delivery has no live channel to report on, so the answer there is the 'not supported in this delivery mode' diagnostic.

func (DeliveryMode) IsForward

func (d DeliveryMode) IsForward() bool

IsForward reports whether the mode belongs to a forward service.

func (DeliveryMode) IsOnline

func (d DeliveryMode) IsOnline() bool

IsOnline reports whether the mode reads from a live channel rather than a store.

func (DeliveryMode) IsReturn

func (d DeliveryMode) IsReturn() bool

IsReturn reports whether the mode belongs to a return service.

func (DeliveryMode) RequiresBackpressure

func (d DeliveryMode) RequiresBackpressure() bool

RequiresBackpressure reports whether the caller must slow down rather than let data be dropped. Complete online and offline both promise every frame, so a slow caller has to become the brake.

func (DeliveryMode) String

func (d DeliveryMode) String() string

String names the delivery mode.

func (DeliveryMode) Valid

func (d DeliveryMode) Valid() bool

Valid reports whether the mode is one of the five the standard defines.

type Diagnostics

type Diagnostics int

Diagnostics is the common diagnostic set every service shares.

const (
	// DiagDuplicateInvokeId means the invoke identifier is already in use.
	DiagDuplicateInvokeId Diagnostics = 100
	// DiagOtherReason covers everything else.
	DiagOtherReason Diagnostics = 127
)

func (Diagnostics) String

func (d Diagnostics) String() string

String names the diagnostic.

type Element

type Element struct {
	// Class is the tag class: universal, application, context or private.
	Class uint8
	// Constructed reports whether the content is itself a run of elements.
	Constructed bool
	// Tag is the tag number.
	Tag uint32
	// Bytes is the content, with the tag and length already stripped.
	Bytes []byte
}

Element is one decoded BER tag-length-value.

func (*Element) Bool

func (e *Element) Bool() (bool, error)

Bool reads an element's content as a BOOLEAN. X.690 clause 8.2.2: any non-zero octet is true.

func (*Element) Copy

func (e *Element) Copy() []byte

Copy returns a copy of the element's content, so it does not alias the buffer the decoder was built over.

func (*Element) Int64

func (e *Element) Int64() (int64, error)

Int64 reads an element's content as a two's complement INTEGER.

func (*Element) IsContext

func (e *Element) IsContext(tag uint32) bool

IsContext reports whether this is a context-specific tag with the given number.

func (*Element) IsUniversal

func (e *Element) IsUniversal(tag uint8) bool

IsUniversal reports whether this is a universal tag with the given number.

func (*Element) ObjectIdentifier

func (e *Element) ObjectIdentifier() ([]uint32, error)

ObjectIdentifier reads an element's content as the arcs of an OBJECT IDENTIFIER (X.690 clause 8.19).

func (*Element) String

func (e *Element) String() string

String reads an element's content as text.

func (*Element) Uint64

func (e *Element) Uint64() (uint64, error)

Uint64 reads an element's content as a non-negative INTEGER.

type EventInvocationId

type EventInvocationId uint32

EventInvocationId numbers a THROW-EVENT invocation, also ascending.

type FCLTUAsyncNotifyInvocation

type FCLTUAsyncNotifyInvocation struct {
	Credentials *Credentials
	// Kind says which notification this is.
	Kind CltuNotificationKind
	// EventInvocationId is set when Kind.CarriesEventId reports true.
	EventInvocationId EventInvocationId
	// LastProcessed and LastOk report the queue's position, sent with every
	// notification whatever its kind.
	LastProcessed    CltuLastProcessed
	LastOk           CltuLastOk
	ProductionStatus FCLTUProductionStatus
	UplinkStatus     UplinkStatus
}

FCLTUAsyncNotifyInvocation is the CltuAsyncNotifyInvocation of annex A2.5: the provider reporting, after the fact, what happened to a CLTU or to the channel.

This is what makes the service asynchronous. TRANSFER-DATA's return only says the CLTU was queued. Whether it actually reached the antenna arrives here, possibly much later.

func DecodeFCLTUAsyncNotifyInvocation

func DecodeFCLTUAsyncNotifyInvocation(data []byte) (*FCLTUAsyncNotifyInvocation, error)

DecodeFCLTUAsyncNotifyInvocation parses an ASYNC-NOTIFY invocation's content.

func (*FCLTUAsyncNotifyInvocation) Encode

func (n *FCLTUAsyncNotifyInvocation) Encode() ([]byte, error)

Encode serializes the ASYNC-NOTIFY invocation's content.

func (*FCLTUAsyncNotifyInvocation) Humanize

func (n *FCLTUAsyncNotifyInvocation) Humanize() string

Humanize returns a human-readable summary.

type FCLTUProductionStatus

type FCLTUProductionStatus int

FCLTUProductionStatus is the state of the forward physical channel, from the ProductionStatus INTEGER of the CLTU structures module.

This is a different type from the return services' ProductionStatus, not a wider spelling of it. FCLTU has four states where the return services have three, and the numbers do not line up: 1 is "configured" here and "halted" there. Sharing one Go type between them would mislabel every status report.

const (
	// FCLTUProductionOperational means the channel is configured and radiating.
	FCLTUProductionOperational FCLTUProductionStatus = 0
	// FCLTUProductionConfigured means the channel is ready but not radiating.
	FCLTUProductionConfigured FCLTUProductionStatus = 1
	// FCLTUProductionInterrupted means radiation stopped unexpectedly.
	FCLTUProductionInterrupted FCLTUProductionStatus = 2
	// FCLTUProductionHalted means the channel ended and will not resume.
	FCLTUProductionHalted FCLTUProductionStatus = 3
)

func (FCLTUProductionStatus) String

func (p FCLTUProductionStatus) String() string

String names the production status.

type FCLTUProvider

type FCLTUProvider struct {
	*ServiceProvider
	// contains filtered or unexported fields
}

FCLTUProvider is the provider half of an FCLTU instance. Partial.

It does track the expected CLTU number, because that is what makes the out-of-sequence check testable, but it does not radiate anything: the caller decides what happens to a CLTU and reports it back through SendAsyncNotify.

func NewFCLTUProvider

func NewFCLTUProvider(config ServiceConfig) (*FCLTUProvider, error)

NewFCLTUProvider prepares the provider half of an FCLTU instance.

func (FCLTUProvider) Association

func (c FCLTUProvider) Association() *Association

Association returns the association underneath.

func (FCLTUProvider) DeliveryMode

func (c FCLTUProvider) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (*FCLTUProvider) ExpectedCltuIdentification

func (p *FCLTUProvider) ExpectedCltuIdentification() (CltuIdentification, bool)

ExpectedCltuIdentification reports the number the next CLTU must carry.

func (*FCLTUProvider) HandlePDU

func (p *FCLTUProvider) HandlePDU(data []byte, now time.Time) (*FCLTUProviderEvent, error)

HandlePDU decodes one PDU from the user.

func (FCLTUProvider) HandlePeerAbort

func (c FCLTUProvider) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*FCLTUProvider) HandleStartInvocation

func (p *FCLTUProvider) HandleStartInvocation(
	s *FCLTUStartInvocation, answer *FCLTUStartReturn, now time.Time, randomNumber int32,
) error

HandleStartInvocation answers a START. Accepting moves to state 3 and arms the expected CLTU number from the invocation.

func (*FCLTUProvider) HandleTransferDataInvocation

func (p *FCLTUProvider) HandleTransferDataInvocation(
	t *FCLTUTransferDataInvocation, accept bool, diagnostic FCLTUTransferDataDiagnostic,
	bufferAvailable uint32, now time.Time, randomNumber int32,
) error

HandleTransferDataInvocation answers one CLTU.

It applies the sequence rule of clause 3.6.2.5 itself, because that rule is the protocol rather than a policy: a CLTU whose number is not the expected one is refused with 'out of sequence', and the return carries the number the provider still wants. Everything else (whether there is buffer space, whether the time window is sane) is the caller's decision, passed in through accept.

bufferAvailable is the free buffer to report, in octets.

func (FCLTUProvider) Kind

func (c FCLTUProvider) Kind() ServiceKind

Kind returns which service this is.

func (FCLTUProvider) NextPDU

func (c FCLTUProvider) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (FCLTUProvider) PeerAbort

func (c FCLTUProvider) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (FCLTUProvider) Pending

func (c FCLTUProvider) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*FCLTUProvider) SendAsyncNotify

func (p *FCLTUProvider) SendAsyncNotify(n *FCLTUAsyncNotifyInvocation, now time.Time) error

SendAsyncNotify queues a notification about a CLTU or the channel. Valid in states 2 and 3: a production status change is worth reporting whether or not CLTUs are flowing.

func (FCLTUProvider) State

func (c FCLTUProvider) State() ServiceState

State returns the service state.

type FCLTUProviderEvent

type FCLTUProviderEvent struct {
	Operation OperationType

	BindInvocation                 *BindInvocation
	UnbindInvocation               *UnbindInvocation
	StartInvocation                *FCLTUStartInvocation
	StopInvocation                 *StopInvocation
	ScheduleStatusReportInvocation *ScheduleStatusReportInvocation
	GetParameterInvocation         *GetParameterInvocation
	TransferDataInvocation         *FCLTUTransferDataInvocation
	ThrowEventInvocation           *FCLTUThrowEventInvocation
	PeerAbort                      *PeerAbort
}

FCLTUProviderEvent is one decoded PDU arriving at the provider.

type FCLTUStartDiagnostic

type FCLTUStartDiagnostic int

FCLTUStartDiagnostic explains a refused START, from the specific alternative of DiagnosticCltuStart.

const (
	FCLTUStartOutOfService          FCLTUStartDiagnostic = 0
	FCLTUStartUnableToComply        FCLTUStartDiagnostic = 1
	FCLTUStartProductionTimeExpired FCLTUStartDiagnostic = 2
	FCLTUStartInvalidCltuId         FCLTUStartDiagnostic = 3
)

func (FCLTUStartDiagnostic) String

func (f FCLTUStartDiagnostic) String() string

String names the diagnostic.

type FCLTUStartInvocation

type FCLTUStartInvocation struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// FirstCltuIdentification is the number the user will put on its first
	// CLTU. Everything after it must count up from here.
	FirstCltuIdentification CltuIdentification
}

FCLTUStartInvocation is the CltuStartInvocation of annex A2.4. It opens the CLTU stream and fixes the number the first CLTU will carry.

func DecodeFCLTUStartInvocation

func DecodeFCLTUStartInvocation(data []byte) (*FCLTUStartInvocation, error)

DecodeFCLTUStartInvocation parses a START invocation's content.

func (*FCLTUStartInvocation) Encode

func (s *FCLTUStartInvocation) Encode() ([]byte, error)

Encode serializes the START invocation's content.

func (*FCLTUStartInvocation) Humanize

func (s *FCLTUStartInvocation) Humanize() string

Humanize returns a human-readable summary.

type FCLTUStartReturn

type FCLTUStartReturn struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// Positive reports whether the provider accepted.
	Positive bool
	// StartRadiationTime is when the provider can begin radiating. Set when
	// Positive.
	StartRadiationTime Time
	// StopRadiationTime bounds the window, or is undefined for "until further
	// notice". Set when Positive.
	StopRadiationTime ConditionalTime
	// CommonDiagnostic is set when a refusal used the common alternative.
	CommonDiagnostic Diagnostics
	// SpecificDiagnostic is set when it used the FCLTU-specific one.
	SpecificDiagnostic FCLTUStartDiagnostic
	// UsedCommon says which alternative a refusal took.
	UsedCommon bool
}

FCLTUStartReturn is the CltuStartReturn of annex A2.5.

Its positive result is not the empty NULL the return services use: it carries the window the provider has reserved for radiation.

func DecodeFCLTUStartReturn

func DecodeFCLTUStartReturn(data []byte) (*FCLTUStartReturn, error)

DecodeFCLTUStartReturn parses a START return's content.

func (*FCLTUStartReturn) Encode

func (s *FCLTUStartReturn) Encode() ([]byte, error)

Encode serializes the START return's content.

func (*FCLTUStartReturn) Humanize

func (s *FCLTUStartReturn) Humanize() string

Humanize returns a human-readable summary.

type FCLTUStatusReportInvocation

type FCLTUStatusReportInvocation struct {
	Credentials      *Credentials
	LastProcessed    CltuLastProcessed
	LastOk           CltuLastOk
	ProductionStatus FCLTUProductionStatus
	UplinkStatus     UplinkStatus
	// NumberOfCltusReceived counts CLTUs the provider accepted.
	NumberOfCltusReceived uint32
	// NumberOfCltusProcessed counts those it took off the queue.
	NumberOfCltusProcessed uint32
	// NumberOfCltusRadiated counts those that actually went out. The gap
	// between these three is where CLTUs are being dropped.
	NumberOfCltusRadiated uint32
	// CltuBufferAvailable is the free buffer in octets.
	CltuBufferAvailable uint32
}

FCLTUStatusReportInvocation is the CltuStatusReportInvocation of annex A2.5: the periodic summary of the forward channel.

func DecodeFCLTUStatusReportInvocation

func DecodeFCLTUStatusReportInvocation(data []byte) (*FCLTUStatusReportInvocation, error)

DecodeFCLTUStatusReportInvocation parses a STATUS-REPORT invocation's content.

func (*FCLTUStatusReportInvocation) Encode

func (s *FCLTUStatusReportInvocation) Encode() ([]byte, error)

Encode serializes the STATUS-REPORT invocation's content.

func (*FCLTUStatusReportInvocation) Humanize

func (s *FCLTUStatusReportInvocation) Humanize() string

Humanize returns a human-readable summary.

type FCLTUThrowEventDiagnostic

type FCLTUThrowEventDiagnostic int

FCLTUThrowEventDiagnostic explains a refused THROW-EVENT, from the specific alternative of DiagnosticCltuThrowEvent.

const (
	FCLTUEventOperationNotSupported FCLTUThrowEventDiagnostic = 0
	FCLTUEventIdOutOfSequence       FCLTUThrowEventDiagnostic = 1
	FCLTUEventNoSuchEvent           FCLTUThrowEventDiagnostic = 2
)

func (FCLTUThrowEventDiagnostic) String

func (f FCLTUThrowEventDiagnostic) String() string

String names the diagnostic.

type FCLTUThrowEventInvocation

type FCLTUThrowEventInvocation struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// EventInvocationIdentification numbers this invocation, ascending like
	// the CLTU numbers.
	EventInvocationIdentification EventInvocationId
	// EventIdentifier names the event, 1 to 65535, defined by the service
	// agreement.
	EventIdentifier uint16
	// EventQualifier is the event's argument, 1 to 1024 octets, also defined
	// by the service agreement.
	EventQualifier []byte
}

FCLTUThrowEventInvocation is the CltuThrowEventInvocation of annex A2.4.

THROW-EVENT is the odd operation of this service. It does not carry data to the spacecraft; it asks the provider's own equipment to do something the service agreement defines, switch an antenna, change a modulation setting, start a ranging measurement. The library cannot know what the events mean, so it carries the identifier and qualifier through untouched.

func DecodeFCLTUThrowEventInvocation

func DecodeFCLTUThrowEventInvocation(data []byte) (*FCLTUThrowEventInvocation, error)

DecodeFCLTUThrowEventInvocation parses a THROW-EVENT invocation's content.

func (*FCLTUThrowEventInvocation) Encode

func (e *FCLTUThrowEventInvocation) Encode() ([]byte, error)

Encode serializes the THROW-EVENT invocation's content.

func (*FCLTUThrowEventInvocation) Humanize

func (e *FCLTUThrowEventInvocation) Humanize() string

Humanize returns a human-readable summary.

type FCLTUThrowEventReturn

type FCLTUThrowEventReturn struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// EventInvocationIdentification echoes the invocation this answers.
	EventInvocationIdentification EventInvocationId
	// Positive reports whether the provider accepted the event.
	Positive bool
	// CommonDiagnostic is set when a refusal used the common alternative.
	CommonDiagnostic Diagnostics
	// SpecificDiagnostic is set when it used the FCLTU-specific one.
	SpecificDiagnostic FCLTUThrowEventDiagnostic
	// UsedCommon says which alternative a refusal took.
	UsedCommon bool
}

FCLTUThrowEventReturn is the CltuThrowEventReturn of annex A2.5.

func DecodeFCLTUThrowEventReturn

func DecodeFCLTUThrowEventReturn(data []byte) (*FCLTUThrowEventReturn, error)

DecodeFCLTUThrowEventReturn parses a THROW-EVENT return's content.

func (*FCLTUThrowEventReturn) Encode

func (e *FCLTUThrowEventReturn) Encode() ([]byte, error)

Encode serializes the THROW-EVENT return's content.

func (*FCLTUThrowEventReturn) Humanize

func (e *FCLTUThrowEventReturn) Humanize() string

Humanize returns a human-readable summary.

type FCLTUTransferDataDiagnostic

type FCLTUTransferDataDiagnostic int

FCLTUTransferDataDiagnostic explains a refused CLTU, from the specific alternative of DiagnosticCltuTransferData.

const (
	FCLTUDataUnableToProcess       FCLTUTransferDataDiagnostic = 0
	FCLTUDataUnableToStore         FCLTUTransferDataDiagnostic = 1
	FCLTUDataOutOfSequence         FCLTUTransferDataDiagnostic = 2
	FCLTUDataInconsistentTimeRange FCLTUTransferDataDiagnostic = 3
	FCLTUDataInvalidTime           FCLTUTransferDataDiagnostic = 4
	FCLTUDataLateSldu              FCLTUTransferDataDiagnostic = 5
	FCLTUDataInvalidDelayTime      FCLTUTransferDataDiagnostic = 6
	FCLTUDataCltuError             FCLTUTransferDataDiagnostic = 7
)

func (FCLTUTransferDataDiagnostic) String

String names the diagnostic.

type FCLTUTransferDataInvocation

type FCLTUTransferDataInvocation struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// CltuIdentification numbers this CLTU. It must be one more than the last.
	CltuIdentification CltuIdentification
	// EarliestTransmissionTime and LatestTransmissionTime bound when the CLTU
	// may be radiated. Either may be undefined, leaving that end open.
	EarliestTransmissionTime ConditionalTime
	LatestTransmissionTime   ConditionalTime
	// DelayTime is how long, in microseconds, the provider must wait after the
	// previous CLTU before radiating this one.
	DelayTime uint32
	// RadiationNotification says whether the user wants an ASYNC-NOTIFY when
	// this CLTU is dealt with.
	RadiationNotification SlduStatusNotification
	// Data is the CLTU itself, 1 to 65536 octets: the acquisition sequence,
	// start sequence, codeblocks and tail sequence that pkg/tcsc builds.
	Data []byte
}

FCLTUTransferDataInvocation is the CltuTransferDataInvocation of annex A2.4: one CLTU handed to the provider for radiation.

func DecodeFCLTUTransferDataInvocation

func DecodeFCLTUTransferDataInvocation(data []byte) (*FCLTUTransferDataInvocation, error)

DecodeFCLTUTransferDataInvocation parses a TRANSFER-DATA invocation's content.

func (*FCLTUTransferDataInvocation) Encode

func (t *FCLTUTransferDataInvocation) Encode() ([]byte, error)

Encode serializes the TRANSFER-DATA invocation's content.

func (*FCLTUTransferDataInvocation) Humanize

func (t *FCLTUTransferDataInvocation) Humanize() string

Humanize returns a human-readable summary.

type FCLTUTransferDataReturn

type FCLTUTransferDataReturn struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// CltuIdentification echoes the CLTU this answers. On a refusal it is the
	// number the provider expected next, which tells the user where to resume.
	CltuIdentification CltuIdentification
	// CltuBufferAvailable is the free buffer in octets. This is the service's
	// flow control: a user that ignores it will be refused for lack of store.
	CltuBufferAvailable uint32
	// Positive reports whether the CLTU was accepted.
	Positive bool
	// CommonDiagnostic is set when a refusal used the common alternative.
	CommonDiagnostic Diagnostics
	// SpecificDiagnostic is set when it used the FCLTU-specific one.
	SpecificDiagnostic FCLTUTransferDataDiagnostic
	// UsedCommon says which alternative a refusal took.
	UsedCommon bool
}

FCLTUTransferDataReturn is the CltuTransferDataReturn of annex A2.5: the provider saying whether it took the CLTU, and how much room is left.

func DecodeFCLTUTransferDataReturn

func DecodeFCLTUTransferDataReturn(data []byte) (*FCLTUTransferDataReturn, error)

DecodeFCLTUTransferDataReturn parses a TRANSFER-DATA return's content.

func (*FCLTUTransferDataReturn) Encode

func (t *FCLTUTransferDataReturn) Encode() ([]byte, error)

Encode serializes the TRANSFER-DATA return's content.

func (*FCLTUTransferDataReturn) Humanize

func (t *FCLTUTransferDataReturn) Humanize() string

Humanize returns a human-readable summary.

type FCLTUUser

type FCLTUUser struct {
	*ServiceUser
	// contains filtered or unexported fields
}

FCLTUUser is the user half of a Forward CLTU instance.

It carries one piece of state the return services have no equivalent for: the next CLTU identification. CCSDS 912.1-B-5 clause 3.6.2.5.1 makes the number the user's to keep. It starts at the START invocation's firstCltuIdentification and goes up by one for every CLTU the provider accepts. Get it wrong and the provider answers 'out of sequence' and discards the CLTU, so the machine keeps the count rather than trusting the caller to.

The number advances as each CLTU is sent, not as each return arrives, Clause 3.1.6 expects the user to pipeline CLTUs without waiting for returns, and each one it sends must carry the next number. A refusal is where the count corrects itself: Clause 3.6.2.5.2b makes the provider quote the number it expected, so a user that fell out of step resynchronises from the refusal.

THROW-EVENT identifications work the same way (clause 3.9): the machine numbers each invocation, and a refusal quotes the identification the provider expected, which resynchronises the count.

func NewFCLTUUser

func NewFCLTUUser(config ServiceConfig) (*FCLTUUser, error)

NewFCLTUUser prepares the user half of an FCLTU instance.

func (FCLTUUser) Association

func (c FCLTUUser) Association() *Association

Association returns the association underneath.

func (FCLTUUser) DeliveryMode

func (c FCLTUUser) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (*FCLTUUser) HandlePDU

func (u *FCLTUUser) HandlePDU(data []byte, now time.Time) (*FCLTUUserEvent, error)

HandlePDU decodes one PDU from the provider and advances the machine.

A refused CLTU comes back as an event with TransferDataReturn set and ErrCltuOutOfSequence as the error: the PDU is valid and worth reading, and the error says the queue is no longer in step.

func (FCLTUUser) HandlePeerAbort

func (c FCLTUUser) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*FCLTUUser) HandleStartReturn

func (u *FCLTUUser) HandleStartReturn(r *FCLTUStartReturn) error

HandleStartReturn takes the answer to START. A positive answer moves to state 3 and arms the CLTU counter at the number the START asked for.

func (*FCLTUUser) HandleThrowEventReturn

func (u *FCLTUUser) HandleThrowEventReturn(r *FCLTUThrowEventReturn) error

HandleThrowEventReturn takes the answer to a THROW-EVENT.

A positive answer means the provider accepted the request, not that the event happened: whether the actions ran arrives later, in an ASYNC-NOTIFY carrying actionListCompleted or actionListNotCompleted.

A refusal echoes the event invocation identification the provider expected (clause 3.9.2.5), so the machine resynchronises its counter from it, the same recovery the CLTU numbers get.

func (*FCLTUUser) HandleTransferDataReturn

func (u *FCLTUUser) HandleTransferDataReturn(r *FCLTUTransferDataReturn) error

HandleTransferDataReturn takes the answer to one CLTU.

On acceptance the counter has already moved (it advanced when the CLTU was sent) so the return changes nothing. On refusal the counter is set to the number the provider says it expects, which clause 3.6.2.5.2b guarantees is in the return: a user that lost its place recovers without another START.

func (FCLTUUser) Kind

func (c FCLTUUser) Kind() ServiceKind

Kind returns which service this is.

func (*FCLTUUser) NextCltuIdentification

func (u *FCLTUUser) NextCltuIdentification() (CltuIdentification, bool)

NextCltuIdentification reports the number the next CLTU will carry, and whether a START has fixed it yet.

func (*FCLTUUser) NextEventInvocationId

func (u *FCLTUUser) NextEventInvocationId() EventInvocationId

NextEventInvocationId reports the identification the next THROW-EVENT will carry.

func (FCLTUUser) NextPDU

func (c FCLTUUser) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (FCLTUUser) PeerAbort

func (c FCLTUUser) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (FCLTUUser) Pending

func (c FCLTUUser) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*FCLTUUser) Start

func (u *FCLTUUser) Start(
	now time.Time, randomNumber int32, first CltuIdentification,
) (InvokeId, error)

Start opens the CLTU stream, fixing the first CLTU's number. State 2 only, per clause 3.4.1.4.

func (FCLTUUser) State

func (c FCLTUUser) State() ServiceState

State returns the service state.

func (*FCLTUUser) ThrowEvent

func (u *FCLTUUser) ThrowEvent(
	now time.Time, randomNumber int32, event uint16, qualifier []byte,
) (InvokeId, EventInvocationId, error)

ThrowEvent asks the provider's equipment to do something the service agreement defines. Valid in states 2 and 3, per clause 3.9.1.

The event invocation identification comes from the machine's counter, not from the caller: Clause 3.9.2.4 makes it a sequence the user must keep, exactly like the CLTU numbers. The identification used is returned, and it advances as the invocation is sent.

func (*FCLTUUser) TransferData

func (u *FCLTUUser) TransferData(
	now time.Time, randomNumber int32,
	cltu []byte, earliest, latest ConditionalTime,
	delay uint32, notification SlduStatusNotification,
) (InvokeId, CltuIdentification, error)

TransferData queues one CLTU for radiation. State 3 only, per clause 3.6.1.

The CLTU's identification is taken from the machine's counter, not from the caller: Clause 3.6.2.5.1 defines it as a sequence the user must keep unbroken. The data is a CLTU as pkg/tcsc.WrapCLTU builds one, acquisition sequence, start sequence, codeblocks and tail sequence.

type FCLTUUserEvent

type FCLTUUserEvent struct {
	Operation OperationType

	BindReturn                 *BindReturn
	UnbindReturn               *UnbindReturn
	StartReturn                *FCLTUStartReturn
	StopReturn                 *Acknowledgement
	ScheduleStatusReportReturn *ScheduleStatusReportReturn
	GetParameterReturn         *GetParameterReturn
	TransferDataReturn         *FCLTUTransferDataReturn
	ThrowEventReturn           *FCLTUThrowEventReturn
	AsyncNotify                *FCLTUAsyncNotifyInvocation
	StatusReport               *FCLTUStatusReportInvocation
	PeerAbort                  *PeerAbort
}

FCLTUUserEvent is one decoded PDU arriving at the user.

type FrameQuality

type FrameQuality int

FrameQuality reports what a delivered frame turned out to be, from the FrameQuality INTEGER of the RAF structures module.

const (
	// FrameGood passed error control.
	FrameGood FrameQuality = 0
	// FrameErred failed it.
	FrameErred FrameQuality = 1
	// FrameUndetermined could not be assessed.
	FrameUndetermined FrameQuality = 2
)

func (FrameQuality) String

func (f FrameQuality) String() string

String names the frame quality.

type GVCID

type GVCID struct {
	// SpacecraftID is the spacecraft identifier.
	SpacecraftID uint16
	// VersionNumber is the transfer frame version: 0 for TM, 1 for AOS.
	VersionNumber uint8
	// VirtualChannelID is the virtual channel, or absent for a master channel.
	VirtualChannelID uint8
	// MasterChannel reports whether this names a master channel rather than a
	// virtual one, in which case VirtualChannelID is meaningless.
	MasterChannel bool
}

GVCID identifies a global virtual channel: a spacecraft, a transfer frame version, and a virtual channel within it.

RCF and ROCF filter by it. The frame packages in this repository carry the same fields on their headers but have no shared type for the triple, so it lives here.

func DecodeGVCID

func DecodeGVCID(e *Element) (GVCID, error)

DecodeGVCID reads a GvcId SEQUENCE from an element.

func (GVCID) String

func (g GVCID) String() string

String renders the global virtual channel identifier.

func (GVCID) Validate

func (g GVCID) Validate() error

Validate checks a GVCID against the ranges of the GvcId SEQUENCE.

type GetParameterDiagnostic

type GetParameterDiagnostic int

GetParameterDiagnostic is the specific alternative of the DiagnosticRafGet / DiagnosticRcfGet / DiagnosticRocfGet / DiagnosticCltuGetParameter CHOICE. All four define the same single value.

const GetParameterUnknown GetParameterDiagnostic = 0

GetParameterUnknown is 'unknownParameter (0)': the provider does not have the named parameter.

func (GetParameterDiagnostic) String

func (g GetParameterDiagnostic) String() string

String names the diagnostic.

type GetParameterInvocation

type GetParameterInvocation struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// Parameter is the service's ParameterName value, from annex A of the
	// service specification. The names differ per service, so this package
	// does not enumerate them.
	Parameter int
}

GetParameterInvocation is the GET-PARAMETER invocation every service shares: RafGetParameterInvocation and its three siblings are the same three fields.

func DecodeGetParameterInvocation

func DecodeGetParameterInvocation(data []byte) (*GetParameterInvocation, error)

DecodeGetParameterInvocation parses a GET-PARAMETER invocation's content.

func (*GetParameterInvocation) Encode

func (g *GetParameterInvocation) Encode() ([]byte, error)

Encode serializes the GET-PARAMETER invocation's content.

func (*GetParameterInvocation) Humanize

func (g *GetParameterInvocation) Humanize() string

Humanize returns a human-readable summary.

type GetParameterReturn

type GetParameterReturn struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// Positive reports whether the provider had the parameter.
	Positive bool
	// Parameter is the chosen alternative of the service's parameter CHOICE,
	// still encoded: one complete BER element. Set when Positive.
	Parameter []byte
	// CommonDiagnostic is set when a refusal used the common alternative.
	CommonDiagnostic Diagnostics
	// SpecificDiagnostic is set when it used the specific one, whose only
	// value is 'unknown parameter'.
	SpecificDiagnostic GetParameterDiagnostic
	// UsedCommon says which alternative a refusal took.
	UsedCommon bool
}

GetParameterReturn is the GET-PARAMETER return every service shares in shape:

result CHOICE
{ positiveResult [0] <service>GetParameter
, negativeResult [1] Diagnostic<service>Get
}

The positive alternative's parameter CHOICE is service-specific and large, so it travels here as raw BER rather than a per-parameter Go type.

func DecodeGetParameterReturn

func DecodeGetParameterReturn(data []byte) (*GetParameterReturn, error)

DecodeGetParameterReturn parses a GET-PARAMETER return's content.

func (*GetParameterReturn) DecodeParameter added in v0.4.0

func (g *GetParameterReturn) DecodeParameter(service ServiceKind) (*ServiceParameter, bool, error)

DecodeParameter decodes this return's positive result against a service's parameter set.

It reports false when the return is negative, a provider answering 'unknown parameter', which the specs define for exactly the case where it does not have the one asked for.

func (*GetParameterReturn) Encode

func (g *GetParameterReturn) Encode() ([]byte, error)

Encode serializes the GET-PARAMETER return's content.

func (*GetParameterReturn) Humanize

func (g *GetParameterReturn) Humanize() string

Humanize returns a human-readable summary.

type Instance added in v0.4.0

type Instance struct {
	// Name is the service instance identifier, rendered the way operators
	// write it.
	Name string

	// Provider answers the operations a user drives.
	Provider *ServiceProvider

	// Production runs the transfer buffer, or nil for an instance configured
	// without one.
	Production *Production
	// contains filtered or unexported fields
}

Instance is one service instance in the complex: its provider, and its production when it has any.

func (*Instance) Kind added in v0.4.0

func (i *Instance) Kind() ServiceKind

Kind names the service this instance provides.

type InstanceConfig added in v0.4.0

type InstanceConfig struct {
	// Service is the instance's own configuration, as NewServiceProvider
	// takes it.
	Service ServiceConfig

	// Production configures the transfer buffer and production status. A
	// zero value leaves the instance without production, which is what a
	// forward service like FCLTU wants: it has no frames to buffer.
	Production *ProductionConfig
}

InstanceConfig describes one service instance the complex will serve.

type InvokeId

type InvokeId uint16

InvokeId correlates a confirmed operation's invocation with its return. IntUnsignedShort: INTEGER (0 .. 65535).

type LockStatus

type LockStatus int

LockStatus reports whether one stage of the receive chain is locked, from the RAF structures module.

const (
	LockInLock    LockStatus = 0
	LockOutOfLock LockStatus = 1
	LockNotInUse  LockStatus = 2
	LockUnknown   LockStatus = 3
)

func (LockStatus) String

func (l LockStatus) String() string

String names the lock status.

type LockStatusReport

type LockStatusReport struct {
	Time                 Time
	CarrierLockStatus    LockStatus
	SubcarrierLockStatus LockStatus
	SymbolSyncLockStatus LockStatus
}

LockStatusReport is the lock state of each stage of the receive chain at a moment, carried by a loss-of-frame-sync notification.

type Message

type Message struct {
	Type MessageType
	// Body is the message body: an encoded SLE PDU, a context body, or empty
	// for a heartbeat.
	Body []byte
}

Message is one TML message.

func DecodeMessage

func DecodeMessage(data []byte) (*Message, int, error)

DecodeMessage parses one complete TML message from the front of data, returning it and the octets consumed.

func DecodeMessageWithLimit

func DecodeMessageWithLimit(data []byte, maxBody int) (*Message, int, error)

DecodeMessageWithLimit parses one message, refusing a body beyond maxBody.

func HeartbeatMessage

func HeartbeatMessage() *Message

HeartbeatMessage returns a TML heartbeat: a header with an empty body.

func ReadMessage

func ReadMessage(r io.Reader, maxBody int) (*Message, error)

ReadMessage reads one TML message from r.

It reads the eight-octet header, then exactly as many body octets as the header promises, and no further. That matters on a stream: reading ahead would swallow the start of the next message.

func (*Message) Encode

func (m *Message) Encode() ([]byte, error)

Encode serializes the message per figure 3-3: a one-octet type, three reserved zero octets, a four-octet body length, then the body.

Clause 3.3.2.2.6: every integer is big-endian.

func (*Message) Humanize

func (m *Message) Humanize() string

Humanize returns a human-readable summary.

type MessageType

type MessageType uint8

MessageType is the TML message type identifier of table 3-1.

const (
	// MessageSLEPDU carries an encoded SLE protocol data unit.
	MessageSLEPDU MessageType = 1
	// MessageContext carries the TML initialization parameters. It is the
	// first message on a connection.
	MessageContext MessageType = 2
	// MessageHeartbeat probes an idle connection. Its body is empty.
	MessageHeartbeat MessageType = 3
)

func (MessageType) String

func (m MessageType) String() string

String names the message type.

func (MessageType) Valid

func (m MessageType) Valid() bool

Valid reports whether the type is one of the three of table 3-1.

type NotificationKind

type NotificationKind int

NotificationKind says which alternative a sync notification took, from the Notification CHOICE of CCSDS 911.1-B-5 annex A, which 911.2-B-4 and 911.5-B-4 repeat unchanged.

const (
	// NotifyLossFrameSync reports that frame synchronization was lost, and
	// carries the lock status of each stage.
	NotifyLossFrameSync NotificationKind = 0
	// NotifyProductionStatusChange reports a change in the channel's state.
	NotifyProductionStatusChange NotificationKind = 1
	// NotifyExcessiveDataBacklog reports the provider cannot keep up.
	NotifyExcessiveDataBacklog NotificationKind = 2
	// NotifyEndOfData reports the requested range is exhausted.
	NotifyEndOfData NotificationKind = 3
)

func (NotificationKind) String

func (n NotificationKind) String() string

String names the notification.

type OperationType

type OperationType int

OperationType names an SLE operation, independent of which service carries it. The wire tags differ per service; this does not.

const (
	OpUnknown OperationType = iota
	OpBindInvocation
	OpBindReturn
	OpUnbindInvocation
	OpUnbindReturn
	OpPeerAbort
	OpStartInvocation
	OpStartReturn
	OpStopInvocation
	OpStopReturn
	OpScheduleStatusReportInvocation
	OpScheduleStatusReportReturn
	OpGetParameterInvocation
	OpGetParameterReturn
	OpTransferBuffer
	OpStatusReportInvocation
	OpTransferDataInvocation
	OpAsyncNotifyInvocation
	OpThrowEventInvocation
	OpThrowEventReturn
	OpTransferDataReturn
)

func (OperationType) String

func (o OperationType) String() string

String names the operation.

type PDU

type PDU struct {
	Service   ServiceKind
	Operation OperationType
	// Tag is the wire tag it arrived under.
	Tag uint32
	// Content is the operation's encoded content, ready for the matching
	// decoder.
	Content []byte
}

PDU is one decoded SLE protocol data unit: which operation it is, and its still-encoded content.

func DecodePDU

func DecodePDU(data []byte, service ServiceKind) (*PDU, error)

DecodePDU reads the outer tag of an SLE PDU and reports which operation it names, leaving the content for the caller to decode.

func (*PDU) Humanize

func (p *PDU) Humanize() string

Humanize returns a human-readable summary.

type ParameterName added in v0.4.0

type ParameterName int32

ParameterName is the schema's ParameterName: the integer that names a configuration parameter.

The values are not contiguous and not ordered (acquisitionSequenceLength is 201 while apidList is 2) because the enumeration grew across issues and each service's additions were given their own range. They are transcribed from the INTEGER definition in CCSDS 911.1-B-5 annex A.

const (
	ParamAcquisitionSequenceLength ParameterName = 201
	ParamAPIDList                  ParameterName = 2
	ParamBitLockRequired           ParameterName = 3
	ParamBlockingTimeoutPeriod     ParameterName = 0
	ParamBlockingUsage             ParameterName = 1
	ParamBufferSize                ParameterName = 4
	ParamClcwGlobalVcID            ParameterName = 202
	ParamClcwPhysicalChannel       ParameterName = 203
	ParamCopCntrFramesRepetition   ParameterName = 300
	ParamDeliveryMode              ParameterName = 6
	ParamDirectiveInvocation       ParameterName = 7
	ParamDirectiveInvocationOnline ParameterName = 108

	ParamExpectedDirectiveIdentification       ParameterName = 8
	ParamExpectedEventInvocationIdentification ParameterName = 9
	ParamExpectedSlduIdentification            ParameterName = 10

	ParamFopSlidingWindow    ParameterName = 11
	ParamFopState            ParameterName = 12
	ParamLatencyLimit        ParameterName = 15
	ParamMapList             ParameterName = 16
	ParamMapMuxControl       ParameterName = 17
	ParamMapMuxScheme        ParameterName = 18
	ParamMaximumFrameLength  ParameterName = 19
	ParamMaximumPacketLength ParameterName = 20
	ParamMaximumSlduLength   ParameterName = 21
	ParamMinimumDelayTime    ParameterName = 204
	ParamMinReportingCycle   ParameterName = 301
	ParamModulationFrequency ParameterName = 22
	ParamModulationIndex     ParameterName = 23
	ParamNotificationMode    ParameterName = 205

	ParamPermittedControlWordTypeSet ParameterName = 101
	ParamPermittedFrameQuality       ParameterName = 302
	ParamPermittedGvcidSet           ParameterName = 24
	ParamPermittedTcVcidSet          ParameterName = 102
	ParamPermittedTransmissionMode   ParameterName = 107
	ParamPermittedUpdateModeSet      ParameterName = 103

	ParamPlop1IdleSequenceLength ParameterName = 206
	ParamPlopInEffect            ParameterName = 25
	ParamProtocolAbortMode       ParameterName = 207
	ParamReportingCycle          ParameterName = 26

	ParamRequestedControlWordType ParameterName = 104
	ParamRequestedFrameQuality    ParameterName = 27
	ParamRequestedGvcid           ParameterName = 28
	ParamRequestedTcVcid          ParameterName = 105
	ParamRequestedUpdateMode      ParameterName = 106

	ParamReturnTimeoutPeriod ParameterName = 29
	ParamRfAvailable         ParameterName = 30
	ParamRfAvailableRequired ParameterName = 31
	ParamSegmentHeader       ParameterName = 32

	ParamSequCntrFramesRepetition ParameterName = 303
	ParamSubcarrierToBitRateRatio ParameterName = 34
	ParamThrowEventOperation      ParameterName = 304
	ParamTimeoutType              ParameterName = 35
	ParamTimerInitial             ParameterName = 36
	ParamTransmissionLimit        ParameterName = 37

	ParamTransmitterFrameSequenceNumber ParameterName = 38
	ParamVcMuxControl                   ParameterName = 39
	ParamVcMuxScheme                    ParameterName = 40
	ParamVirtualChannel                 ParameterName = 41
)

The parameter names, from CCSDS 911.1-B-5 annex A.

func (ParameterName) String added in v0.4.0

func (p ParameterName) String() string

String returns the schema's spelling of the name.

type PeerAbort

type PeerAbort struct {
	Diagnostic PeerAbortDiagnostic
}

PeerAbort is the SlePeerAbort of annex A2.2: a bare diagnostic, with no credentials and no surrounding sequence.

func DecodePeerAbort

func DecodePeerAbort(data []byte) (*PeerAbort, error)

DecodePeerAbort parses a PEER-ABORT's content: the bare diagnostic octets found under the primitive [104] tag.

The legacy shape this package once emitted (a complete INTEGER TLV nested under a constructed [104]) is still recognized, so an old peer's abort is read rather than mistaken for a huge diagnostic.

func (*PeerAbort) Encode

func (p *PeerAbort) Encode() []byte

Encode serializes the PEER-ABORT's content: the bare two's complement octets of the diagnostic.

The SLE modules are DEFINITIONS IMPLICIT TAGS, and the PDU CHOICE makes the operation [104] IMPLICIT SlePeerAbort, so [104] replaces the INTEGER tag rather than wrapping it. On the wire the whole PDU is a primitive context-specific element, 9F 68 01 xx, with no nested INTEGER TLV.

func (*PeerAbort) Humanize

func (p *PeerAbort) Humanize() string

Humanize returns a human-readable summary.

func (*PeerAbort) UrgentData

func (p *PeerAbort) UrgentData() byte

UrgentData returns the diagnostic as the single octet CCSDS 913.1-B-2 clause 3.4 maps onto TCP urgent data. The aborting end sends this octet out of band (MSG_OOB) before closing the connection, so the peer can tell an abort from a failure; this package owns no socket, so sending it is the caller's job.

type PeerAbortDiagnostic

type PeerAbortDiagnostic int

PeerAbortDiagnostic explains an abrupt end to an association, from the PeerAbortDiagnostic INTEGER of annex A2.2. Values 128 to 255 are reserved for the communications technology in use.

const (
	AbortAccessDenied                PeerAbortDiagnostic = 0
	AbortUnexpectedResponderID       PeerAbortDiagnostic = 1
	AbortOperationalRequirement      PeerAbortDiagnostic = 2
	AbortProtocolError               PeerAbortDiagnostic = 3
	AbortCommunicationsFailure       PeerAbortDiagnostic = 4
	AbortEncodingError               PeerAbortDiagnostic = 5
	AbortReturnTimeout               PeerAbortDiagnostic = 6
	AbortEndOfServiceProvisionPeriod PeerAbortDiagnostic = 7
	AbortUnsolicitedInvokeID         PeerAbortDiagnostic = 8
	AbortOtherReason                 PeerAbortDiagnostic = 127
)

func (PeerAbortDiagnostic) String

func (p PeerAbortDiagnostic) String() string

String names the diagnostic.

type Production added in v0.4.0

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

Production runs the transfer buffer and the production status for one service instance.

It owns no clock. Every method that could involve time takes the time, and the release timer is checked by the caller through Due and Expired, which is the same bargain the rest of this library makes: a library that sleeps is a library you cannot test.

It is safe for concurrent use, because production and the association that drains it are naturally different goroutines.

func NewProduction added in v0.4.0

func NewProduction(config ProductionConfig) (*Production, error)

NewProduction prepares production for one service instance.

The initial status is halted, per clause B2.3: production is not yet configured for the instance. A caller that has configured it calls SetRunning.

func (*Production) Abort added in v0.4.0

func (p *Production) Abort()

Abort clears the transfer buffer without delivering it (clause 3.1.9.1.12).

An aborted association has nowhere to deliver to, so the contents go rather than waiting for a connection that is not coming back. The counters are kept: they describe the instance, not the association.

func (*Production) Backpressure added in v0.4.0

func (p *Production) Backpressure(now time.Time) bool

Backpressure handles the communications service refusing a released buffer (clause 3.1.9.1.9).

The whole buffer is discarded rather than the one record that would not fit, a 'data discarded due to excessive backlog' notification is inserted, and the release timer is restarted. Per clause 3.1.9.1.10 the buffer's size is incremented by one while that notification waits, so a channel configured with a buffer size of one still carries some telemetry rather than nothing but notifications.

It returns whether the buffer is due again, which it is when the size is one: the notification alone then fills it.

func (*Production) Capacity added in v0.4.0

func (p *Production) Capacity() int

Capacity reports the buffer's current size, including the temporary increment of clause 3.1.9.1.10 when one is in effect.

func (*Production) Counters added in v0.4.0

func (p *Production) Counters() (released, discarded int)

Counters reports how many buffers have been released and how many discarded for backpressure.

func (*Production) Deadline added in v0.4.0

func (p *Production) Deadline() (time.Time, bool)

Deadline reports when the release timer expires, and whether one is running.

A caller driving this from a select loop uses it to size its wait rather than polling Due.

func (*Production) Due added in v0.4.0

func (p *Production) Due(now time.Time) bool

Due reports whether the buffer should be released now: it is full, or the release timer has expired.

func (*Production) Expired added in v0.4.0

func (p *Production) Expired(now time.Time) bool

Expired reports whether the release timer has run out (clause 3.1.9.1.5).

It is false when no timer is running, which is the case for an empty buffer and for a configuration with no latency limit.

func (*Production) Humanize added in v0.4.0

func (p *Production) Humanize() string

Humanize returns a human-readable summary.

func (*Production) Insert added in v0.4.0

func (p *Production) Insert(frame *RAFTransferDataInvocation, now time.Time) (due bool, err error)

Insert puts one annotated frame into the transfer buffer.

It reports whether the buffer is now due for release, which happens when the buffer is full (clause 3.1.9.1.7a). A caller inserting frames checks the return and calls Release when it is true; it also has to check Expired between inserts, because the release timer can fire while nothing is arriving.

Frames are refused unless production is running: a provider that is halted or interrupted has no data to deliver, and buffering one anyway would deliver it late and out of sequence when production resumed.

func (*Production) InsertNotification added in v0.4.0

func (p *Production) InsertNotification(notification *SyncNotifyInvocation, now time.Time) (due bool, err error)

InsertNotification puts one synchronous notification into the transfer buffer.

Notifications are accepted whatever production is doing, because the notifications are how a user learns production stopped. Clause 3.1.9.1.3 requires a status-change notification to sit in sequence between the frames acquired before the event and those after it, which is only possible if it goes through the same buffer.

An 'end of data' notification releases the buffer at once (clause 3.1.9.1.7c), which is why this reports due as well.

func (*Production) Pending added in v0.4.0

func (p *Production) Pending() int

Pending reports how many records are waiting in the transfer buffer.

func (*Production) Release added in v0.4.0

func (p *Production) Release() RAFTransferBuffer

Release takes the buffer's contents to hand to the communications service.

It returns the records in insertion order (clause 3.1.9.1.8) and clears the buffer, stopping the release timer. An empty buffer yields nil, which is not an error: a caller may release on a schedule and find nothing waiting.

The temporary size increment of clause 3.1.9.1.10 is given back here, since the clause ties it to the buffer being passed to the communications service.

func (*Production) SetHalted added in v0.4.0

func (p *Production) SetHalted() (*SyncNotifyInvocation, bool)

SetHalted moves production to halted, which table B-1 allows from any state: it is direct management action.

func (*Production) SetInterrupted added in v0.4.0

func (p *Production) SetInterrupted() (*SyncNotifyInvocation, bool)

SetInterrupted moves production to interrupted, which table B-1 allows only from running: it is the provider detecting a production fault.

From halted it is refused. Halted means production is not configured, so there is nothing running to be interrupted, and reporting one would tell a user the channel had failed rather than that it was never started.

func (*Production) SetRunning added in v0.4.0

func (p *Production) SetRunning() (*SyncNotifyInvocation, bool)

SetRunning moves production to running.

Table B-1 allows it from halted (management has configured production) and from interrupted (the provider has detected the fault is corrected). It returns the notification to deliver, which the caller inserts into the buffer; clause 3.1.9.1.3 puts a status-change notification in sequence with the frames, not out of band.

Calling it when production is already running changes nothing and yields no notification: table B-1 lists notifications against transitions, and a non-transition is not one.

func (*Production) Status added in v0.4.0

func (p *Production) Status() ProductionStatus

Status reports the current production status.

func (*Production) Stop added in v0.4.0

func (p *Production) Stop() RAFTransferBuffer

Stop builds the buffer for immediate delivery on an accepted STOP invocation (clause 3.1.9.1.11).

The clause requires the provider to build and pass the buffer at once rather than waiting for the timer, so a user that stops a service gets what production had already recovered.

type ProductionConfig added in v0.4.0

type ProductionConfig struct {
	// BufferSize is transfer-buffer-size: how many transfer-data and
	// sync-notify records the buffer holds before it must be released
	// (clause 3.1.9.1.6). It must be at least one.
	BufferSize int

	// LatencyLimit is how long the release timer runs from the moment a
	// record enters an empty buffer (clause 3.1.9.1.5). Zero means no timer, which
	// is the offline and complete-online case: Clause 3.1.9.1 requires the timer
	// only for timely online delivery, though the buffer itself is used in
	// every mode.
	LatencyLimit time.Duration
}

ProductionConfig is what service management sets for one service instance (clause 3.1.9.1.5 and clause 3.1.9.1.6).

func (ProductionConfig) Validate added in v0.4.0

func (c ProductionConfig) Validate() error

Validate checks the configuration.

type ProductionStatus

type ProductionStatus int

ProductionStatus is the state of the return physical channel, from the RAF structures module and annex B.

const (
	// ProductionRunning means the channel is producing data.
	ProductionRunning ProductionStatus = 0
	// ProductionInterrupted means production stopped unexpectedly and may resume.
	ProductionInterrupted ProductionStatus = 1
	// ProductionHalted means production ended and will not resume.
	ProductionHalted ProductionStatus = 2
)

func (ProductionStatus) String

func (p ProductionStatus) String() string

String names the production status.

type RAFProvider

type RAFProvider struct {
	*ServiceProvider
}

RAFProvider is the provider half of a RAF instance. Pair it with a Production for the transfer buffer that clause 3.1.9.1 requires of a return service.

func NewRAFProvider

func NewRAFProvider(config ServiceConfig) (*RAFProvider, error)

NewRAFProvider prepares the provider half of a RAF instance.

func (RAFProvider) Association

func (c RAFProvider) Association() *Association

Association returns the association underneath.

func (RAFProvider) DeliveryMode

func (c RAFProvider) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (*RAFProvider) HandlePDU

func (p *RAFProvider) HandlePDU(data []byte, now time.Time) (*RAFProviderEvent, error)

HandlePDU decodes one PDU from the user. Unlike the user's HandlePDU this only decodes and reports: the answer is the caller's to compose, because only the caller knows whether the provider can comply.

func (RAFProvider) HandlePeerAbort

func (c RAFProvider) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*RAFProvider) HandleStartInvocation

func (p *RAFProvider) HandleStartInvocation(
	s *RAFStartInvocation, answer *RAFStartReturn, now time.Time, randomNumber int32,
) error

HandleStartInvocation answers a START. Accepting moves to state 3, which is state table row 9's positive branch.

func (RAFProvider) Kind

func (c RAFProvider) Kind() ServiceKind

Kind returns which service this is.

func (RAFProvider) NextPDU

func (c RAFProvider) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (RAFProvider) PeerAbort

func (c RAFProvider) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (RAFProvider) Pending

func (c RAFProvider) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*RAFProvider) SendTransferBuffer

func (p *RAFProvider) SendTransferBuffer(buffer RAFTransferBuffer, now time.Time) error

SendTransferBuffer queues a buffer of frames and notifications. State 3 only, per clause 3.6.1.3.

func (RAFProvider) State

func (c RAFProvider) State() ServiceState

State returns the service state.

type RAFProviderEvent

type RAFProviderEvent struct {
	Operation OperationType

	BindInvocation                 *BindInvocation
	UnbindInvocation               *UnbindInvocation
	StartInvocation                *RAFStartInvocation
	StopInvocation                 *StopInvocation
	ScheduleStatusReportInvocation *ScheduleStatusReportInvocation
	GetParameterInvocation         *GetParameterInvocation
	PeerAbort                      *PeerAbort
}

RAFProviderEvent is one decoded PDU arriving at the provider.

type RAFStartDiagnostic

type RAFStartDiagnostic int

RAFStartDiagnostic explains a refused START, from the DiagnosticRafStart CHOICE of the RAF structures module.

The CHOICE has a common alternative carrying the shared Diagnostics and a specific one carrying these.

const (
	RAFStartOutOfService     RAFStartDiagnostic = 0
	RAFStartUnableToComply   RAFStartDiagnostic = 1
	RAFStartInvalidStartTime RAFStartDiagnostic = 2
	RAFStartInvalidStopTime  RAFStartDiagnostic = 3
	RAFStartMissingTimeValue RAFStartDiagnostic = 4
)

func (RAFStartDiagnostic) String

func (r RAFStartDiagnostic) String() string

String names the diagnostic.

type RAFStartInvocation

type RAFStartInvocation struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// StartTime and StopTime bound the requested range. Either may be
	// undefined, meaning "from now" and "until further notice".
	StartTime ConditionalTime
	StopTime  ConditionalTime
	// RequestedFrameQuality selects which frames to deliver.
	RequestedFrameQuality RequestedFrameQuality
}

RAFStartInvocation is the RafStartInvocation of annex A2.6. It asks the provider to begin delivering frames.

func DecodeRAFStartInvocation

func DecodeRAFStartInvocation(data []byte) (*RAFStartInvocation, error)

DecodeRAFStartInvocation parses a START invocation's content.

func (*RAFStartInvocation) Encode

func (s *RAFStartInvocation) Encode() ([]byte, error)

Encode serializes the START invocation's content.

func (*RAFStartInvocation) Humanize

func (s *RAFStartInvocation) Humanize() string

Humanize returns a human-readable summary.

type RAFStartReturn

type RAFStartReturn struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// Positive reports whether the provider accepted.
	Positive bool
	// CommonDiagnostic is set when the refusal used the common alternative.
	CommonDiagnostic Diagnostics
	// SpecificDiagnostic is set when it used the RAF-specific one.
	SpecificDiagnostic RAFStartDiagnostic
	// UsedCommon says which alternative a refusal took.
	UsedCommon bool
}

RAFStartReturn is the RafStartReturn of annex A2.7.

func DecodeRAFStartReturn

func DecodeRAFStartReturn(data []byte) (*RAFStartReturn, error)

DecodeRAFStartReturn parses a START return's content.

func (*RAFStartReturn) Encode

func (s *RAFStartReturn) Encode() ([]byte, error)

Encode serializes the START return's content.

func (*RAFStartReturn) Humanize

func (s *RAFStartReturn) Humanize() string

Humanize returns a human-readable summary.

type RAFStatusReportInvocation

type RAFStatusReportInvocation struct {
	Credentials *Credentials
	// ErrorFreeFrameNumber counts frames delivered that passed error control.
	ErrorFreeFrameNumber uint32
	// DeliveredFrameNumber counts every frame delivered.
	DeliveredFrameNumber uint32

	FrameSyncLockStatus  LockStatus
	SymbolSyncLockStatus LockStatus
	SubcarrierLockStatus LockStatus
	CarrierLockStatus    LockStatus
	ProductionStatus     ProductionStatus
}

RAFStatusReportInvocation is the RafStatusReportInvocation of annex A2.7: a periodic summary of how the channel is doing.

func DecodeRAFStatusReportInvocation

func DecodeRAFStatusReportInvocation(data []byte) (*RAFStatusReportInvocation, error)

DecodeRAFStatusReportInvocation parses a STATUS-REPORT invocation's content.

func (*RAFStatusReportInvocation) Encode

func (s *RAFStatusReportInvocation) Encode() ([]byte, error)

Encode serializes the STATUS-REPORT invocation's content.

func (*RAFStatusReportInvocation) Humanize

func (s *RAFStatusReportInvocation) Humanize() string

Humanize returns a human-readable summary.

type RAFTransferBuffer

type RAFTransferBuffer []TransferBufferEntry

RAFTransferBuffer is the RafTransferBuffer of annex A2.7: a SEQUENCE OF frames and notifications, delivered together.

Buffering is why RAF scales. A provider recovering frames at line rate does not send one PDU per frame; it fills a buffer and ships it, so the TCP connection carries a few large messages rather than thousands of small ones.

func DecodeRAFTransferBuffer

func DecodeRAFTransferBuffer(data []byte) (RAFTransferBuffer, error)

DecodeRAFTransferBuffer parses a transfer buffer's content.

func (RAFTransferBuffer) Encode

func (b RAFTransferBuffer) Encode() ([]byte, error)

Encode serializes the transfer buffer's content.

func (RAFTransferBuffer) Frames

Frames returns just the frames in the buffer, which is what a user normally wants.

func (RAFTransferBuffer) Humanize

func (b RAFTransferBuffer) Humanize() string

Humanize returns a human-readable summary.

type RAFTransferDataInvocation

type RAFTransferDataInvocation struct {
	Credentials *Credentials
	// EarthReceiveTime is when the frame reached the ground.
	EarthReceiveTime Time
	// AntennaId names the antenna that received it.
	AntennaId AntennaId
	// DataLinkContinuity counts frames lost since the last delivery, or -1
	// when the provider cannot tell. INTEGER (-1 .. 16777215).
	DataLinkContinuity int32
	// DeliveredFrameQuality is what the frame turned out to be.
	DeliveredFrameQuality FrameQuality
	// PrivateAnnotation is an optional provider-defined field, 1 to 128 octets.
	PrivateAnnotation []byte
	// Data is the frame itself: a CADU's frame content, as pkg/tmsc.UnwrapCADU
	// produces.
	Data []byte
}

RAFTransferDataInvocation is the RafTransferDataInvocation of annex A2.7: one telemetry frame with the metadata describing how it arrived.

func DecodeRAFTransferDataInvocation

func DecodeRAFTransferDataInvocation(data []byte) (*RAFTransferDataInvocation, error)

DecodeRAFTransferDataInvocation parses a TRANSFER-DATA invocation's content.

func (*RAFTransferDataInvocation) Encode

func (t *RAFTransferDataInvocation) Encode() ([]byte, error)

Encode serializes the TRANSFER-DATA invocation's content.

func (*RAFTransferDataInvocation) Humanize

func (t *RAFTransferDataInvocation) Humanize() string

Humanize returns a human-readable summary.

type RAFUser

type RAFUser struct {
	*ServiceUser
}

RAFUser is the user half of a RAF service instance.

The lifecycle is the one the state table of CCSDS 911.1-B-5 clause 4.2.2 walks: Bind, wait for the return, Start, then pull transfer buffers until you have what you came for, Stop, Unbind. Each call queues a PDU; NextPDU hands it to you to write, and HandlePDU takes what comes back.

func NewRAFUser

func NewRAFUser(config ServiceConfig) (*RAFUser, error)

NewRAFUser prepares the user half of a RAF instance. The configuration's Kind is set for you.

func (RAFUser) Association

func (c RAFUser) Association() *Association

Association returns the association underneath.

func (RAFUser) DeliveryMode

func (c RAFUser) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (*RAFUser) HandlePDU

func (u *RAFUser) HandlePDU(data []byte, now time.Time) (*RAFUserEvent, error)

HandlePDU decodes one PDU from the provider, advances the state machine and returns what arrived.

A PDU the state does not allow is answered with a PEER-ABORT for protocol error, queued for sending, and reported as ErrUnexpectedPDU, which is what every 'peer abort protocol error' cell of the state table says to do.

func (RAFUser) HandlePeerAbort

func (c RAFUser) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*RAFUser) HandleStartReturn

func (u *RAFUser) HandleStartReturn(r *RAFStartReturn) error

HandleStartReturn takes the answer to START. A positive answer moves to state 3.

func (RAFUser) Kind

func (c RAFUser) Kind() ServiceKind

Kind returns which service this is.

func (RAFUser) NextPDU

func (c RAFUser) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (RAFUser) PeerAbort

func (c RAFUser) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (RAFUser) Pending

func (c RAFUser) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*RAFUser) Start

func (u *RAFUser) Start(
	now time.Time, randomNumber int32,
	start, stop ConditionalTime, quality RequestedFrameQuality,
) (InvokeId, error)

Start asks the provider to begin delivering frames. State 2 only, per Clause 3.4.1.7.

func (RAFUser) State

func (c RAFUser) State() ServiceState

State returns the service state.

type RAFUserEvent

type RAFUserEvent struct {
	Operation OperationType

	BindReturn                 *BindReturn
	UnbindReturn               *UnbindReturn
	StartReturn                *RAFStartReturn
	StopReturn                 *Acknowledgement
	ScheduleStatusReportReturn *ScheduleStatusReportReturn
	GetParameterReturn         *GetParameterReturn
	TransferBuffer             RAFTransferBuffer
	StatusReport               *RAFStatusReportInvocation
	PeerAbort                  *PeerAbort
}

RAFUserEvent is one decoded PDU arriving at the user. Exactly one field is set, and Operation says which.

type RCFProvider

type RCFProvider struct {
	*ServiceProvider
}

RCFProvider is the provider half of an RCF instance. Partial, like the rest.

func NewRCFProvider

func NewRCFProvider(config ServiceConfig) (*RCFProvider, error)

NewRCFProvider prepares the provider half of an RCF instance.

func (RCFProvider) Association

func (c RCFProvider) Association() *Association

Association returns the association underneath.

func (RCFProvider) DeliveryMode

func (c RCFProvider) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (RCFProvider) HandlePeerAbort

func (c RCFProvider) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*RCFProvider) HandleStartInvocation

func (p *RCFProvider) HandleStartInvocation(
	s *RCFStartInvocation, answer *RCFStartReturn, now time.Time, randomNumber int32,
) error

HandleStartInvocation answers a START, moving to state 3 when it accepts.

func (RCFProvider) Kind

func (c RCFProvider) Kind() ServiceKind

Kind returns which service this is.

func (RCFProvider) NextPDU

func (c RCFProvider) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (RCFProvider) PeerAbort

func (c RCFProvider) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (RCFProvider) Pending

func (c RCFProvider) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*RCFProvider) SendTransferBuffer

func (p *RCFProvider) SendTransferBuffer(buffer RCFTransferBuffer, now time.Time) error

SendTransferBuffer queues a buffer of frames and notifications. State 3 only.

func (RCFProvider) State

func (c RCFProvider) State() ServiceState

State returns the service state.

type RCFStartDiagnostic

type RCFStartDiagnostic int

RCFStartDiagnostic explains a refused START, from the DiagnosticRcfStart CHOICE of the RCF structures module.

const (
	RCFStartOutOfService     RCFStartDiagnostic = 0
	RCFStartUnableToComply   RCFStartDiagnostic = 1
	RCFStartInvalidStartTime RCFStartDiagnostic = 2
	RCFStartInvalidStopTime  RCFStartDiagnostic = 3
	RCFStartMissingTimeValue RCFStartDiagnostic = 4
	RCFStartInvalidGVCID     RCFStartDiagnostic = 5
)

func (RCFStartDiagnostic) String

func (r RCFStartDiagnostic) String() string

String names the diagnostic.

type RCFStartInvocation

type RCFStartInvocation struct {
	Credentials *Credentials
	InvokeId    InvokeId
	StartTime   ConditionalTime
	StopTime    ConditionalTime
	// RequestedGVCID names the master or virtual channel to deliver.
	RequestedGVCID GVCID
}

RCFStartInvocation is the RcfStartInvocation of the RCF incoming PDUs module: like RAF's, but naming a channel rather than a frame quality.

func DecodeRCFStartInvocation

func DecodeRCFStartInvocation(data []byte) (*RCFStartInvocation, error)

DecodeRCFStartInvocation parses a START invocation's content.

func (*RCFStartInvocation) Encode

func (s *RCFStartInvocation) Encode() ([]byte, error)

Encode serializes the START invocation's content.

func (*RCFStartInvocation) Humanize

func (s *RCFStartInvocation) Humanize() string

Humanize returns a human-readable summary.

type RCFStartReturn

type RCFStartReturn struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// Positive reports whether the provider accepted.
	Positive bool
	// CommonDiagnostic is set when a refusal used the common alternative.
	CommonDiagnostic Diagnostics
	// SpecificDiagnostic is set when it used the RCF-specific one.
	SpecificDiagnostic RCFStartDiagnostic
	// UsedCommon says which alternative a refusal took.
	UsedCommon bool
}

RCFStartReturn is the RcfStartReturn of annex A2.7.

Unlike FCLTU's, its positive result is an empty NULL: there is nothing to tell the user beyond "yes".

func DecodeRCFStartReturn

func DecodeRCFStartReturn(data []byte) (*RCFStartReturn, error)

DecodeRCFStartReturn parses a START return's content.

func (*RCFStartReturn) Encode

func (s *RCFStartReturn) Encode() ([]byte, error)

Encode serializes the START return's content.

func (*RCFStartReturn) Humanize

func (s *RCFStartReturn) Humanize() string

Humanize returns a human-readable summary.

type RCFStatusReportInvocation

type RCFStatusReportInvocation struct {
	Credentials *Credentials
	// DeliveredFrameNumber counts frames delivered on the requested channel.
	DeliveredFrameNumber uint32

	FrameSyncLockStatus  LockStatus
	SymbolSyncLockStatus LockStatus
	SubcarrierLockStatus LockStatus
	CarrierLockStatus    LockStatus
	ProductionStatus     ProductionStatus
}

RCFStatusReportInvocation is the RcfStatusReportInvocation of annex A2.7.

It is RAF's status report with one field missing. RAF counts frames twice ( delivered, and of those, error free) because RAF can deliver bad frames. RCF only ever delivers good ones, so the error-free count would say nothing and the spec leaves it out.

func DecodeRCFStatusReportInvocation

func DecodeRCFStatusReportInvocation(data []byte) (*RCFStatusReportInvocation, error)

DecodeRCFStatusReportInvocation parses a STATUS-REPORT invocation's content.

func (*RCFStatusReportInvocation) Encode

func (s *RCFStatusReportInvocation) Encode() ([]byte, error)

Encode serializes the STATUS-REPORT invocation's content.

func (*RCFStatusReportInvocation) Humanize

func (s *RCFStatusReportInvocation) Humanize() string

Humanize returns a human-readable summary.

type RCFTransferBuffer

type RCFTransferBuffer []RCFTransferBufferEntry

RCFTransferBuffer is the RcfTransferBuffer of annex A2.7: a SEQUENCE OF frames and notifications, delivered together for the same reason RAF buffers.

func DecodeRCFTransferBuffer

func DecodeRCFTransferBuffer(data []byte) (RCFTransferBuffer, error)

DecodeRCFTransferBuffer parses a transfer buffer's content.

func (RCFTransferBuffer) Encode

func (b RCFTransferBuffer) Encode() ([]byte, error)

Encode serializes the transfer buffer's content.

func (RCFTransferBuffer) Frames

Frames returns just the frames in the buffer.

func (RCFTransferBuffer) Humanize

func (b RCFTransferBuffer) Humanize() string

Humanize returns a human-readable summary.

type RCFTransferBufferEntry

type RCFTransferBufferEntry struct {
	Frame        *RCFTransferDataInvocation
	Notification *SyncNotifyInvocation
}

RCFTransferBufferEntry is one element of an RcfTransferBuffer.

FrameOrNotification ::= CHOICE
{ annotatedFrame   [0] RcfTransferDataInvocation
, syncNotification [1] RcfSyncNotifyInvocation
}

type RCFTransferDataInvocation

type RCFTransferDataInvocation struct {
	Credentials        *Credentials
	EarthReceiveTime   Time
	AntennaId          AntennaId
	DataLinkContinuity int32
	PrivateAnnotation  []byte
	Data               []byte
}

RCFTransferDataInvocation is the RcfTransferDataInvocation of the RCF outgoing PDUs module.

It differs from RAF's by having no delivered-frame-quality field: RCF delivers only frames that passed error control, so there is nothing to report.

func DecodeRCFTransferDataInvocation

func DecodeRCFTransferDataInvocation(data []byte) (*RCFTransferDataInvocation, error)

DecodeRCFTransferDataInvocation parses a TRANSFER-DATA invocation's content.

func (*RCFTransferDataInvocation) Encode

func (t *RCFTransferDataInvocation) Encode() ([]byte, error)

Encode serializes the TRANSFER-DATA invocation's content.

func (*RCFTransferDataInvocation) Humanize

func (t *RCFTransferDataInvocation) Humanize() string

Humanize returns a human-readable summary.

type RCFUser

type RCFUser struct {
	*ServiceUser
}

RCFUser is the user half of an RCF service instance.

It is RAF's machine with one difference in START: the user names a channel instead of a frame quality, and gets only that channel's frames.

func NewRCFUser

func NewRCFUser(config ServiceConfig) (*RCFUser, error)

NewRCFUser prepares the user half of an RCF instance.

func (RCFUser) Association

func (c RCFUser) Association() *Association

Association returns the association underneath.

func (RCFUser) DeliveryMode

func (c RCFUser) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (*RCFUser) HandlePDU

func (u *RCFUser) HandlePDU(data []byte, now time.Time) (*RCFUserEvent, error)

HandlePDU decodes one PDU from the provider and advances the machine.

func (RCFUser) HandlePeerAbort

func (c RCFUser) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*RCFUser) HandleStartReturn

func (u *RCFUser) HandleStartReturn(r *RCFStartReturn) error

HandleStartReturn takes the answer to START, moving to state 3 when positive.

func (RCFUser) Kind

func (c RCFUser) Kind() ServiceKind

Kind returns which service this is.

func (RCFUser) NextPDU

func (c RCFUser) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (RCFUser) PeerAbort

func (c RCFUser) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (RCFUser) Pending

func (c RCFUser) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*RCFUser) Start

func (u *RCFUser) Start(
	now time.Time, randomNumber int32, start, stop ConditionalTime, channel GVCID,
) (InvokeId, error)

Start asks the provider to begin delivering one channel's frames. State 2 only.

func (RCFUser) State

func (c RCFUser) State() ServiceState

State returns the service state.

type RCFUserEvent

type RCFUserEvent struct {
	Operation OperationType

	BindReturn                 *BindReturn
	UnbindReturn               *UnbindReturn
	StartReturn                *RCFStartReturn
	StopReturn                 *Acknowledgement
	ScheduleStatusReportReturn *ScheduleStatusReportReturn
	GetParameterReturn         *GetParameterReturn
	TransferBuffer             RCFTransferBuffer
	StatusReport               *RCFStatusReportInvocation
	PeerAbort                  *PeerAbort
}

RCFUserEvent is one decoded PDU arriving at the user.

type ROCFProvider

type ROCFProvider struct {
	*ServiceProvider
}

ROCFProvider is the provider half of an ROCF instance. Partial.

func NewROCFProvider

func NewROCFProvider(config ServiceConfig) (*ROCFProvider, error)

NewROCFProvider prepares the provider half of an ROCF instance.

func (ROCFProvider) Association

func (c ROCFProvider) Association() *Association

Association returns the association underneath.

func (ROCFProvider) DeliveryMode

func (c ROCFProvider) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (ROCFProvider) HandlePeerAbort

func (c ROCFProvider) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*ROCFProvider) HandleStartInvocation

func (p *ROCFProvider) HandleStartInvocation(
	s *ROCFStartInvocation, answer *ROCFStartReturn, now time.Time, randomNumber int32,
) error

HandleStartInvocation answers a START, moving to state 3 when it accepts.

func (ROCFProvider) Kind

func (c ROCFProvider) Kind() ServiceKind

Kind returns which service this is.

func (ROCFProvider) NextPDU

func (c ROCFProvider) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (ROCFProvider) PeerAbort

func (c ROCFProvider) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (ROCFProvider) Pending

func (c ROCFProvider) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*ROCFProvider) SendTransferBuffer

func (p *ROCFProvider) SendTransferBuffer(buffer ROCFTransferBuffer, now time.Time) error

SendTransferBuffer queues a buffer of control fields and notifications. State 3 only.

func (ROCFProvider) State

func (c ROCFProvider) State() ServiceState

State returns the service state.

type ROCFStartDiagnostic

type ROCFStartDiagnostic int

ROCFStartDiagnostic explains a refused START, from the DiagnosticRocfStart CHOICE of the ROCF structures module.

const (
	ROCFStartOutOfService           ROCFStartDiagnostic = 0
	ROCFStartUnableToComply         ROCFStartDiagnostic = 1
	ROCFStartInvalidStartTime       ROCFStartDiagnostic = 2
	ROCFStartInvalidStopTime        ROCFStartDiagnostic = 3
	ROCFStartMissingTimeValue       ROCFStartDiagnostic = 4
	ROCFStartInvalidGVCID           ROCFStartDiagnostic = 5
	ROCFStartInvalidControlWordType ROCFStartDiagnostic = 6
	ROCFStartInvalidTcVcid          ROCFStartDiagnostic = 7
	ROCFStartInvalidUpdateMode      ROCFStartDiagnostic = 8
)

func (ROCFStartDiagnostic) String

func (r ROCFStartDiagnostic) String() string

String names the diagnostic.

type ROCFStartInvocation

type ROCFStartInvocation struct {
	Credentials    *Credentials
	InvokeId       InvokeId
	StartTime      ConditionalTime
	StopTime       ConditionalTime
	RequestedGVCID GVCID
	// ControlWordType filters which control words to deliver.
	ControlWordType ControlWordType
	// UpdateMode says whether to deliver every one or only changes.
	UpdateMode UpdateMode
}

ROCFStartInvocation is the RocfStartInvocation of the ROCF incoming PDUs module.

func DecodeROCFStartInvocation

func DecodeROCFStartInvocation(data []byte) (*ROCFStartInvocation, error)

DecodeROCFStartInvocation parses a START invocation's content.

func (*ROCFStartInvocation) Encode

func (s *ROCFStartInvocation) Encode() ([]byte, error)

Encode serializes the START invocation's content.

func (*ROCFStartInvocation) Humanize

func (s *ROCFStartInvocation) Humanize() string

Humanize returns a human-readable summary.

type ROCFStartReturn

type ROCFStartReturn struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// Positive reports whether the provider accepted.
	Positive bool
	// CommonDiagnostic is set when a refusal used the common alternative.
	CommonDiagnostic Diagnostics
	// SpecificDiagnostic is set when it used the ROCF-specific one.
	SpecificDiagnostic ROCFStartDiagnostic
	// UsedCommon says which alternative a refusal took.
	UsedCommon bool
}

ROCFStartReturn is the RocfStartReturn of annex A2.7.

func DecodeROCFStartReturn

func DecodeROCFStartReturn(data []byte) (*ROCFStartReturn, error)

DecodeROCFStartReturn parses a START return's content.

func (*ROCFStartReturn) Encode

func (s *ROCFStartReturn) Encode() ([]byte, error)

Encode serializes the START return's content.

func (*ROCFStartReturn) Humanize

func (s *ROCFStartReturn) Humanize() string

Humanize returns a human-readable summary.

type ROCFStatusReportInvocation

type ROCFStatusReportInvocation struct {
	Credentials *Credentials
	// ProcessedFrameNumber counts frames the provider examined.
	ProcessedFrameNumber uint32
	// DeliveredOCFsNumber counts control fields actually delivered.
	DeliveredOCFsNumber uint32

	FrameSyncLockStatus  LockStatus
	SymbolSyncLockStatus LockStatus
	SubcarrierLockStatus LockStatus
	CarrierLockStatus    LockStatus
	ProductionStatus     ProductionStatus
}

ROCFStatusReportInvocation is the RocfStatusReportInvocation of annex A2.7.

Its two counters are not the return services' usual pair. ROCF counts the frames it looked at and the OCFs it sent on, and those differ: a frame may carry no operational control field, or carry one the filter rejected. The gap between the two numbers is how much of the channel was not of interest.

func DecodeROCFStatusReportInvocation

func DecodeROCFStatusReportInvocation(data []byte) (*ROCFStatusReportInvocation, error)

DecodeROCFStatusReportInvocation parses a STATUS-REPORT invocation's content.

func (*ROCFStatusReportInvocation) Encode

func (s *ROCFStatusReportInvocation) Encode() ([]byte, error)

Encode serializes the STATUS-REPORT invocation's content.

func (*ROCFStatusReportInvocation) Humanize

func (s *ROCFStatusReportInvocation) Humanize() string

Humanize returns a human-readable summary.

type ROCFTransferBuffer

type ROCFTransferBuffer []ROCFTransferBufferEntry

ROCFTransferBuffer is the RocfTransferBuffer of annex A2.7.

Buffering matters more here than in RAF. An OCF is four octets, so one PDU per control field would spend far more on framing than on data.

func DecodeROCFTransferBuffer

func DecodeROCFTransferBuffer(data []byte) (ROCFTransferBuffer, error)

DecodeROCFTransferBuffer parses a transfer buffer's content.

func (ROCFTransferBuffer) Encode

func (b ROCFTransferBuffer) Encode() ([]byte, error)

Encode serializes the transfer buffer's content.

func (ROCFTransferBuffer) Humanize

func (b ROCFTransferBuffer) Humanize() string

Humanize returns a human-readable summary.

func (ROCFTransferBuffer) OCFs

OCFs returns just the control fields in the buffer.

type ROCFTransferBufferEntry

type ROCFTransferBufferEntry struct {
	OCF          *ROCFTransferDataInvocation
	Notification *SyncNotifyInvocation
}

ROCFTransferBufferEntry is one element of a RocfTransferBuffer.

OcfOrNotification ::= CHOICE
{ annotatedOcf     [0] RocfTransferDataInvocation
, syncNotification [1] RocfSyncNotifyInvocation
}

type ROCFTransferDataInvocation

type ROCFTransferDataInvocation struct {
	Credentials        *Credentials
	EarthReceiveTime   Time
	AntennaId          AntennaId
	DataLinkContinuity int32
	PrivateAnnotation  []byte
	// Data is the operational control field.
	Data []byte
}

ROCFTransferDataInvocation is the RocfTransferDataInvocation of the ROCF outgoing PDUs module.

Its Data is the operational control field itself (four octets, usually a CLCW that pkg/cop can decode) rather than a whole frame.

func DecodeROCFTransferDataInvocation

func DecodeROCFTransferDataInvocation(data []byte) (*ROCFTransferDataInvocation, error)

DecodeROCFTransferDataInvocation parses a TRANSFER-DATA invocation's content.

The layout matches RCF's exactly, so this shares its decoder and relabels the result.

func (*ROCFTransferDataInvocation) Encode

func (t *ROCFTransferDataInvocation) Encode() ([]byte, error)

Encode serializes the TRANSFER-DATA invocation's content.

func (*ROCFTransferDataInvocation) Humanize

func (t *ROCFTransferDataInvocation) Humanize() string

Humanize returns a human-readable summary.

type ROCFUser

type ROCFUser struct {
	*ServiceUser
}

ROCFUser is the user half of an ROCF service instance.

ROCF is the narrowest of the return services: four octets per frame, and only from the frames that carry a control field of the requested kind. A mission running FOP-1 on the ground uses it to close the loop, feeding each delivered field to pkg/cop's CLCW decoder.

func NewROCFUser

func NewROCFUser(config ServiceConfig) (*ROCFUser, error)

NewROCFUser prepares the user half of an ROCF instance.

func (ROCFUser) Association

func (c ROCFUser) Association() *Association

Association returns the association underneath.

func (ROCFUser) DeliveryMode

func (c ROCFUser) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (*ROCFUser) HandlePDU

func (u *ROCFUser) HandlePDU(data []byte, now time.Time) (*ROCFUserEvent, error)

HandlePDU decodes one PDU from the provider and advances the machine.

func (ROCFUser) HandlePeerAbort

func (c ROCFUser) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*ROCFUser) HandleStartReturn

func (u *ROCFUser) HandleStartReturn(r *ROCFStartReturn) error

HandleStartReturn takes the answer to START, moving to state 3 when positive.

func (ROCFUser) Kind

func (c ROCFUser) Kind() ServiceKind

Kind returns which service this is.

func (ROCFUser) NextPDU

func (c ROCFUser) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (ROCFUser) PeerAbort

func (c ROCFUser) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (ROCFUser) Pending

func (c ROCFUser) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*ROCFUser) Start

func (u *ROCFUser) Start(
	now time.Time, randomNumber int32, start, stop ConditionalTime,
	channel GVCID, control ControlWordType, mode UpdateMode,
) (InvokeId, error)

Start asks the provider to begin delivering control fields. State 2 only.

func (ROCFUser) State

func (c ROCFUser) State() ServiceState

State returns the service state.

type ROCFUserEvent

type ROCFUserEvent struct {
	Operation OperationType

	BindReturn                 *BindReturn
	UnbindReturn               *UnbindReturn
	StartReturn                *ROCFStartReturn
	StopReturn                 *Acknowledgement
	ScheduleStatusReportReturn *ScheduleStatusReportReturn
	GetParameterReturn         *GetParameterReturn
	TransferBuffer             ROCFTransferBuffer
	StatusReport               *ROCFStatusReportInvocation
	PeerAbort                  *PeerAbort
}

ROCFUserEvent is one decoded PDU arriving at the user.

type ReportRequestKind

type ReportRequestKind int

ReportRequestKind says what a SCHEDULE-STATUS-REPORT is asking for, from the ReportRequestType CHOICE of the common PDUs module.

const (
	// ReportImmediately asks for one report now.
	ReportImmediately ReportRequestKind = 0
	// ReportPeriodically asks for a report every so many seconds.
	ReportPeriodically ReportRequestKind = 1
	// ReportStop turns periodic reporting off.
	ReportStop ReportRequestKind = 2
)

func (ReportRequestKind) String

func (r ReportRequestKind) String() string

String names the request.

type RequestedFrameQuality

type RequestedFrameQuality int

RequestedFrameQuality says which frames a START asks for, from the parReqFrameQuality values of the RAF structures module.

const (
	// FrameQualityGoodOnly asks for frames that passed error control.
	FrameQualityGoodOnly RequestedFrameQuality = 0
	// FrameQualityErredOnly asks for frames that failed it.
	FrameQualityErredOnly RequestedFrameQuality = 1
	// FrameQualityAll asks for everything.
	FrameQualityAll RequestedFrameQuality = 2
)

func (RequestedFrameQuality) String

func (r RequestedFrameQuality) String() string

String names the requested quality.

type Role

type Role uint8

Role says which end of the association this is.

const (
	// RoleUser is the service user, the side that sends BIND. Usually a
	// mission control centre.
	RoleUser Role = iota
	// RoleProvider is the service provider, the side that answers. Usually a
	// ground station.
	RoleProvider
)

func (Role) String

func (r Role) String() string

String names the role.

type ScheduleStatusReportDiagnostic

type ScheduleStatusReportDiagnostic int

ScheduleStatusReportDiagnostic explains a refused SCHEDULE-STATUS-REPORT, from the specific alternative of DiagnosticScheduleStatusReport.

const (
	// ScheduleNotSupportedInThisDeliveryMode means the mode has no reports.
	ScheduleNotSupportedInThisDeliveryMode ScheduleStatusReportDiagnostic = 0
	// ScheduleAlreadyStopped answers a stop when nothing was running.
	ScheduleAlreadyStopped ScheduleStatusReportDiagnostic = 1
	// ScheduleInvalidReportingCycle means the cycle was outside 2 to 600.
	ScheduleInvalidReportingCycle ScheduleStatusReportDiagnostic = 2
)

func (ScheduleStatusReportDiagnostic) String

String names the diagnostic.

type ScheduleStatusReportInvocation

type ScheduleStatusReportInvocation struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// Kind says whether to report once, periodically, or to stop.
	Kind ReportRequestKind
	// ReportingCycle is the period in seconds, used only when Kind is
	// ReportPeriodically.
	ReportingCycle uint16
}

ScheduleStatusReportInvocation is the SleScheduleStatusReportInvocation of the common PDUs module. All four services use it unchanged.

func DecodeScheduleStatusReportInvocation

func DecodeScheduleStatusReportInvocation(data []byte) (*ScheduleStatusReportInvocation, error)

DecodeScheduleStatusReportInvocation parses the invocation's content.

func (*ScheduleStatusReportInvocation) Encode

func (s *ScheduleStatusReportInvocation) Encode() ([]byte, error)

Encode serializes the SCHEDULE-STATUS-REPORT invocation's content.

func (*ScheduleStatusReportInvocation) Humanize

func (s *ScheduleStatusReportInvocation) Humanize() string

Humanize returns a human-readable summary.

type ScheduleStatusReportReturn

type ScheduleStatusReportReturn struct {
	Credentials *Credentials
	InvokeId    InvokeId
	// Positive reports whether the provider accepted.
	Positive bool
	// CommonDiagnostic is set when a refusal used the common alternative.
	CommonDiagnostic Diagnostics
	// SpecificDiagnostic is set when it used the specific one.
	SpecificDiagnostic ScheduleStatusReportDiagnostic
	// UsedCommon says which alternative a refusal took.
	UsedCommon bool
}

ScheduleStatusReportReturn is the SleScheduleStatusReportReturn of the common PDUs module.

func DecodeScheduleStatusReportReturn

func DecodeScheduleStatusReportReturn(data []byte) (*ScheduleStatusReportReturn, error)

DecodeScheduleStatusReportReturn parses the return's content.

func (*ScheduleStatusReportReturn) Encode

func (s *ScheduleStatusReportReturn) Encode() ([]byte, error)

Encode serializes the SCHEDULE-STATUS-REPORT return's content.

func (*ScheduleStatusReportReturn) Humanize

func (s *ScheduleStatusReportReturn) Humanize() string

Humanize returns a human-readable summary.

type ServiceConfig

type ServiceConfig struct {
	// Association is the bound association this instance runs over. It must
	// already exist; this package does not create one for you, because a
	// caller normally wants to configure authentication and heartbeats first.
	Association *Association

	// Kind names the service, which decides the PDU tags.
	Kind ServiceKind

	// DeliveryMode is the mode the service agreement fixed. See delivery.go
	// for what the machine does with it and what it leaves to you.
	DeliveryMode DeliveryMode

	// Version is the service version to bind at.
	Version uint16

	// ResponderPort names the provider's port identifier, used by BIND.
	ResponderPort string

	// Instance identifies the service instance, used by BIND.
	Instance ServiceInstanceIdentifier
}

ServiceConfig configures one service instance.

type ServiceInstanceAttribute

type ServiceInstanceAttribute struct {
	// Identifier names the attribute. On the wire it is an OBJECT IDENTIFIER
	// from the SLE-SERVICE-INSTANCE-ID module; here it is the operator name (
	// "sagr", "spack", "rsl-fg", "fsl-fg", "raf", "rcf", "rocf", "cltu" or
	// "antenna") or a dotted OID string for an identifier this package does
	// not know by name.
	Identifier string
	// Value is the attribute value.
	Value string
	// Legacy reports that the identifier arrived as a VisibleString rather
	// than the OBJECT IDENTIFIER the module requires. Some older peers, and
	// earlier versions of this package, encoded it that way; the decoder
	// accepts the form and flags it here. This package always encodes OIDs.
	Legacy bool
}

ServiceInstanceAttribute is one name-value pair of a service instance identifier.

type ServiceInstanceIdentifier

type ServiceInstanceIdentifier []ServiceInstanceAttribute

ServiceInstanceIdentifier names a service instance: a sequence of attributes that together identify one configured service at the provider.

func (ServiceInstanceIdentifier) String

func (s ServiceInstanceIdentifier) String() string

String renders the identifier the way SLE operators write it, as name=value pairs.

type ServiceKind

type ServiceKind int

ServiceKind names which transfer service a PDU belongs to. The same tag number means different operations in different services, so decoding needs to know.

const (
	// ServiceRAF is Return All Frames, CCSDS 911.1-B-5.
	ServiceRAF ServiceKind = iota
	// ServiceRCF is Return Channel Frames, CCSDS 911.2-B-4.
	ServiceRCF
	// ServiceROCF is Return Operational Control Fields, CCSDS 911.5-B-4.
	ServiceROCF
	// ServiceFCLTU is Forward CLTU, CCSDS 912.1-B-5.
	ServiceFCLTU
)

func (ServiceKind) String

func (s ServiceKind) String() string

String names the service.

type ServiceParameter added in v0.4.0

type ServiceParameter struct {
	// Service is the transfer service whose parameter set this was read
	// against, because the same tag means different things in each.
	Service ServiceKind

	// Tag is the CHOICE alternative the provider chose.
	Tag uint32

	// Name is the parameterName the alternative carried. The schema
	// constrains it to match the alternative, and Decode checks that it
	// does: a provider that disagrees with itself is reporting something
	// this package should not paper over.
	Name ParameterName

	// Value is the parameter's value when the schema makes it a single
	// integer, which most are. Valid only when HasValue is set.
	Value    int64
	HasValue bool

	// Raw is the parameterValue element's content when the value is
	// structured. A set of GVCIDs, the online/offline CHOICE of a latency
	// limit. Decoding it further needs the service's own ASN.1, and this
	// package does not model those shapes rather than guess at them.
	Raw []byte
}

ServiceParameter is one configuration parameter from a GET-PARAMETER return.

func DecodeServiceParameter added in v0.4.0

func DecodeServiceParameter(content []byte, service ServiceKind) (*ServiceParameter, error)

DecodeServiceParameter reads the positive result of a GET-PARAMETER return against one service's parameter set.

content is the parameter CHOICE as GetParameterReturn carries it: the alternative's tag and content, which is where getparameter.go stops.

service is required and cannot be inferred. The same context tag names a different parameter in each service, so decoding a RAF PDU against the FCLTU set would report the wrong parameter with a plausible value.

func (*ServiceParameter) Humanize added in v0.4.0

func (p *ServiceParameter) Humanize() string

Humanize returns a human-readable summary.

type ServiceProvider

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

ServiceProvider is the provider half: the ground-station side.

It answers the operations a user drives (BIND, START, STOP, UNBIND) and lets the caller push data while active. One of these is one service instance on one association.

The rest of a real provider lives beside it rather than in it. Production and the transfer buffer are in production.go; serving several instances and routing an inbound BIND between them is Complex, in complex.go. What none of them holds is a service agreement: the provision periods, permitted parameter ranges and scheduling that service management hands down are configuration a mission supplies. See docs/content/conformance/sle.md for the row-by-row picture.

func NewServiceProvider

func NewServiceProvider(config ServiceConfig) (*ServiceProvider, error)

NewServiceProvider prepares the provider half of a service instance.

func (ServiceProvider) Association

func (c ServiceProvider) Association() *Association

Association returns the association underneath.

func (ServiceProvider) DeliveryMode

func (c ServiceProvider) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (*ServiceProvider) HandleBindInvocation

func (p *ServiceProvider) HandleBindInvocation(b *BindInvocation, now time.Time, randomNumber int32) error

HandleBindInvocation answers a BIND. State table row 5: accept and go to state 2, or refuse and stay at state 1.

func (*ServiceProvider) HandleGetParameterInvocation

func (p *ServiceProvider) HandleGetParameterInvocation(
	g *GetParameterInvocation, parameter []byte, now time.Time, randomNumber int32,
) error

HandleGetParameterInvocation answers a GET-PARAMETER. Valid in states 2 and 3, per clause 3.10.

parameter is the still-encoded alternative of the service's parameter CHOICE (one complete BER element) or nil, which answers negatively with 'unknown parameter'. This package does not model the per-service parameter CHOICEs; the caller that has a value to report encodes it.

func (ServiceProvider) HandlePeerAbort

func (c ServiceProvider) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*ServiceProvider) HandleScheduleStatusReportInvocation

func (p *ServiceProvider) HandleScheduleStatusReportInvocation(
	s *ScheduleStatusReportInvocation, accept bool,
	diagnostic ScheduleStatusReportDiagnostic, now time.Time, randomNumber int32,
) error

HandleScheduleStatusReportInvocation answers a report request.

func (*ServiceProvider) HandleStopInvocation

func (p *ServiceProvider) HandleStopInvocation(
	s *StopInvocation, accept bool, diagnostic Diagnostics, now time.Time, randomNumber int32,
) error

HandleStopInvocation answers a STOP, returning to state 2 when it accepts.

func (*ServiceProvider) HandleUnbindInvocation

func (p *ServiceProvider) HandleUnbindInvocation(u *UnbindInvocation, now time.Time, randomNumber int32) error

HandleUnbindInvocation answers an UNBIND, returning to state 1.

func (ServiceProvider) Kind

func (c ServiceProvider) Kind() ServiceKind

Kind returns which service this is.

func (ServiceProvider) NextPDU

func (c ServiceProvider) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (ServiceProvider) PeerAbort

func (c ServiceProvider) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (ServiceProvider) Pending

func (c ServiceProvider) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*ServiceProvider) SendStatusReport

func (p *ServiceProvider) SendStatusReport(
	report interface{ Encode() ([]byte, error) }, now time.Time,
) error

SendStatusReport queues an unconfirmed STATUS-REPORT. Valid in states 2 and 3: the channel has something to report as soon as the instance is bound.

func (ServiceProvider) State

func (c ServiceProvider) State() ServiceState

State returns the service state.

type ServiceState

type ServiceState int

ServiceState is the state of one service instance.

The numbers are the specs' own: state 1, 2 and 3. They start at 1 rather than 0 so that a state printed in a log matches the state named in the table you are reading it against.

const (
	// ServiceUnbound is state 1: no association, nothing allocated.
	ServiceUnbound ServiceState = 1
	// ServiceReady is state 2: bound, but not moving data.
	ServiceReady ServiceState = 2
	// ServiceActive is state 3: bound and transferring.
	ServiceActive ServiceState = 3
)

func (ServiceState) String

func (s ServiceState) String() string

String names the state the way the specs do.

type ServiceUser

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

ServiceUser is the user half of a service instance: the mission-control side, which binds, starts, receives or sends data, stops and unbinds.

It is embedded by RAFUser, RCFUser, ROCFUser and FCLTUUser, which add the operations that differ between services. Use one of those rather than this directly.

func NewServiceUser

func NewServiceUser(config ServiceConfig) (*ServiceUser, error)

NewServiceUser prepares the user half of a service instance.

func (ServiceUser) Association

func (c ServiceUser) Association() *Association

Association returns the association underneath.

func (*ServiceUser) Bind

func (u *ServiceUser) Bind(now time.Time, randomNumber int32) error

Bind opens the association and asks for the service instance. State 1 only, per CCSDS 911.1-B-5 clause 3.2.1.6.

func (ServiceUser) DeliveryMode

func (c ServiceUser) DeliveryMode() DeliveryMode

DeliveryMode returns the configured delivery mode.

func (*ServiceUser) GetParameter

func (u *ServiceUser) GetParameter(parameter int, now time.Time, randomNumber int32) (InvokeId, error)

GetParameter asks the provider for one configuration parameter, named by the service's ParameterName value. Valid in states 2 and 3, per clause 3.10 of each service specification.

func (*ServiceUser) HandleBindReturn

func (u *ServiceUser) HandleBindReturn(b *BindReturn, now time.Time) error

HandleBindReturn takes the provider's answer to BIND. A positive answer moves to state 2.

func (*ServiceUser) HandleGetParameterReturn

func (u *ServiceUser) HandleGetParameterReturn(r *GetParameterReturn) error

HandleGetParameterReturn takes the answer to GET-PARAMETER.

func (ServiceUser) HandlePeerAbort

func (c ServiceUser) HandlePeerAbort(p *PeerAbort, now time.Time)

HandlePeerAbort takes an inbound PEER-ABORT: the association is over.

func (*ServiceUser) HandleScheduleStatusReportReturn

func (u *ServiceUser) HandleScheduleStatusReportReturn(r *ScheduleStatusReportReturn) error

HandleScheduleStatusReportReturn takes the answer to a report request.

func (*ServiceUser) HandleStopReturn

func (u *ServiceUser) HandleStopReturn(a *Acknowledgement) error

HandleStopReturn takes the answer to STOP. A positive answer returns the instance to state 2; a negative one leaves it active, which is the point of state table row 10's ELSE branch.

func (*ServiceUser) HandleUnbindReturn

func (u *ServiceUser) HandleUnbindReturn(r *UnbindReturn, now time.Time) error

HandleUnbindReturn takes the provider's answer to UNBIND, ending the instance at state 1.

func (ServiceUser) Kind

func (c ServiceUser) Kind() ServiceKind

Kind returns which service this is.

func (ServiceUser) NextPDU

func (c ServiceUser) NextPDU() ([]byte, bool)

NextPDU takes the next PDU the caller should send, or reports false when there is nothing waiting.

func (*ServiceUser) Outstanding

func (u *ServiceUser) Outstanding() map[InvokeId]OperationType

Outstanding returns the invoke identifiers still awaiting a return, so a caller running the spec's return timers knows which to watch.

func (ServiceUser) PeerAbort

func (c ServiceUser) PeerAbort(diagnostic PeerAbortDiagnostic, now time.Time)

PeerAbort ends the association from this end.

func (ServiceUser) Pending

func (c ServiceUser) Pending() int

Pending reports how many PDUs are waiting to be sent.

func (*ServiceUser) ScheduleStatusReport

func (u *ServiceUser) ScheduleStatusReport(
	kind ReportRequestKind, cycle uint16, now time.Time, randomNumber int32,
) (InvokeId, error)

ScheduleStatusReport asks for status reports, once or periodically, or turns periodic reporting off. Valid in states 2 and 3.

func (ServiceUser) State

func (c ServiceUser) State() ServiceState

State returns the service state.

func (*ServiceUser) Stop

func (u *ServiceUser) Stop(now time.Time, randomNumber int32) (InvokeId, error)

Stop ends data transfer. State 3 only, per clause 3.5.1.3.

func (*ServiceUser) Unbind

func (u *ServiceUser) Unbind(now time.Time, randomNumber int32, reason UnbindReason) error

Unbind ends the association. State 2 only, per clause 3.3.1.5. A user must stop before it may unbind.

type SlduStatusNotification

type SlduStatusNotification int

SlduStatusNotification says whether the user wants an ASYNC-NOTIFY once the CLTU has been dealt with.

const (
	// ProduceNotification asks for the notification.
	ProduceNotification SlduStatusNotification = 0
	// DoNotProduceNotification declines it.
	DoNotProduceNotification SlduStatusNotification = 1
)

func (SlduStatusNotification) String

func (s SlduStatusNotification) String() string

String names the choice.

type StopInvocation

type StopInvocation struct {
	Credentials *Credentials
	InvokeId    InvokeId
}

StopInvocation is the SleStopInvocation of the common PDUs module: a confirmed operation ending data transfer.

func DecodeStopInvocation

func DecodeStopInvocation(data []byte) (*StopInvocation, error)

DecodeStopInvocation parses a STOP invocation's content.

func (*StopInvocation) Encode

func (s *StopInvocation) Encode() ([]byte, error)

Encode serializes the STOP invocation's content.

type SyncNotifyInvocation

type SyncNotifyInvocation struct {
	Credentials *Credentials
	Kind        NotificationKind
	// LockStatus is set when Kind is NotifyLossFrameSync.
	LockStatus *LockStatusReport
	// ProductionStatus is set when Kind is NotifyProductionStatusChange.
	ProductionStatus ProductionStatus
}

SyncNotifyInvocation is the sync notification a return service sends: the provider telling the user something happened to the channel.

RAF, RCF and ROCF each define this SEQUENCE in their own ASN.1 module ( RafSyncNotifyInvocation, RcfSyncNotifyInvocation, RocfSyncNotifyInvocation) and all three are the same two fields wrapping the same Notification CHOICE. One Go type covers all three.

func DecodeSyncNotifyInvocation

func DecodeSyncNotifyInvocation(data []byte) (*SyncNotifyInvocation, error)

DecodeSyncNotifyInvocation parses a SYNC-NOTIFY invocation's content.

func (*SyncNotifyInvocation) Encode

func (n *SyncNotifyInvocation) Encode() ([]byte, error)

Encode serializes the SYNC-NOTIFY invocation's content.

func (*SyncNotifyInvocation) Humanize

func (n *SyncNotifyInvocation) Humanize() string

Humanize returns a human-readable summary.

type Time

type Time struct {
	// Days since the 1958 epoch.
	Days uint16
	// Milliseconds of the day.
	Milliseconds uint32
	// Microseconds of the millisecond. Zero when unused.
	Microseconds uint16
}

Time is a CCSDS Day Segmented time as SLE encodes it.

func DecodeTime

func DecodeTime(data []byte) (Time, error)

DecodeTime parses an eight-octet T-field.

func DecodeTimeChoice

func DecodeTimeChoice(e *Element) (Time, error)

DecodeTimeChoice reads an SLE Time CHOICE.

Alternative [0] is the eight-octet form and [1] the ten-octet picosecond one. This package reads both but keeps only microsecond resolution: the extra precision has nowhere to go in a Go time.Time at these magnitudes.

func NewTime

func NewTime(t time.Time) (Time, error)

NewTime converts a Go time to the SLE representation.

func (Time) Encode

func (t Time) Encode() []byte

Encode serializes the eight-octet T-field.

func (Time) Humanize

func (t Time) Humanize() string

Humanize returns a human-readable summary.

func (Time) Time

func (t Time) Time() time.Time

Time converts back to a Go time.

type TransferBufferEntry

type TransferBufferEntry struct {
	Frame        *RAFTransferDataInvocation
	Notification *SyncNotifyInvocation
}

TransferBufferEntry is one element of a RafTransferBuffer: either a frame or a notification.

FrameOrNotification ::= CHOICE
{ annotatedFrame   [0] RafTransferDataInvocation
, syncNotification [1] RafSyncNotifyInvocation
}

type UnbindInvocation

type UnbindInvocation struct {
	Credentials *Credentials
	Reason      UnbindReason
}

UnbindInvocation is the SleUnbindInvocation of annex A2.2.

func DecodeUnbindInvocation

func DecodeUnbindInvocation(data []byte) (*UnbindInvocation, error)

DecodeUnbindInvocation parses an UNBIND invocation's content.

func (*UnbindInvocation) Encode

func (u *UnbindInvocation) Encode() ([]byte, error)

Encode serializes the UNBIND invocation's content.

func (*UnbindInvocation) Humanize

func (u *UnbindInvocation) Humanize() string

Humanize returns a human-readable summary.

type UnbindReason

type UnbindReason int

UnbindReason says why an association is ending, from the UnbindReason INTEGER of annex A2.2.

const (
	// UnbindEnd means the service provision period has ended.
	UnbindEnd UnbindReason = 0
	// UnbindSuspend means the association is being suspended and may resume.
	UnbindSuspend UnbindReason = 1
	// UnbindVersionNotSupported means the peer cannot speak this version.
	UnbindVersionNotSupported UnbindReason = 2
	// UnbindOther covers everything else.
	UnbindOther UnbindReason = 127
)

func (UnbindReason) String

func (u UnbindReason) String() string

String names the reason.

type UnbindReturn

type UnbindReturn struct {
	Credentials *Credentials
}

UnbindReturn is the SleUnbindReturn of annex A2.2. Its result CHOICE has only a positive alternative: an UNBIND cannot be refused.

func DecodeUnbindReturn

func DecodeUnbindReturn(data []byte) (*UnbindReturn, error)

DecodeUnbindReturn parses an UNBIND return's content.

func (*UnbindReturn) Encode

func (u *UnbindReturn) Encode() ([]byte, error)

Encode serializes the UNBIND return's content.

type UpdateMode

type UpdateMode int

UpdateMode says whether to deliver every control field or only changes, from the RequestedUpdateMode INTEGER of the ROCF structures module.

const (
	// UpdateContinuous delivers every operational control field.
	UpdateContinuous UpdateMode = 0
	// UpdateChangeBased delivers only fields differing from the last one sent.
	//
	// A CLCW usually repeats unchanged for many frames, so this cuts the
	// downlink cost of watching one dramatically.
	UpdateChangeBased UpdateMode = 1
)

func (UpdateMode) String

func (u UpdateMode) String() string

String names the update mode.

type UplinkStatus

type UplinkStatus int

UplinkStatus reports what the uplink carrier is doing, from the UplinkStatus INTEGER of the CLTU structures module.

const (
	UplinkStatusNotAvailable UplinkStatus = 0
	UplinkNoRfAvailable      UplinkStatus = 1
	UplinkNoBitLock          UplinkStatus = 2
	UplinkNominal            UplinkStatus = 3
)

func (UplinkStatus) String

func (u UplinkStatus) String() string

String names the uplink status.

Jump to

Keyboard shortcuts

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