|
1 | 1 | //! # Support of the CCSDS Unified Space Data Link Protocol (USLP) |
2 | 2 | #![deny(missing_docs)] |
| 3 | + |
3 | 4 | use arbitrary_int::{prelude::*, u4, u6}; |
4 | 5 |
|
5 | 6 | use crate::{crc::CRC_CCITT_FALSE, ByteConversionError}; |
@@ -577,6 +578,100 @@ impl<'data> TransferFrameCreator<'data> { |
577 | 578 | } |
578 | 579 | } |
579 | 580 |
|
| 581 | +/// USLP transfer frame creator which can reduce copy operations. |
| 582 | +/// |
| 583 | +/// This structure provides direct mutable access to the data zone. This avoids the need for an |
| 584 | +/// additional slice which would be required to hold the transfer data. Instead, user data can be |
| 585 | +/// copied into the frame field directly. The full length of the user data needs to be known |
| 586 | +/// beforehand. |
| 587 | +pub struct TransferFrameCreatorWithReservedData<'data> { |
| 588 | + buf: &'data mut [u8], |
| 589 | + len_written: usize, |
| 590 | + data_index: usize, |
| 591 | + data_size: usize, |
| 592 | + has_fecf: bool, |
| 593 | +} |
| 594 | + |
| 595 | +impl<'data> TransferFrameCreatorWithReservedData<'data> { |
| 596 | + /// Constructor. |
| 597 | + /// |
| 598 | + /// If the operational control field is present, the OCF flag in the primary header will |
| 599 | + /// be set accordingly. The frame length field of the [PrimaryHeader] is also updated according |
| 600 | + /// to the provided arguments. |
| 601 | + pub fn new( |
| 602 | + buf: &'data mut [u8], |
| 603 | + mut primary_header: PrimaryHeader, |
| 604 | + data_field_header: TransferFrameDataFieldHeader, |
| 605 | + data_size: usize, |
| 606 | + op_control_field: Option<u32>, |
| 607 | + has_fecf: bool, |
| 608 | + ) -> Result<TransferFrameCreatorWithReservedData<'data>, ByteConversionError> { |
| 609 | + let len_written = primary_header.len_header() |
| 610 | + + data_field_header.len_header() |
| 611 | + + data_size |
| 612 | + + if op_control_field.is_some() { 4 } else { 0 } |
| 613 | + + if has_fecf { 2 } else { 0 }; |
| 614 | + primary_header.set_frame_len(len_written); |
| 615 | + if op_control_field.is_some() { |
| 616 | + primary_header.ocf_flag = true; |
| 617 | + } |
| 618 | + if len_written > buf.len() { |
| 619 | + return Err(ByteConversionError::ToSliceTooSmall { |
| 620 | + found: buf.len(), |
| 621 | + expected: len_written, |
| 622 | + }); |
| 623 | + } |
| 624 | + let mut current_index = 0; |
| 625 | + current_index += primary_header.write_to_bytes(buf)?; |
| 626 | + |
| 627 | + current_index += |
| 628 | + data_field_header.write_to_bytes(&mut buf[primary_header.len_header()..])?; |
| 629 | + let data_index = current_index; |
| 630 | + //buf[current_index..current_index + self.data.len()].copy_from_slice(self.data); |
| 631 | + current_index += data_size; |
| 632 | + |
| 633 | + if let Some(ocf) = op_control_field { |
| 634 | + buf[current_index..current_index + 4].copy_from_slice(&ocf.to_be_bytes()); |
| 635 | + } |
| 636 | + Ok(Self { |
| 637 | + buf, |
| 638 | + data_size, |
| 639 | + data_index, |
| 640 | + len_written, |
| 641 | + has_fecf, |
| 642 | + }) |
| 643 | + } |
| 644 | + |
| 645 | + /// Length of the frame when written to bytes. |
| 646 | + pub fn len_written(&self) -> usize { |
| 647 | + self.len_written |
| 648 | + } |
| 649 | + |
| 650 | + /// Mutable accesss to user data buffer. |
| 651 | + pub fn data_mut(&mut self) -> &mut [u8] { |
| 652 | + &mut self.buf[self.data_index..self.data_index + self.data_size] |
| 653 | + } |
| 654 | + |
| 655 | + /// Shared accesss to user data buffer. |
| 656 | + pub fn data(&self) -> &[u8] { |
| 657 | + &self.buf[self.data_index..self.data_index + self.data_size] |
| 658 | + } |
| 659 | + |
| 660 | + /// Write [self] to the provided byte buffer. |
| 661 | + /// |
| 662 | + /// Calculates and writes the checksum if the `has_fecf` field is set. |
| 663 | + /// Returns the frame size. |
| 664 | + pub fn finish(self) -> usize { |
| 665 | + if self.has_fecf { |
| 666 | + let mut digest = CRC_CCITT_FALSE.digest(); |
| 667 | + digest.update(&self.buf[0..self.len_written - 2]); |
| 668 | + let crc = digest.finalize(); |
| 669 | + self.buf[self.len_written - 2..self.len_written].copy_from_slice(&crc.to_be_bytes()); |
| 670 | + } |
| 671 | + self.len_written |
| 672 | + } |
| 673 | +} |
| 674 | + |
580 | 675 | /// Simple USLP transfer frame reader. |
581 | 676 | /// |
582 | 677 | /// Currently, only insert zone lengths of 0 are supported. |
@@ -1199,6 +1294,38 @@ mod tests { |
1199 | 1294 | assert_eq!(reader.len_frame(), 14); |
1200 | 1295 | } |
1201 | 1296 |
|
| 1297 | + #[test] |
| 1298 | + fn test_frame_creator_no_fecf() { |
| 1299 | + let mut primary_header = PrimaryHeader::new( |
| 1300 | + 0x1234, |
| 1301 | + SourceOrDestField::Source, |
| 1302 | + u6::new(0b101010), |
| 1303 | + u4::new(0b0101), |
| 1304 | + 0, |
| 1305 | + ) |
| 1306 | + .unwrap(); |
| 1307 | + let data_field_header = TransferFrameDataFieldHeader { |
| 1308 | + construction_rule: ConstructionRule::NoSegmentation, |
| 1309 | + uslp_protocol_id: UslpProtocolId::UserDefinedOctetStream, |
| 1310 | + fhp_or_lvo: None, |
| 1311 | + }; |
| 1312 | + let data = [1, 2, 3, 4]; |
| 1313 | + let frame_creator = |
| 1314 | + TransferFrameCreator::new(primary_header, data_field_header, &data, None, false); |
| 1315 | + let mut buf: [u8; 64] = [0; 64]; |
| 1316 | + assert_eq!(frame_creator.len_written(), 12); |
| 1317 | + let written = frame_creator.write_to_bytes(&mut buf).unwrap(); |
| 1318 | + assert_eq!(written, 12); |
| 1319 | + assert_eq!(written, frame_creator.len_written()); |
| 1320 | + let reader = TransferFrameReader::from_bytes(&buf, false).unwrap(); |
| 1321 | + primary_header.set_frame_len(written); |
| 1322 | + assert_eq!(reader.primary_header(), &primary_header); |
| 1323 | + assert_eq!(reader.data_field_header(), &data_field_header); |
| 1324 | + assert_eq!(reader.data(), &data); |
| 1325 | + assert!(reader.operational_control_field().is_none()); |
| 1326 | + assert_eq!(reader.len_frame(), 12); |
| 1327 | + } |
| 1328 | + |
1202 | 1329 | #[test] |
1203 | 1330 | fn test_frame_creator_using_vec() { |
1204 | 1331 | // Relying on the reader implementation for now. |
@@ -1263,4 +1390,119 @@ mod tests { |
1263 | 1390 | assert_eq!(reader.operational_control_field().unwrap(), 4); |
1264 | 1391 | assert_eq!(reader.len_frame(), 18); |
1265 | 1392 | } |
| 1393 | + |
| 1394 | + #[test] |
| 1395 | + fn test_creator_with_reserved_data() { |
| 1396 | + let mut primary_header = PrimaryHeader::new( |
| 1397 | + 0x1234, |
| 1398 | + SourceOrDestField::Source, |
| 1399 | + u6::new(0b101010), |
| 1400 | + u4::new(0b0101), |
| 1401 | + 0, |
| 1402 | + ) |
| 1403 | + .unwrap(); |
| 1404 | + let data_field_header = TransferFrameDataFieldHeader::new( |
| 1405 | + ConstructionRule::NoSegmentation, |
| 1406 | + UslpProtocolId::UserDefinedOctetStream, |
| 1407 | + None, |
| 1408 | + ) |
| 1409 | + .unwrap(); |
| 1410 | + let mut buf: [u8; 32] = [0; 32]; |
| 1411 | + let mut frame_creator = TransferFrameCreatorWithReservedData::new( |
| 1412 | + &mut buf, |
| 1413 | + primary_header, |
| 1414 | + data_field_header, |
| 1415 | + 4, |
| 1416 | + None, |
| 1417 | + true, |
| 1418 | + ) |
| 1419 | + .unwrap(); |
| 1420 | + assert_eq!(frame_creator.data().len(), 4); |
| 1421 | + frame_creator.data_mut().copy_from_slice(&[1, 2, 3, 4]); |
| 1422 | + let frame_size = frame_creator.finish(); |
| 1423 | + let reader = TransferFrameReader::from_bytes(&buf[0..frame_size], true).unwrap(); |
| 1424 | + primary_header.set_frame_len(frame_size); |
| 1425 | + assert_eq!(reader.primary_header(), &primary_header); |
| 1426 | + assert_eq!(reader.data_field_header(), &data_field_header); |
| 1427 | + assert_eq!(reader.data(), &[1, 2, 3, 4]); |
| 1428 | + assert!(reader.operational_control_field().is_none()); |
| 1429 | + assert_eq!(reader.len_frame(), 14); |
| 1430 | + } |
| 1431 | + |
| 1432 | + #[test] |
| 1433 | + fn test_creator_with_reserved_data_and_ocf_field() { |
| 1434 | + let mut primary_header = PrimaryHeader::new( |
| 1435 | + 0x1234, |
| 1436 | + SourceOrDestField::Source, |
| 1437 | + u6::new(0b101010), |
| 1438 | + u4::new(0b0101), |
| 1439 | + 0, |
| 1440 | + ) |
| 1441 | + .unwrap(); |
| 1442 | + let data_field_header = TransferFrameDataFieldHeader::new( |
| 1443 | + ConstructionRule::NoSegmentation, |
| 1444 | + UslpProtocolId::UserDefinedOctetStream, |
| 1445 | + None, |
| 1446 | + ) |
| 1447 | + .unwrap(); |
| 1448 | + let mut buf: [u8; 32] = [0; 32]; |
| 1449 | + let mut frame_creator = TransferFrameCreatorWithReservedData::new( |
| 1450 | + &mut buf, |
| 1451 | + primary_header, |
| 1452 | + data_field_header, |
| 1453 | + 4, |
| 1454 | + Some(4), |
| 1455 | + true, |
| 1456 | + ) |
| 1457 | + .unwrap(); |
| 1458 | + assert_eq!(frame_creator.data().len(), 4); |
| 1459 | + frame_creator.data_mut().copy_from_slice(&[1, 2, 3, 4]); |
| 1460 | + let frame_size = frame_creator.finish(); |
| 1461 | + let reader = TransferFrameReader::from_bytes(&buf[0..frame_size], true).unwrap(); |
| 1462 | + primary_header.set_frame_len(frame_size); |
| 1463 | + primary_header.ocf_flag = true; |
| 1464 | + assert_eq!(reader.primary_header(), &primary_header); |
| 1465 | + assert_eq!(reader.data_field_header(), &data_field_header); |
| 1466 | + assert_eq!(reader.data(), &[1, 2, 3, 4]); |
| 1467 | + assert_eq!(reader.operational_control_field().unwrap(), 4); |
| 1468 | + assert_eq!(reader.len_frame(), 18); |
| 1469 | + } |
| 1470 | + |
| 1471 | + #[test] |
| 1472 | + fn test_creator_no_fecf() { |
| 1473 | + let mut primary_header = PrimaryHeader::new( |
| 1474 | + 0x1234, |
| 1475 | + SourceOrDestField::Source, |
| 1476 | + u6::new(0b101010), |
| 1477 | + u4::new(0b0101), |
| 1478 | + 0, |
| 1479 | + ) |
| 1480 | + .unwrap(); |
| 1481 | + let data_field_header = TransferFrameDataFieldHeader::new( |
| 1482 | + ConstructionRule::NoSegmentation, |
| 1483 | + UslpProtocolId::UserDefinedOctetStream, |
| 1484 | + None, |
| 1485 | + ) |
| 1486 | + .unwrap(); |
| 1487 | + let mut buf: [u8; 32] = [0; 32]; |
| 1488 | + let mut frame_creator = TransferFrameCreatorWithReservedData::new( |
| 1489 | + &mut buf, |
| 1490 | + primary_header, |
| 1491 | + data_field_header, |
| 1492 | + 4, |
| 1493 | + None, |
| 1494 | + false, |
| 1495 | + ) |
| 1496 | + .unwrap(); |
| 1497 | + assert_eq!(frame_creator.data().len(), 4); |
| 1498 | + frame_creator.data_mut().copy_from_slice(&[1, 2, 3, 4]); |
| 1499 | + let frame_size = frame_creator.finish(); |
| 1500 | + let reader = TransferFrameReader::from_bytes(&buf[0..frame_size], false).unwrap(); |
| 1501 | + primary_header.set_frame_len(frame_size); |
| 1502 | + assert_eq!(reader.primary_header(), &primary_header); |
| 1503 | + assert_eq!(reader.data_field_header(), &data_field_header); |
| 1504 | + assert_eq!(reader.data(), &[1, 2, 3, 4]); |
| 1505 | + assert!(reader.operational_control_field().is_none()); |
| 1506 | + assert_eq!(reader.len_frame(), 12); |
| 1507 | + } |
1266 | 1508 | } |
0 commit comments