SpaceWire (ECSS-E-ST-50-12C) and RMAP (ECSS-E-ST-50-52C)
0
fork

Configure Feed

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

irmin: WIP save before mli-first redesign

+126 -49
+1
dune-project
··· 20 20 (depends 21 21 (ocaml (>= 5.1)) 22 22 (fmt (>= 0.9)) 23 + (wire (>= 0.1)) 23 24 (alcotest :with-test) 24 25 (crowbar :with-test) 25 26 (odoc :with-doc)))
+1 -1
lib/dune
··· 1 1 (library 2 2 (name spacewire) 3 3 (public_name spacewire) 4 - (libraries fmt)) 4 + (libraries fmt wire))
+123 -48
lib/spacewire.ml
··· 254 254 255 255 let rmap_protocol_id = 0x01 256 256 257 + (* Wire codec for the RMAP instruction byte. 258 + Default bit_order is Msb_first, so fields are declared MSB to LSB. *) 259 + 260 + type rmap_instruction = { 261 + instr_reserved : int; 262 + instr_is_command : bool; 263 + instr_is_write : bool; 264 + instr_is_verify : bool; 265 + instr_is_ack : bool; 266 + instr_is_increment : bool; 267 + instr_reply_addr_len : int; 268 + } 269 + 270 + let instr_bits n = Wire.bits ~width:n Wire.U8 271 + let instr_bool = Wire.bit (instr_bits 1) 272 + 273 + let f_instr_reserved = 274 + Wire.Codec.( 275 + Wire.Field.v "reserved" (instr_bits 1) $ fun i -> i.instr_reserved) 276 + 277 + let f_instr_is_command = 278 + Wire.Codec.(Wire.Field.v "command" instr_bool $ fun i -> i.instr_is_command) 279 + 280 + let f_instr_is_write = 281 + Wire.Codec.(Wire.Field.v "write" instr_bool $ fun i -> i.instr_is_write) 282 + 283 + let f_instr_is_verify = 284 + Wire.Codec.(Wire.Field.v "verify" instr_bool $ fun i -> i.instr_is_verify) 285 + 286 + let f_instr_is_ack = 287 + Wire.Codec.(Wire.Field.v "ack" instr_bool $ fun i -> i.instr_is_ack) 288 + 289 + let f_instr_is_increment = 290 + Wire.Codec.( 291 + Wire.Field.v "increment" instr_bool $ fun i -> i.instr_is_increment) 292 + 293 + let f_instr_reply_addr_len = 294 + Wire.Codec.( 295 + Wire.Field.v "reply_addr_len" (instr_bits 2) $ fun i -> 296 + i.instr_reply_addr_len) 297 + 298 + let rmap_instruction_codec = 299 + Wire.Codec.v "RmapInstruction" 300 + (fun reserved is_command is_write is_verify is_ack is_increment 301 + reply_addr_len -> 302 + { 303 + instr_reserved = reserved; 304 + instr_is_command = is_command; 305 + instr_is_write = is_write; 306 + instr_is_verify = is_verify; 307 + instr_is_ack = is_ack; 308 + instr_is_increment = is_increment; 309 + instr_reply_addr_len = reply_addr_len; 310 + }) 311 + Wire.Codec. 312 + [ 313 + f_instr_reserved; 314 + f_instr_is_command; 315 + f_instr_is_write; 316 + f_instr_is_verify; 317 + f_instr_is_ack; 318 + f_instr_is_increment; 319 + f_instr_reply_addr_len; 320 + ] 321 + 322 + (* Helper: convert command code to write/verify bit pair *) 323 + let command_code_to_bits = function 324 + | Read -> (false, false) 325 + | Write -> (true, false) 326 + | Write_verify -> (true, true) 327 + | Read_modify_write -> (false, true) 328 + 329 + (* Helper: convert write/verify bit pair to command code *) 330 + let bits_to_command_code is_write is_verify = 331 + match (is_write, is_verify) with 332 + | false, false -> Some Read 333 + | true, false -> Some Write 334 + | true, true -> Some Write_verify 335 + | false, true -> Some Read_modify_write 336 + 257 337 let encode_instruction ~is_command cmd = 258 - let cmd_bit = if is_command then 0x40 else 0x00 in 259 - let write_bit = 260 - match cmd.cmd_code with 261 - | Read -> 0x00 262 - | Write -> 0x20 263 - | Write_verify -> 0x20 264 - | Read_modify_write -> 0x00 265 - in 266 - let verify_bit = 267 - match cmd.cmd_code with 268 - | Write_verify -> 0x10 269 - | Read_modify_write -> 0x10 270 - | _ -> 0x00 271 - in 272 - let ack_bit = match cmd.cmd_ack with Ack -> 0x08 | No_ack -> 0x00 in 273 - let inc_bit = 274 - match cmd.cmd_increment with Increment -> 0x04 | No_increment -> 0x00 275 - in 338 + let is_write, is_verify = command_code_to_bits cmd.cmd_code in 276 339 (* Reply address length in 4-byte units, capped at 3 (12 bytes max) *) 277 340 let reply_addr_len = List.length cmd.cmd_reply_address in 278 341 let reply_addr_words = min 3 ((reply_addr_len + 3) / 4) in 279 - cmd_bit lor write_bit lor verify_bit lor ack_bit lor inc_bit 280 - lor reply_addr_words 342 + let instr = 343 + { 344 + instr_reserved = 0; 345 + instr_is_command = is_command; 346 + instr_is_write = is_write; 347 + instr_is_verify = is_verify; 348 + instr_is_ack = (match cmd.cmd_ack with Ack -> true | No_ack -> false); 349 + instr_is_increment = 350 + (match cmd.cmd_increment with 351 + | Increment -> true 352 + | No_increment -> false); 353 + instr_reply_addr_len = reply_addr_words; 354 + } 355 + in 356 + let buf = Bytes.create 1 in 357 + Wire.Codec.encode rmap_instruction_codec instr buf 0; 358 + Bytes.get_uint8 buf 0 281 359 282 360 let decode_instruction byte = 283 - let is_command = byte land 0x40 <> 0 in 284 - let is_write = byte land 0x20 <> 0 in 285 - let is_verify = byte land 0x10 <> 0 in 286 - let is_ack = byte land 0x08 <> 0 in 287 - let is_inc = byte land 0x04 <> 0 in 288 - let reply_addr_words = byte land 0x03 in 289 - let code = 290 - match (is_write, is_verify) with 291 - | false, false -> Some Read 292 - | true, false -> Some Write 293 - | true, true -> Some Write_verify 294 - | false, true -> Some Read_modify_write 295 - in 296 - let ack = if is_ack then Ack else No_ack in 297 - let increment = if is_inc then Increment else No_increment in 298 - (is_command, code, ack, increment, reply_addr_words) 361 + let buf = Bytes.create 1 in 362 + Bytes.set_uint8 buf 0 byte; 363 + match Wire.Codec.decode rmap_instruction_codec buf 0 with 364 + | Error _ -> 365 + (* Should never happen for a valid byte *) 366 + (false, None, No_ack, No_increment, 0) 367 + | Ok instr -> 368 + let code = 369 + bits_to_command_code instr.instr_is_write instr.instr_is_verify 370 + in 371 + let ack = if instr.instr_is_ack then Ack else No_ack in 372 + let increment = 373 + if instr.instr_is_increment then Increment else No_increment 374 + in 375 + (instr.instr_is_command, code, ack, increment, instr.instr_reply_addr_len) 299 376 300 377 (* {1 RMAP Command Encoding} 301 378 ··· 461 538 in 462 539 let header_len = if has_data then 12 else 8 in 463 540 let buf = Bytes.make header_len '\x00' in 464 - (* Build a dummy command for instruction encoding *) 465 - let dummy_cmd = 541 + let is_write, is_verify = command_code_to_bits rpl.rpl_code in 542 + let instr = 466 543 { 467 - cmd_code = rpl.rpl_code; 468 - cmd_ack = Ack; 469 - cmd_increment = Increment; 470 - cmd_key = 0; 471 - cmd_reply_address = []; 472 - cmd_initiator = rpl.rpl_initiator; 473 - cmd_transaction_id = rpl.rpl_transaction_id; 474 - cmd_address = 0L; 475 - cmd_data_length = rpl.rpl_data_length; 544 + instr_reserved = 0; 545 + instr_is_command = false; 546 + instr_is_write = is_write; 547 + instr_is_verify = is_verify; 548 + instr_is_ack = true; 549 + instr_is_increment = true; 550 + instr_reply_addr_len = 0; 476 551 } 477 552 in 478 553 Bytes.set_uint8 buf 0 (rpl.rpl_initiator land 0xFF); 479 554 Bytes.set_uint8 buf 1 rmap_protocol_id; 480 - Bytes.set_uint8 buf 2 (encode_instruction ~is_command:false dummy_cmd); 555 + Wire.Codec.encode rmap_instruction_codec instr buf 2; 481 556 Bytes.set_uint8 buf 3 (rmap_status_to_int rpl.rpl_status); 482 557 Bytes.set_uint8 buf 4 (target_logical_address land 0xFF); 483 558 Bytes.set_uint8 buf 5 ((rpl.rpl_transaction_id lsr 8) land 0xFF);
+1
spacewire.opam
··· 12 12 "dune" {>= "3.21"} 13 13 "ocaml" {>= "5.1"} 14 14 "fmt" {>= "0.9"} 15 + "wire" {>= "0.1"} 15 16 "alcotest" {with-test} 16 17 "crowbar" {with-test} 17 18 "odoc" {with-doc}