Compare commits
1 Commits
add-uslp-f
...
minor-ci-t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7d004b299 |
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -2,7 +2,7 @@ name: ci
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
check:
|
||||
build:
|
||||
name: Check build
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo check --release
|
||||
- run: cargo build
|
||||
|
||||
test:
|
||||
name: Run Tests
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@1.83
|
||||
- run: cargo check --release
|
||||
- run: cargo check
|
||||
|
||||
cross-check:
|
||||
name: Check Cross-Compilation
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: "armv7-unknown-linux-gnueabihf, thumbv7em-none-eabihf, thumbv6m-none-eabi"
|
||||
- run: cargo check --release --target=${{matrix.target}} --no-default-features
|
||||
- run: cargo check --target=${{matrix.target}} --no-default-features
|
||||
|
||||
fmt:
|
||||
name: Check formatting
|
||||
|
||||
@@ -17,7 +17,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
`CcsdsPacketCreatorWithReservedData::packet_data`, including mutable variants as well.
|
||||
- `SequenceCounter::MAX_BIT_WIDTH` is now a regular trait method `SequenceCounter::max_bit_width`
|
||||
to allow dyn compatibility and easier usage in trait objects.
|
||||
- Improved type level support in USLP module by using VC ID type `u6` and MAP ID type `u4`.
|
||||
|
||||
## Added
|
||||
|
||||
|
||||
365
src/uslp/mod.rs
365
src/uslp/mod.rs
@@ -1,7 +1,5 @@
|
||||
//! # Support of the CCSDS Unified Space Data Link Protocol (USLP)
|
||||
#![warn(missing_docs)]
|
||||
use arbitrary_int::{prelude::*, u4, u6};
|
||||
|
||||
use crate::{crc::CRC_CCITT_FALSE, ByteConversionError};
|
||||
|
||||
/// Only this version is supported by the library
|
||||
@@ -66,6 +64,12 @@ pub enum UslpError {
|
||||
/// Invalid version number.
|
||||
#[error("invalid version number: {0}")]
|
||||
InvalidVersionNumber(u8),
|
||||
/// Invalid virtual channel ID.
|
||||
#[error("invalid virtual channel ID: {0}")]
|
||||
InvalidVcId(u8),
|
||||
/// Invalid MAP ID.
|
||||
#[error("invalid MAP ID: {0}")]
|
||||
InvalidMapId(u8),
|
||||
/// Checksum failure.
|
||||
#[error("checksum failure")]
|
||||
ChecksumFailure(u16),
|
||||
@@ -78,7 +82,7 @@ pub enum UslpError {
|
||||
#[error("invalid value for length of the field")]
|
||||
pub struct InvalidValueForLenError {
|
||||
value: u64,
|
||||
len: u3,
|
||||
len: u8,
|
||||
}
|
||||
|
||||
/// Primary header of a USLP transfer frame.
|
||||
@@ -91,9 +95,9 @@ pub struct PrimaryHeader {
|
||||
/// Source or destination identifier.
|
||||
pub source_or_dest_field: SourceOrDestField,
|
||||
/// Virtual channel ID.
|
||||
pub vc_id: u6,
|
||||
pub vc_id: u8,
|
||||
/// MAP ID.
|
||||
pub map_id: u4,
|
||||
pub map_id: u8,
|
||||
frame_len_field: u16,
|
||||
/// Bypass sequence control flag.
|
||||
pub sequence_control_flag: BypassSequenceControlFlag,
|
||||
@@ -101,7 +105,7 @@ pub struct PrimaryHeader {
|
||||
pub protocol_control_command_flag: ProtocolControlCommandFlag,
|
||||
/// Operational control field flag.
|
||||
pub ocf_flag: bool,
|
||||
vc_frame_count_len: u3,
|
||||
vc_frame_count_len: u8,
|
||||
vc_frame_count: u64,
|
||||
}
|
||||
|
||||
@@ -110,10 +114,16 @@ impl PrimaryHeader {
|
||||
pub fn new(
|
||||
spacecraft_id: u16,
|
||||
source_or_dest_field: SourceOrDestField,
|
||||
vc_id: u6,
|
||||
map_id: u4,
|
||||
vc_id: u8,
|
||||
map_id: u8,
|
||||
frame_len: u16,
|
||||
) -> Result<Self, UslpError> {
|
||||
if vc_id > 0b111111 {
|
||||
return Err(UslpError::InvalidVcId(vc_id));
|
||||
}
|
||||
if map_id > 0b1111 {
|
||||
return Err(UslpError::InvalidMapId(map_id));
|
||||
}
|
||||
Ok(Self {
|
||||
spacecraft_id,
|
||||
source_or_dest_field,
|
||||
@@ -123,7 +133,7 @@ impl PrimaryHeader {
|
||||
sequence_control_flag: BypassSequenceControlFlag::SequenceControlledQoS,
|
||||
protocol_control_command_flag: ProtocolControlCommandFlag::TfdfContainsUserData,
|
||||
ocf_flag: false,
|
||||
vc_frame_count_len: u3::ZERO,
|
||||
vc_frame_count_len: 0,
|
||||
vc_frame_count: 0,
|
||||
})
|
||||
}
|
||||
@@ -131,10 +141,10 @@ impl PrimaryHeader {
|
||||
/// Set the virtual channel frame count.
|
||||
pub fn set_vc_frame_count(
|
||||
&mut self,
|
||||
count_len: u3,
|
||||
count_len: u8,
|
||||
count: u64,
|
||||
) -> Result<(), InvalidValueForLenError> {
|
||||
if count > 2_u64.pow(count_len.as_u32() * 8) - 1 {
|
||||
if count > 2_u64.pow(count_len as u32 * 8) - 1 {
|
||||
return Err(InvalidValueForLenError {
|
||||
value: count,
|
||||
len: count_len,
|
||||
@@ -153,7 +163,7 @@ impl PrimaryHeader {
|
||||
|
||||
/// Length of the virtual channel frame count field.
|
||||
#[inline]
|
||||
pub fn vc_frame_count_len(&self) -> u3 {
|
||||
pub fn vc_frame_count_len(&self) -> u8 {
|
||||
self.vc_frame_count_len
|
||||
}
|
||||
|
||||
@@ -188,15 +198,15 @@ impl PrimaryHeader {
|
||||
1 => SourceOrDestField::Dest,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let vc_frame_count_len = u3::new(buf[6] & 0b111);
|
||||
if buf.len() < 7 + vc_frame_count_len.as_usize() {
|
||||
let vc_frame_count_len = buf[6] & 0b111;
|
||||
if buf.len() < 7 + vc_frame_count_len as usize {
|
||||
return Err(ByteConversionError::FromSliceTooSmall {
|
||||
found: buf.len(),
|
||||
expected: 7 + vc_frame_count_len.as_usize(),
|
||||
expected: 7 + vc_frame_count_len as usize,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
let vc_frame_count = match vc_frame_count_len.value() {
|
||||
let vc_frame_count = match vc_frame_count_len {
|
||||
1 => buf[7] as u64,
|
||||
2 => u16::from_be_bytes(buf[7..9].try_into().unwrap()) as u64,
|
||||
4 => u32::from_be_bytes(buf[7..11].try_into().unwrap()) as u64,
|
||||
@@ -215,8 +225,8 @@ impl PrimaryHeader {
|
||||
| ((buf[1] as u16) << 4)
|
||||
| ((buf[2] as u16) >> 4) & 0b1111,
|
||||
source_or_dest_field,
|
||||
vc_id: u6::new(((buf[2] & 0b111) << 3) | (buf[3] >> 5) & 0b111),
|
||||
map_id: u4::new((buf[3] >> 1) & 0b1111),
|
||||
vc_id: ((buf[2] & 0b111) << 3) | (buf[3] >> 5) & 0b111,
|
||||
map_id: (buf[3] >> 1) & 0b1111,
|
||||
frame_len_field: ((buf[4] as u16) << 8) | buf[5] as u16,
|
||||
sequence_control_flag: ((buf[6] >> 7) & 0b1).try_into().unwrap(),
|
||||
protocol_control_command_flag: ((buf[6] >> 6) & 0b1).try_into().unwrap(),
|
||||
@@ -227,7 +237,7 @@ impl PrimaryHeader {
|
||||
}
|
||||
|
||||
/// Write primary header to bytes.
|
||||
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
|
||||
pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
|
||||
if buf.len() < self.len_header() {
|
||||
return Err(ByteConversionError::ToSliceTooSmall {
|
||||
found: buf.len(),
|
||||
@@ -238,15 +248,15 @@ impl PrimaryHeader {
|
||||
buf[1] = (self.spacecraft_id >> 4) as u8;
|
||||
buf[2] = (((self.spacecraft_id & 0b1111) as u8) << 4)
|
||||
| ((self.source_or_dest_field as u8) << 3)
|
||||
| (self.vc_id.as_u8() >> 3) & 0b111;
|
||||
buf[3] = ((self.vc_id.as_u8() & 0b111) << 5) | (self.map_id.as_u8() << 1);
|
||||
| (self.vc_id >> 3) & 0b111;
|
||||
buf[3] = ((self.vc_id & 0b111) << 5) | (self.map_id << 1);
|
||||
buf[4..6].copy_from_slice(&self.frame_len_field.to_be_bytes());
|
||||
buf[6] = ((self.sequence_control_flag as u8) << 7)
|
||||
| ((self.protocol_control_command_flag as u8) << 6)
|
||||
| ((self.ocf_flag as u8) << 3)
|
||||
| self.vc_frame_count_len.as_u8();
|
||||
| self.vc_frame_count_len;
|
||||
let mut packet_idx = 7;
|
||||
for idx in (0..self.vc_frame_count_len.value()).rev() {
|
||||
for idx in (0..self.vc_frame_count_len).rev() {
|
||||
buf[packet_idx] = ((self.vc_frame_count >> (idx * 8)) & 0xff) as u8;
|
||||
packet_idx += 1;
|
||||
}
|
||||
@@ -265,7 +275,7 @@ impl PrimaryHeader {
|
||||
/// Length of primary header when written to bytes.
|
||||
#[inline(always)]
|
||||
pub fn len_header(&self) -> usize {
|
||||
7 + self.vc_frame_count_len.as_usize()
|
||||
7 + self.vc_frame_count_len as usize
|
||||
}
|
||||
|
||||
/// Length of the entire frame.
|
||||
@@ -431,96 +441,6 @@ impl TransferFrameDataFieldHeader {
|
||||
fhp_or_lvo,
|
||||
})
|
||||
}
|
||||
|
||||
/// Write [self] to the provided byte buffer.
|
||||
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
|
||||
let full_len = self.len_header();
|
||||
if buf.len() < full_len {
|
||||
return Err(ByteConversionError::ToSliceTooSmall {
|
||||
found: buf.len(),
|
||||
expected: full_len,
|
||||
});
|
||||
}
|
||||
buf[0] = ((self.construction_rule as u8) << 5) | (self.uslp_protocol_id as u8 & 0b11111);
|
||||
if let Some(fhp_or_lvo) = self.fhp_or_lvo {
|
||||
buf[1..3].copy_from_slice(&fhp_or_lvo.to_be_bytes());
|
||||
}
|
||||
Ok(full_len)
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple USLP transfer frame creator.
|
||||
pub struct TransferFrameCreator<'data> {
|
||||
primary_header: PrimaryHeader,
|
||||
data_field_header: TransferFrameDataFieldHeader,
|
||||
data: &'data [u8],
|
||||
operational_control_field: Option<u32>,
|
||||
has_fecf: bool,
|
||||
}
|
||||
|
||||
impl<'data> TransferFrameCreator<'data> {
|
||||
/// Constructor.
|
||||
pub fn new(
|
||||
primary_header: PrimaryHeader,
|
||||
data_field_header: TransferFrameDataFieldHeader,
|
||||
data: &'data [u8],
|
||||
op_control_field: Option<u32>,
|
||||
has_fecf: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
primary_header,
|
||||
data_field_header,
|
||||
data,
|
||||
operational_control_field: op_control_field,
|
||||
has_fecf,
|
||||
}
|
||||
}
|
||||
|
||||
/// Length of the frame when written to bytes.
|
||||
pub fn len_written(&self) -> usize {
|
||||
self.primary_header.len_header()
|
||||
+ self.data_field_header.len_header()
|
||||
+ self.data.len()
|
||||
+ if self.operational_control_field.is_some() {
|
||||
4
|
||||
} else {
|
||||
0
|
||||
}
|
||||
+ if self.has_fecf { 2 } else { 0 }
|
||||
}
|
||||
|
||||
/// Write [self] to the provided byte buffer.
|
||||
pub fn write_to_bytes(&mut self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
|
||||
let full_len = self.len_written();
|
||||
if full_len > buf.len() {
|
||||
return Err(ByteConversionError::ToSliceTooSmall {
|
||||
found: buf.len(),
|
||||
expected: full_len,
|
||||
});
|
||||
}
|
||||
let mut current_index = 0;
|
||||
self.primary_header.set_frame_len(full_len);
|
||||
current_index += self.primary_header.write_to_bytes(buf)?;
|
||||
|
||||
current_index += self
|
||||
.data_field_header
|
||||
.write_to_bytes(&mut buf[self.primary_header.len_header()..])?;
|
||||
buf[current_index..current_index + self.data.len()].copy_from_slice(self.data);
|
||||
current_index += self.data.len();
|
||||
|
||||
if let Some(ocf) = self.operational_control_field {
|
||||
buf[current_index..current_index + 4].copy_from_slice(&ocf.to_be_bytes());
|
||||
current_index += 4;
|
||||
}
|
||||
if self.has_fecf {
|
||||
let mut digest = CRC_CCITT_FALSE.digest();
|
||||
digest.update(&buf[0..current_index]);
|
||||
let crc = digest.finalize();
|
||||
buf[current_index..current_index + 2].copy_from_slice(&crc.to_be_bytes());
|
||||
current_index += 2;
|
||||
}
|
||||
Ok(current_index)
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple USLP transfer frame reader.
|
||||
@@ -646,15 +566,15 @@ mod tests {
|
||||
let primary_header = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0b110101,
|
||||
0b1010,
|
||||
0x2345,
|
||||
)
|
||||
.unwrap();
|
||||
// Virtual channel count 0.
|
||||
assert_eq!(primary_header.write_to_bytes(&mut buf).unwrap(), 7);
|
||||
assert_eq!(primary_header.write_to_be_bytes(&mut buf).unwrap(), 7);
|
||||
common_basic_check(&buf);
|
||||
assert_eq!(primary_header.vc_frame_count_len().value(), 0);
|
||||
assert_eq!(primary_header.vc_frame_count_len(), 0);
|
||||
assert_eq!(primary_header.vc_frame_count(), 0);
|
||||
// Bypass / Sequence Control Flag.
|
||||
assert_eq!(
|
||||
@@ -680,8 +600,8 @@ mod tests {
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0b110101,
|
||||
0b1010,
|
||||
0x2345,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -689,12 +609,10 @@ mod tests {
|
||||
primary_header.protocol_control_command_flag =
|
||||
ProtocolControlCommandFlag::TfdfContainsProtocolInfo;
|
||||
primary_header.ocf_flag = true;
|
||||
primary_header
|
||||
.set_vc_frame_count(u3::new(4), 0x12345678)
|
||||
.unwrap();
|
||||
primary_header.set_vc_frame_count(4, 0x12345678).unwrap();
|
||||
// Virtual channel count 4.
|
||||
assert_eq!(primary_header.write_to_bytes(&mut buf).unwrap(), 11);
|
||||
assert_eq!(primary_header.vc_frame_count_len().value(), 4);
|
||||
assert_eq!(primary_header.write_to_be_bytes(&mut buf).unwrap(), 11);
|
||||
assert_eq!(primary_header.vc_frame_count_len(), 4);
|
||||
assert_eq!(primary_header.vc_frame_count(), 0x12345678);
|
||||
common_basic_check(&buf);
|
||||
// Bypass / Sequence Control Flag.
|
||||
@@ -725,20 +643,20 @@ mod tests {
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0b110101,
|
||||
0b1010,
|
||||
0x2345,
|
||||
)
|
||||
.unwrap();
|
||||
primary_header.set_vc_frame_count(u3::new(2), 5).unwrap();
|
||||
assert_eq!(primary_header.vc_frame_count_len().value(), 2);
|
||||
primary_header.set_vc_frame_count(2, 5).unwrap();
|
||||
assert_eq!(primary_header.vc_frame_count_len(), 2);
|
||||
assert_eq!(primary_header.vc_frame_count(), 5);
|
||||
assert_eq!(primary_header.write_to_bytes(&mut buf).unwrap(), 9);
|
||||
assert_eq!(primary_header.write_to_be_bytes(&mut buf).unwrap(), 9);
|
||||
assert_eq!(buf[6] & 0b111, 2);
|
||||
assert_eq!(u16::from_be_bytes(buf[7..9].try_into().unwrap()), 5);
|
||||
|
||||
let primary_header = PrimaryHeader::from_bytes(&buf).unwrap();
|
||||
assert_eq!(primary_header.vc_frame_count_len().value(), 2);
|
||||
assert_eq!(primary_header.vc_frame_count_len(), 2);
|
||||
assert_eq!(primary_header.vc_frame_count(), 5);
|
||||
}
|
||||
|
||||
@@ -750,20 +668,20 @@ mod tests {
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0b110101,
|
||||
0b1010,
|
||||
0x2345,
|
||||
)
|
||||
.unwrap();
|
||||
primary_header.set_vc_frame_count(u3::new(1), 255).unwrap();
|
||||
assert_eq!(primary_header.vc_frame_count_len().value(), 1);
|
||||
primary_header.set_vc_frame_count(1, 255).unwrap();
|
||||
assert_eq!(primary_header.vc_frame_count_len(), 1);
|
||||
assert_eq!(primary_header.vc_frame_count(), 255);
|
||||
assert_eq!(primary_header.write_to_bytes(&mut buf).unwrap(), 8);
|
||||
assert_eq!(primary_header.write_to_be_bytes(&mut buf).unwrap(), 8);
|
||||
assert_eq!(buf[6] & 0b111, 1);
|
||||
assert_eq!(buf[7], 255);
|
||||
|
||||
let primary_header = PrimaryHeader::from_bytes(&buf).unwrap();
|
||||
assert_eq!(primary_header.vc_frame_count_len().value(), 1);
|
||||
assert_eq!(primary_header.vc_frame_count_len(), 1);
|
||||
assert_eq!(primary_header.vc_frame_count(), 255);
|
||||
}
|
||||
|
||||
@@ -773,12 +691,12 @@ mod tests {
|
||||
let primary_header = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0b110101,
|
||||
0b1010,
|
||||
0x2345,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(primary_header.write_to_bytes(&mut buf).unwrap(), 7);
|
||||
assert_eq!(primary_header.write_to_be_bytes(&mut buf).unwrap(), 7);
|
||||
let parsed_header = PrimaryHeader::from_bytes(&buf).unwrap();
|
||||
assert_eq!(parsed_header, primary_header);
|
||||
}
|
||||
@@ -789,8 +707,8 @@ mod tests {
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0b110101,
|
||||
0b1010,
|
||||
0x2345,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -798,37 +716,57 @@ mod tests {
|
||||
primary_header.protocol_control_command_flag =
|
||||
ProtocolControlCommandFlag::TfdfContainsProtocolInfo;
|
||||
primary_header.ocf_flag = true;
|
||||
primary_header
|
||||
.set_vc_frame_count(u3::new(4), 0x12345678)
|
||||
.unwrap();
|
||||
assert_eq!(primary_header.write_to_bytes(&mut buf).unwrap(), 11);
|
||||
primary_header.set_vc_frame_count(4, 0x12345678).unwrap();
|
||||
assert_eq!(primary_header.write_to_be_bytes(&mut buf).unwrap(), 11);
|
||||
let parsed_header = PrimaryHeader::from_bytes(&buf).unwrap();
|
||||
assert_eq!(parsed_header, primary_header);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_vcid() {
|
||||
let error = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
0b1101011,
|
||||
0b1010,
|
||||
0x2345,
|
||||
);
|
||||
assert!(error.is_err());
|
||||
let error = error.unwrap_err();
|
||||
matches!(error, UslpError::InvalidVcId(0b1101011));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_mapid() {
|
||||
let error = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
0b110101,
|
||||
0b10101,
|
||||
0x2345,
|
||||
);
|
||||
assert!(error.is_err());
|
||||
let error = error.unwrap_err();
|
||||
matches!(error, UslpError::InvalidMapId(0b10101));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_vc_count() {
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0b110101,
|
||||
0b1010,
|
||||
0x2345,
|
||||
)
|
||||
.unwrap();
|
||||
matches!(
|
||||
primary_header.set_vc_frame_count(u3::ZERO, 1).unwrap_err(),
|
||||
InvalidValueForLenError {
|
||||
value: 1,
|
||||
len: u3::ZERO
|
||||
}
|
||||
primary_header.set_vc_frame_count(0, 1).unwrap_err(),
|
||||
InvalidValueForLenError { value: 1, len: 0 }
|
||||
);
|
||||
let len = u3::new(1);
|
||||
assert_eq!(
|
||||
primary_header
|
||||
.set_vc_frame_count(u3::new(1), 256)
|
||||
.unwrap_err(),
|
||||
InvalidValueForLenError { value: 256, len }
|
||||
matches!(
|
||||
primary_header.set_vc_frame_count(1, 256).unwrap_err(),
|
||||
InvalidValueForLenError { value: 256, len: 1 }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -836,21 +774,15 @@ mod tests {
|
||||
fn test_frame_parser() {
|
||||
let mut buf: [u8; 32] = [0; 32];
|
||||
// Build a variable frame manually.
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0x01,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
let mut primary_header =
|
||||
PrimaryHeader::new(0x01, SourceOrDestField::Dest, 0b110101, 0b1010, 0).unwrap();
|
||||
let header_len = primary_header.len_header();
|
||||
buf[header_len] = ((ConstructionRule::NoSegmentation as u8) << 5)
|
||||
| (UslpProtocolId::UserDefinedOctetStream as u8) & 0b11111;
|
||||
buf[header_len + 1] = 0x42;
|
||||
// 1 byte TFDH, 1 byte data, 2 bytes CRC.
|
||||
primary_header.set_frame_len(header_len + 4);
|
||||
primary_header.write_to_bytes(&mut buf).unwrap();
|
||||
primary_header.write_to_be_bytes(&mut buf).unwrap();
|
||||
// Calculate and write CRC16.
|
||||
let mut digest = CRC_CCITT_FALSE.digest();
|
||||
digest.update(&buf[0..header_len + 2]);
|
||||
@@ -877,21 +809,15 @@ mod tests {
|
||||
fn test_frame_parser_invalid_checksum() {
|
||||
let mut buf: [u8; 32] = [0; 32];
|
||||
// Build a variable frame manually.
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0x01,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
let mut primary_header =
|
||||
PrimaryHeader::new(0x01, SourceOrDestField::Dest, 0b110101, 0b1010, 0).unwrap();
|
||||
let header_len = primary_header.len_header();
|
||||
buf[header_len] = ((ConstructionRule::NoSegmentation as u8) << 5)
|
||||
| (UslpProtocolId::UserDefinedOctetStream as u8) & 0b11111;
|
||||
buf[header_len + 1] = 0x42;
|
||||
// 1 byte TFDH, 1 byte data, 2 bytes CRC.
|
||||
primary_header.set_frame_len(header_len + 4);
|
||||
primary_header.write_to_bytes(&mut buf).unwrap();
|
||||
primary_header.write_to_be_bytes(&mut buf).unwrap();
|
||||
// Now parse the frame without having calculated the checksum.
|
||||
match TransferFrameReader::from_bytes(&buf, true) {
|
||||
Ok(_) => panic!("transfer frame read call did not fail"),
|
||||
@@ -905,21 +831,15 @@ mod tests {
|
||||
fn test_frame_parser_buf_too_small() {
|
||||
let mut buf: [u8; 32] = [0; 32];
|
||||
// Build a variable frame manually.
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0x01,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
let mut primary_header =
|
||||
PrimaryHeader::new(0x01, SourceOrDestField::Dest, 0b110101, 0b1010, 0).unwrap();
|
||||
let header_len = primary_header.len_header();
|
||||
buf[header_len] = ((ConstructionRule::NoSegmentation as u8) << 5)
|
||||
| (UslpProtocolId::UserDefinedOctetStream as u8) & 0b11111;
|
||||
buf[header_len + 1] = 0x42;
|
||||
// 1 byte TFDH, 1 byte data, 2 bytes CRC.
|
||||
primary_header.set_frame_len(header_len + 4);
|
||||
primary_header.write_to_bytes(&mut buf).unwrap();
|
||||
primary_header.write_to_be_bytes(&mut buf).unwrap();
|
||||
// Now parse the frame.
|
||||
let error = TransferFrameReader::from_bytes(&buf[0..7], true).unwrap_err();
|
||||
assert_eq!(
|
||||
@@ -961,15 +881,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_from_bytes_truncated_not_supported() {
|
||||
let mut buf: [u8; 7] = [0; 7];
|
||||
let primary_header = PrimaryHeader::new(
|
||||
0x01,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
primary_header.write_to_bytes(&mut buf).unwrap();
|
||||
let primary_header =
|
||||
PrimaryHeader::new(0x01, SourceOrDestField::Dest, 0b110101, 0b1010, 0).unwrap();
|
||||
primary_header.write_to_be_bytes(&mut buf).unwrap();
|
||||
// Set truncated header flag manually.
|
||||
buf[3] |= 0b1;
|
||||
assert_eq!(
|
||||
@@ -986,15 +900,13 @@ mod tests {
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0b110101,
|
||||
0b1010,
|
||||
0x2345,
|
||||
)
|
||||
.unwrap();
|
||||
primary_header
|
||||
.set_vc_frame_count(u3::new(4), 0x12345678)
|
||||
.unwrap();
|
||||
primary_header.write_to_bytes(&mut buf).unwrap();
|
||||
primary_header.set_vc_frame_count(4, 0x12345678).unwrap();
|
||||
primary_header.write_to_be_bytes(&mut buf).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
PrimaryHeader::from_bytes(&buf[0..8]).unwrap_err(),
|
||||
@@ -1008,15 +920,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_invalid_version_number() {
|
||||
let mut buf: [u8; 7] = [0; 7];
|
||||
let primary_header = PrimaryHeader::new(
|
||||
0x01,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
primary_header.write_to_bytes(&mut buf).unwrap();
|
||||
let primary_header =
|
||||
PrimaryHeader::new(0x01, SourceOrDestField::Dest, 0b110101, 0b1010, 0).unwrap();
|
||||
primary_header.write_to_be_bytes(&mut buf).unwrap();
|
||||
buf[0] &= 0b00001111;
|
||||
assert_eq!(
|
||||
PrimaryHeader::from_bytes(&buf).unwrap_err(),
|
||||
@@ -1029,13 +935,13 @@ mod tests {
|
||||
let primary_header = PrimaryHeader::new(
|
||||
0b10100101_11000011,
|
||||
SourceOrDestField::Dest,
|
||||
u6::new(0b110101),
|
||||
u4::new(0b1010),
|
||||
0b110101,
|
||||
0b1010,
|
||||
0x2345,
|
||||
)
|
||||
.unwrap();
|
||||
if let Err(ByteConversionError::ToSliceTooSmall { found, expected }) =
|
||||
primary_header.write_to_bytes(&mut [0; 4])
|
||||
primary_header.write_to_be_bytes(&mut [0; 4])
|
||||
{
|
||||
assert_eq!(found, 4);
|
||||
assert_eq!(expected, 7);
|
||||
@@ -1096,37 +1002,4 @@ mod tests {
|
||||
.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_frame_creator() {
|
||||
// Relying on the reader implementation for now.
|
||||
let mut primary_header = PrimaryHeader::new(
|
||||
0x1234,
|
||||
SourceOrDestField::Source,
|
||||
u6::new(0b101010),
|
||||
u4::new(0b0101),
|
||||
0,
|
||||
).unwrap();
|
||||
let data_field_header = TransferFrameDataFieldHeader {
|
||||
construction_rule: ConstructionRule::NoSegmentation,
|
||||
uslp_protocol_id: UslpProtocolId::UserDefinedOctetStream,
|
||||
fhp_or_lvo: None,
|
||||
};
|
||||
let data = [1, 2, 3, 4];
|
||||
let mut frame_creator = TransferFrameCreator::new(
|
||||
primary_header,
|
||||
data_field_header,
|
||||
&data,
|
||||
None,
|
||||
true,
|
||||
);
|
||||
let mut buf: [u8; 64] = [0; 64];
|
||||
let written = frame_creator.write_to_bytes(&mut buf).unwrap();
|
||||
assert_eq!(written, 14);
|
||||
assert_eq!(written, frame_creator.len_written());
|
||||
let reader = TransferFrameReader::from_bytes(&buf, true).unwrap();
|
||||
primary_header.set_frame_len(written);
|
||||
assert_eq!(reader.primary_header(), &primary_header);
|
||||
// TODO: More tests
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user