CCSDS File Delivery Protocol (CCSDS 727.0-B-5) for space file transfer
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

ocaml-linkedin: apply dune fmt

Pure formatting changes from `dune fmt`: doc comment placement moves
from above the binding to below it for `type`s, multi-line `match`
expressions collapse onto one line where they fit, and infix operator
applications pick up spaces (`Soup.($?)` -> `Soup.( $? )`). No
semantic changes.

+123 -68
+108 -66
README.md
··· 11 11 - **Class 1**: Unacknowledged (unreliable) transfers 12 12 - **Class 2**: Acknowledged (reliable) transfers with NAK-based retransmission 13 13 14 + ## Packages 15 + 16 + - **cfdp** -- Core protocol: PDU types, codecs, state machines 17 + - **cfdp-eio** -- TCP transport and file I/O using Eio 18 + 19 + ## Installation 20 + 21 + Install with opam: 22 + 23 + ```sh 24 + $ opam install cfdp cfdp-eio 25 + ``` 26 + 27 + If opam cannot find the packages, they may not yet be released in the public 28 + `opam-repository`. Add the overlay repository, then install them: 29 + 30 + ```sh 31 + $ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git 32 + $ opam update 33 + $ opam install cfdp cfdp-eio 34 + ``` 35 + 36 + ## Usage 37 + 38 + ### Send a file 39 + 40 + ```ocaml 41 + let () = 42 + Eio_main.run @@ fun env -> 43 + Eio.Switch.run @@ fun sw -> 44 + let conn = 45 + Cfdp_eio.connect ~sw ~net:env#net ~host:"flatsat-1" ~port:1734 () 46 + in 47 + match 48 + Cfdp_eio.Sender.send_file conn 49 + ~src:(Fpath.v "firmware.elf") 50 + ~dst:"firmware.elf" 51 + () 52 + with 53 + | Ok tid -> Format.printf "Done: %a@." Cfdp.pp_transaction_id tid 54 + | Error msg -> Format.eprintf "Error: %s@." msg 55 + ``` 56 + 57 + ### Receive a file 58 + 59 + ```ocaml 60 + let () = 61 + Eio_main.run @@ fun env -> 62 + Eio.Switch.run @@ fun sw -> 63 + let conn = 64 + Cfdp_eio.connect ~sw ~net:env#net ~host:"flatsat-1" ~port:1734 () 65 + in 66 + match 67 + Cfdp_eio.Receiver.recv_file conn ~dest_dir:(Fpath.v "./incoming") () 68 + with 69 + | Ok (path, tid) -> 70 + Format.printf "Received %a (txn %a)@." 71 + Fpath.pp path Cfdp.pp_transaction_id tid 72 + | Error msg -> Format.eprintf "Error: %s@." msg 73 + ``` 74 + 75 + Both calls accept an optional `~on_progress` callback receiving `{bytes_sent; 76 + bytes_total; segments_sent; segments_total}`. 77 + 14 78 ## Features 15 79 16 80 - Full PDU header encoding/decoding with variable-length entity IDs (1-8 bytes) ··· 26 90 - Timer management for inactivity, NAK, EOF, Finished, and Keep Alive 27 91 - Wire codecs for Finished, ACK, and Prompt directives 28 92 29 - ## Packages 93 + ## Low-level API 94 + 95 + ### State machine (Class 1 Sender) 30 96 31 - - **cfdp** -- Core protocol: PDU types, codecs, state machines 32 - - **cfdp-eio** -- TCP transport and file I/O using Eio 97 + For custom transports or in-process simulation, drive the state machines 98 + directly: 33 99 34 - ## Installation 100 + ```ocaml 101 + let sender = Cfdp.Sender1.initial (Cfdp.Entity_id.of_int_exn 1) 102 + let req = 103 + Cfdp.put_request 104 + ~dest_entity:(Cfdp.Entity_id.of_int_exn 2) 105 + ~source_filename:"firmware.elf" 106 + ~dest_filename:"firmware.elf" 107 + () 35 108 36 - ``` 37 - opam install cfdp cfdp-eio 109 + let file_size = 4096L 110 + let read_data _offset = Bytes.create 1024 111 + let sender, actions = 112 + Cfdp.Sender1.step sender 113 + (Cfdp.Sender1.Ev_put_request (req, file_size, read_data)) 38 114 ``` 39 115 40 - ## Usage 116 + Feed events in, get actions out (`Act_send_metadata`, `Act_send_file_data`, 117 + ...). 41 118 42 - ### Encoding PDUs 119 + ### PDU encode / decode 43 120 44 121 ```ocaml 45 122 open Cfdp 46 123 47 - (* Create entity IDs (returns t option) *) 48 124 let source = Entity_id.of_int_exn 1 49 125 let dest = Entity_id.of_int_exn 2 50 - 51 - (* Use default PDU config: 2-byte entity IDs, 4-byte sequence numbers *) 52 126 let config = default_config 127 + let meta = 128 + metadata 129 + ~file_size:1024L 130 + ~source_filename:"data.bin" 131 + ~dest_filename:"data.bin" () 53 132 54 - (* Build a metadata PDU *) 55 - let meta = metadata ~file_size:1024L 56 - ~source_filename:"data.bin" ~dest_filename:"data.bin" () 133 + let hdr : header = 134 + { version = 1; 135 + pdu_type = File_directive; 136 + direction = Toward_receiver; 137 + transmission_mode = Unacknowledged; 138 + crc_present = false; 139 + large_file = false; 140 + segment_ctrl = false; 141 + segment_metadata = false; 142 + source_entity = source; 143 + transaction_seq = 1L; 144 + dest_entity = dest; 145 + data_len = 0; 146 + } 57 147 58 - (* Encode the metadata as a directive PDU *) 59 - let hdr : header = { 60 - version = 1; pdu_type = File_directive; 61 - direction = Toward_receiver; transmission_mode = Unacknowledged; 62 - crc_present = false; large_file = false; 63 - segment_ctrl = false; segment_metadata = false; 64 - source_entity = source; transaction_seq = 1L; 65 - dest_entity = dest; data_len = 0; 66 - } 67 148 let bytes = encode config (Pdu_directive (hdr, Metadata meta)) 68 - ``` 69 149 70 - ### Decoding 71 - 72 - ```ocaml 73 - match Cfdp.decode bytes with 74 - | Ok (pdu, _consumed) -> Format.printf "%a@." Cfdp.pp_pdu pdu 75 - | Error e -> Format.printf "Error: %a@." Cfdp.pp_error e 76 - ``` 77 - 78 - ### State Machine (Class 1 Sender) 79 - 80 - ```ocaml 81 - let sender = Sender1.initial (Entity_id.of_int_exn 1) in 82 - 83 - let req = put_request 84 - ~dest_entity:(Entity_id.of_int_exn 2) 85 - ~source_filename:"firmware.elf" 86 - ~dest_filename:"firmware.elf" () 87 - in 88 - 89 - let file_size = 4096L in 90 - let read_data _offset = Bytes.create 1024 in 91 - let sender, actions = 92 - Sender1.step sender (Ev_put_request (req, file_size, read_data)) 93 - in 94 - (* Process actions: Act_send_metadata, Act_send_file_data, ... *) 95 - ignore (sender, actions) 96 - ``` 97 - 98 - ### File Transfer with Eio 99 - 100 - ```ocaml 101 - Eio_main.run @@ fun env -> 102 - Eio.Switch.run @@ fun sw -> 103 - let conn = 104 - Cfdp_eio.connect ~sw ~net:env#net ~host:"flatsat-1" ~port:1734 () 105 - in 106 - match Cfdp_eio.Sender.send_file conn 107 - ~src:(Fpath.v "firmware.elf") ~dst:"firmware.elf" () with 108 - | Ok tid -> Format.printf "Done: %a@." Cfdp.pp_transaction_id tid 109 - | Error msg -> Format.eprintf "Error: %s@." msg 150 + let () = 151 + match decode bytes with 152 + | Ok (pdu, _consumed) -> Format.printf "%a@." pp_pdu pdu 153 + | Error e -> Format.printf "Error: %a@." pp_error e 110 154 ``` 111 155 112 156 ## State Machines ··· 117 161 | `Sender2` | 2 (acknowledged) | Sender with NAK retransmission | 118 162 | `Receiver1` | 1 (unacknowledged) | Receiver | 119 163 | `Receiver2` | 2 (acknowledged) | Receiver with NAK generation | 120 - 121 - Each state machine is event-driven: feed events in, get actions out. 122 164 123 165 Timer types: `Timer_nak`, `Timer_eof`, `Timer_finished`, `Timer_inactivity`, 124 166 `Timer_keep_alive`.
+1
cfdp-eio.opam
··· 16 16 "eio" {>= "1.0"} 17 17 "fpath" {>= "0.7"} 18 18 "fmt" {>= "0.9"} 19 + "mdx" {with-test} 19 20 "logs" {>= "0.7"} 20 21 "odoc" {with-doc} 21 22 ]
+2
cfdp.opam
··· 17 17 "fmt" {>= "0.9"} 18 18 "wire" 19 19 "alcotest" {with-test & >= "1.7"} 20 + "mdx" {with-test} 20 21 "alcobar" {with-test} 22 + "eio_main" {with-test} 21 23 "odoc" {with-doc} 22 24 ] 23 25 build: [
+4
dune
··· 1 1 (env 2 2 (dev 3 3 (flags :standard %{dune-warnings}))) 4 + 5 + (mdx 6 + (files README.md) 7 + (libraries cfdp cfdp-eio eio_main eio eio.unix fmt fpath))
+8 -2
dune-project
··· 1 1 (lang dune 3.21) 2 + (using mdx 0.4) 2 3 3 4 (name cfdp) 4 5 ··· 26 27 (fmt (>= 0.9)) 27 28 wire 28 29 (alcotest (and :with-test (>= 1.7))) 29 - (alcobar :with-test))) 30 + (mdx :with-test) 31 + (alcobar :with-test) 32 + (eio_main :with-test)) 33 + ) 30 34 31 35 (package 32 36 (name cfdp-eio) ··· 40 44 (eio (>= 1.0)) 41 45 (fpath (>= 0.7)) 42 46 (fmt (>= 0.9)) 43 - (logs (>= 0.7)))) 47 + (mdx :with-test) 48 + (logs (>= 0.7))) 49 + )