- OCaml 94%
- Java 6%
- Shell <1%
cop1 #
The Communications Operation Procedure-1 (COP-1) of CCSDS 232.1-B-2, for OCaml.
A telecommand uplink loses frames, and a spacecraft must execute commands
once and in order. COP-1 is the CCSDS answer: a go-back-N retransmission
protocol over the TC Space Data Link Protocol, with a sender on the ground
(FOP-1) and a receiver on the spacecraft (FARM-1). The receiver reports what
it has accepted in the Command Link Control Word (CLCW) that the spacecraft
sends down with its telemetry. This package implements both state machines of
CCSDS 232.1-B-2 without I/O, following the event numbering of its
state tables, and cop1-eio runs them with an Eio clock for the
retransmission timer.
Packages #
cop1: the FOP-1 and FARM-1 state machines, without I/O.cop1-eio: services that run them with an Eio clock and build the frames.
Install #
$ opam install cop1 cop1-eio
If opam cannot find the packages, add the overlay repository first:
$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install cop1 cop1-eio
Usage #
FOP-1, the ground side #
Frames come in three types. A Type-AD frame is sequence-controlled: it carries a sequence number N(S), the receiver accepts it only in order, and FOP-1 retransmits it until a CLCW confirms it; this is the AD service (A for acceptance, D for data). A Type-BD frame bypasses that check and is accepted whenever the receiver has room, for an emergency such as commanding a spacecraft whose FARM-1 is in lockout. A Type-BC frame carries one of the two control commands, Unlock and Set V(R).
A new FOP-1 machine is in state Initial. Each event (a directive, a frame
accepted or rejected by the lower layer, a CLCW, a timer expiry) returns the
new state and the actions the caller must take:
let fop = Cop1.Fop1.v ()
let fop', actions =
Cop1.Fop1.incoming fop
(Cop1.Fop1.Directive Cop1.Fop1.Initiate_ad_without_clcw)
(* Initiating AD service moves Initial -> Active, and accepts and confirms
the directive (CCSDS 232.1-B-2 table 5-1, E23). *)
let () = assert (Cop1.Fop1.equal_state (Cop1.Fop1.state fop') Cop1.Fop1.Active)
let () = assert (actions = [ Cop1.Fop1.Accept; Cop1.Fop1.Confirm ])
Cop1.Fop1.transfer_ad and transfer_bd return the Higher Procedures
answer alongside the state and actions. Cop1.Recovery selects recovery
directives from that same state and the last CLCW. These operations are pure;
the Eio service installs their state and performs their actions.
FARM-1, the spacecraft side #
FARM-1 accepts or rejects each received transfer frame, updates its expected
sequence number V(R) and its flags, and produces the CLCW from which the
ground advances its window:
let farm = Cop1.Farm1.v ()
let farm', _actions =
Cop1.Farm1.incoming farm (Cop1.Farm1.Frame (Cop1.Farm1.Valid_ad 0))
let clcw = Cop1.Farm1.to_clcw farm' ~vcid:0
(* The in-sequence frame is accepted: V(R) advances to 1 and the CLCW
reports the next expected sequence number. *)
let () = assert (Cop1.Farm1.vr farm' = 1)
let () = assert (clcw.Cop1.Clcw.report_value = 1)
FARM-1 splits the 256 sequence numbers around V(R) into a positive window of W/2 numbers from V(R), a negative window of W/2 numbers below it, and a lockout area of 256 − W numbers. A Type-AD frame numbered V(R) is accepted. A frame ahead of V(R) but inside the positive window means that a frame was lost: FARM-1 discards it and sets the retransmit flag, which asks FOP-1 to go back to the lost frame. A frame in the negative window is a repeat and is discarded quietly. Only a frame in the lockout area puts FARM-1 in lockout, where it refuses every Type-AD frame until an Unlock arrives. With V(R) = 0, frame 5 falls in the positive window:
let farm = Cop1.Farm1.v ()
let farm', _ =
Cop1.Farm1.incoming farm (Cop1.Farm1.Frame (Cop1.Farm1.Valid_ad 5))
(* Frame 5 is ahead of V(R) = 0 but inside the window, so it is
discarded and sets the retransmit flag in the next CLCW. *)
let () = assert (Cop1.Farm1.retransmit_flag farm')
Parameters #
Cop1.Fop1.v takes the sliding window width fop_width, the timer value
t1_initial, the transmission_limit and the timeout_type, and
Cop1.Farm1.v takes farm_width (126 by default), so that a caller can use
the values agreed for a virtual channel. The standard requires W to be even,
from 2 to 254, when Type-AD frames may be retransmitted, because the window
splits into two equal halves (CCSDS 232.1-B-2, sections 6.1.8.2 and
6.1.8.3.1); the default takes 63 numbers on each side. Cop1.Farm1.control
declares W as the limit FARM_Sliding_Window_Width and checks its graph at
the widths 2, 10, 126 and 254.
License #
ISC. See LICENSE.md.