base line cuc impl done
This commit is contained in:
parent
f7f500ea48
commit
c4f8eee8da
340
src/time.rs
340
src/time.rs
@ -7,15 +7,14 @@ use core::fmt::{Display, Formatter};
|
|||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use num_traits::float::FloatCore;
|
use num_traits::float::FloatCore;
|
||||||
|
|
||||||
|
use crate::time::cuc::CucError;
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::time::{SystemTime, SystemTimeError};
|
use std::time::{SystemTime, SystemTimeError};
|
||||||
|
|
||||||
use crate::time::cds::LengthOfDaySegment;
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub const DAYS_CCSDS_TO_UNIX: i32 = -4383;
|
pub const DAYS_CCSDS_TO_UNIX: i32 = -4383;
|
||||||
pub const SECONDS_PER_DAY: u32 = 86400;
|
pub const SECONDS_PER_DAY: u32 = 86400;
|
||||||
|
|
||||||
@ -51,36 +50,6 @@ pub fn ccsds_time_code_from_p_field(pfield: u8) -> Result<CcsdsTimeCodes, u8> {
|
|||||||
CcsdsTimeCodes::try_from(raw_bits).map_err(|_| raw_bits)
|
CcsdsTimeCodes::try_from(raw_bits).map_err(|_| raw_bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
pub enum CdsError {
|
|
||||||
/// CCSDS days value exceeds maximum allowed size or is negative
|
|
||||||
InvalidCcsdsDays(i64),
|
|
||||||
/// There are distinct constructors depending on the days field width detected in the preamble
|
|
||||||
/// field. This error will be returned if there is a missmatch.
|
|
||||||
InvalidCtorForDaysOfLenInPreamble(LengthOfDaySegment),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for CdsError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
|
||||||
match self {
|
|
||||||
CdsError::InvalidCcsdsDays(days) => {
|
|
||||||
write!(f, "invalid ccsds days {}", days)
|
|
||||||
}
|
|
||||||
CdsError::InvalidCtorForDaysOfLenInPreamble(length_of_day) => {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"wrong constructor for length of day {:?} detected in preamble",
|
|
||||||
length_of_day
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl Error for CdsError {}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub enum TimestampError {
|
pub enum TimestampError {
|
||||||
@ -88,13 +57,20 @@ pub enum TimestampError {
|
|||||||
/// value is the found raw value
|
/// value is the found raw value
|
||||||
InvalidTimeCode(CcsdsTimeCodes, u8),
|
InvalidTimeCode(CcsdsTimeCodes, u8),
|
||||||
ByteConversionError(ByteConversionError),
|
ByteConversionError(ByteConversionError),
|
||||||
CdsError(CdsError),
|
CdsError(cds::CdsError),
|
||||||
|
CucError(cuc::CucError),
|
||||||
CustomEpochNotSupported,
|
CustomEpochNotSupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CdsError> for TimestampError {
|
impl From<cds::CdsError> for TimestampError {
|
||||||
fn from(v: CdsError) -> Self {
|
fn from(e: cds::CdsError) -> Self {
|
||||||
TimestampError::CdsError(v)
|
TimestampError::CdsError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<cuc::CucError> for TimestampError {
|
||||||
|
fn from(e: CucError) -> Self {
|
||||||
|
TimestampError::CucError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +109,9 @@ impl Display for TimestampError {
|
|||||||
TimestampError::CdsError(e) => {
|
TimestampError::CdsError(e) => {
|
||||||
write!(f, "cds error {}", e)
|
write!(f, "cds error {}", e)
|
||||||
}
|
}
|
||||||
|
TimestampError::CucError(e) => {
|
||||||
|
write!(f, "cuc error {}", e)
|
||||||
|
}
|
||||||
TimestampError::ByteConversionError(e) => {
|
TimestampError::ByteConversionError(e) => {
|
||||||
write!(f, "byte conversion error {}", e)
|
write!(f, "byte conversion error {}", e)
|
||||||
}
|
}
|
||||||
@ -149,6 +128,7 @@ impl Error for TimestampError {
|
|||||||
match self {
|
match self {
|
||||||
TimestampError::ByteConversionError(e) => Some(e),
|
TimestampError::ByteConversionError(e) => Some(e),
|
||||||
TimestampError::CdsError(e) => Some(e),
|
TimestampError::CdsError(e) => Some(e),
|
||||||
|
TimestampError::CucError(e) => Some(e),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,6 +250,35 @@ pub mod cds {
|
|||||||
Reserved,
|
Reserved,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub enum CdsError {
|
||||||
|
/// CCSDS days value exceeds maximum allowed size or is negative
|
||||||
|
InvalidCcsdsDays(i64),
|
||||||
|
/// There are distinct constructors depending on the days field width detected in the preamble
|
||||||
|
/// field. This error will be returned if there is a missmatch.
|
||||||
|
InvalidCtorForDaysOfLenInPreamble(LengthOfDaySegment),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for CdsError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
match self {
|
||||||
|
CdsError::InvalidCcsdsDays(days) => {
|
||||||
|
write!(f, "invalid ccsds days {}", days)
|
||||||
|
}
|
||||||
|
CdsError::InvalidCtorForDaysOfLenInPreamble(length_of_day) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"wrong constructor for length of day {:?} detected in preamble",
|
||||||
|
length_of_day
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl Error for CdsError {}
|
||||||
pub fn length_of_day_segment_from_pfield(pfield: u8) -> LengthOfDaySegment {
|
pub fn length_of_day_segment_from_pfield(pfield: u8) -> LengthOfDaySegment {
|
||||||
if (pfield >> 2) & 0b1 == 1 {
|
if (pfield >> 2) & 0b1 == 1 {
|
||||||
return LengthOfDaySegment::Long24Bits;
|
return LengthOfDaySegment::Long24Bits;
|
||||||
@ -816,8 +825,41 @@ pub mod cds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod cuc {
|
pub mod cuc {
|
||||||
use core::fmt::Debug;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
const MIN_CUC_LEN: usize = 2;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub enum CucError {
|
||||||
|
InvalidCounterWidth(u8),
|
||||||
|
InvalidFractionWidth(u8),
|
||||||
|
InvalidCounter(u8, u64),
|
||||||
|
InvalidFractions(u8, u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for CucError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
match self {
|
||||||
|
CucError::InvalidCounterWidth(w) => {
|
||||||
|
write!(f, "invalid cuc counter byte width {}", w)
|
||||||
|
}
|
||||||
|
CucError::InvalidFractionWidth(w) => {
|
||||||
|
write!(f, "invalid cuc fractional part byte width {}", w)
|
||||||
|
}
|
||||||
|
CucError::InvalidCounter(w, c) => {
|
||||||
|
write!(f, "invalid cuc counter {} for width {}", c, w)
|
||||||
|
}
|
||||||
|
CucError::InvalidFractions(w, c) => {
|
||||||
|
write!(f, "invalid cuc fractional part {} for width {}", c, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl Error for CucError {}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
@ -833,7 +875,7 @@ pub mod cuc {
|
|||||||
pub struct TimeProviderCcsdsEpoch {
|
pub struct TimeProviderCcsdsEpoch {
|
||||||
pfield: u8,
|
pfield: u8,
|
||||||
counter: WidthCounterPair,
|
counter: WidthCounterPair,
|
||||||
fractions: Option<WidthCounterPair>
|
fractions: Option<WidthCounterPair>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -841,53 +883,183 @@ pub mod cuc {
|
|||||||
if ((pfield >> 7) & 0b1) == 1 {
|
if ((pfield >> 7) & 0b1) == 1 {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
return 1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimeProviderCcsdsEpoch {
|
impl TimeProviderCcsdsEpoch {
|
||||||
fn build_p_field(counter_width: u8, fractions_width: Option<u8>) -> u8 {
|
fn build_p_field(counter_width: u8, fractions_width: Option<u8>) -> u8 {
|
||||||
let mut pfield = (CcsdsTimeCodes::CucCcsdsEpoch as u8) << 4;
|
let mut pfield = (CcsdsTimeCodes::CucCcsdsEpoch as u8) << 4;
|
||||||
if counter_width < 1 || counter_width > 4 {
|
if !(1..=4).contains(&counter_width) {
|
||||||
|
// Okay to panic here, this function is private and all input values should
|
||||||
|
// have been sanitized
|
||||||
panic!("invalid counter width {} for cuc timestamp", counter_width);
|
panic!("invalid counter width {} for cuc timestamp", counter_width);
|
||||||
}
|
}
|
||||||
pfield |= counter_width << 3;
|
pfield |= (counter_width - 1) << 3;
|
||||||
if let Some(fractions_width) = fractions_width {
|
if let Some(fractions_width) = fractions_width {
|
||||||
if fractions_width < 1 || fractions_width > 3 {
|
if !(1..=3).contains(&fractions_width) {
|
||||||
panic!("invalid fractions width {} for cuc timestamp", fractions_width);
|
// Okay to panic here, this function is private and all input values should
|
||||||
|
// have been sanitized
|
||||||
|
panic!(
|
||||||
|
"invalid fractions width {} for cuc timestamp",
|
||||||
|
fractions_width
|
||||||
|
);
|
||||||
}
|
}
|
||||||
pfield |= fractions_width;
|
pfield |= fractions_width;
|
||||||
}
|
}
|
||||||
pfield
|
pfield
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn len_packed(&self) -> usize {
|
pub fn len_packed(&self) -> usize {
|
||||||
// TODO: Implement
|
Self::len_packed_from_pfield(self.pfield)
|
||||||
todo!()
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn len_cntr_from_pfield(pfield: u8) -> u8 {
|
||||||
|
((pfield >> 2) & 0b11) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn len_fractions_from_pfield(pfield: u8) -> u8 {
|
||||||
|
pfield & 0b11
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This returns the length of the individual components of the CUC timestamp in addition
|
||||||
|
/// to the total size.
|
||||||
|
///
|
||||||
|
/// This function will return a tuple where the first value is the byte width of the
|
||||||
|
/// counter, the second value is the byte width of the fractional part, and the third
|
||||||
|
/// components is the total size.
|
||||||
|
pub fn len_components_and_total_from_pfield(pfield: u8) -> (u8, u8, usize) {
|
||||||
|
let base_len: usize = 1;
|
||||||
|
let cntr_len = Self::len_cntr_from_pfield(pfield);
|
||||||
|
let fractions_len = Self::len_fractions_from_pfield(pfield);
|
||||||
|
(
|
||||||
|
cntr_len,
|
||||||
|
fractions_len,
|
||||||
|
base_len + cntr_len as usize + fractions_len as usize,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len_packed_from_pfield(pfield: u8) -> usize {
|
||||||
|
let mut base_len: usize = 1;
|
||||||
|
base_len += Self::len_cntr_from_pfield(pfield) as usize;
|
||||||
|
base_len += Self::len_fractions_from_pfield(pfield) as usize;
|
||||||
|
base_len
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies the raw width parameter and returns the actual length, which is the raw
|
||||||
|
/// value plus 1.
|
||||||
|
fn verify_counter_width(width: u8) -> Result<(), CucError> {
|
||||||
|
if width == 0 || width > 4 {
|
||||||
|
return Err(CucError::InvalidCounterWidth(width));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_fractions_width(width: u8) -> Result<(), CucError> {
|
||||||
|
if width > 3 {
|
||||||
|
return Err(CucError::InvalidFractionWidth(width));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimeProviderCcsdsEpoch {
|
impl TimeProviderCcsdsEpoch {
|
||||||
pub fn new_default(counter: u32) -> Self {
|
pub fn new_default(counter: u32) -> Self {
|
||||||
Self::new(WidthCounterPair(4, counter), None)
|
// These values are definitely valid, so it is okay to unwrap here.
|
||||||
|
Self::new(WidthCounterPair(4, counter), None).unwrap()
|
||||||
|
}
|
||||||
|
pub fn new_u16_counter(counter: u16) -> Self {
|
||||||
|
// These values are definitely valid, so it is okay to unwrap here.
|
||||||
|
Self::new(WidthCounterPair(2, counter as u32), None).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(counter: WidthCounterPair, fractions: Option<WidthCounterPair>) -> Self {
|
pub fn new(
|
||||||
let fractions_width = match fractions {
|
counter: WidthCounterPair,
|
||||||
None => 0,
|
fractions: Option<WidthCounterPair>,
|
||||||
Some(fractions) => fractions.0
|
) -> Result<Self, CucError> {
|
||||||
};
|
Self::verify_counter_width(counter.0)?;
|
||||||
Self {
|
if counter.1 > 2u32.pow(counter.0 as u32 * 8) - 1 {
|
||||||
pfield: Self::build_p_field(counter.0.into(), fractions_width.into()),
|
return Err(CucError::InvalidCounter(counter.0, counter.1 as u64));
|
||||||
counter,
|
|
||||||
fractions
|
|
||||||
}
|
}
|
||||||
|
if let Some(fractions) = fractions {
|
||||||
|
Self::verify_fractions_width(fractions.0)?;
|
||||||
|
if fractions.1 > 2u32.pow((fractions.0 as u32) * 8) - 1 {
|
||||||
|
return Err(CucError::InvalidFractions(fractions.0, fractions.1 as u64));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
pfield: Self::build_p_field(counter.0, fractions.map(|v| v.0)),
|
||||||
|
counter,
|
||||||
|
fractions,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimeReader for TimeProviderCcsdsEpoch {
|
impl TimeReader for TimeProviderCcsdsEpoch {
|
||||||
fn from_bytes(_buf: &[u8]) -> Result<Self, TimestampError> where Self: Sized {
|
fn from_bytes(buf: &[u8]) -> Result<Self, TimestampError>
|
||||||
todo!()
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
if buf.len() < MIN_CUC_LEN {
|
||||||
|
return Err(TimestampError::ByteConversionError(
|
||||||
|
ByteConversionError::FromSliceTooSmall(SizeMissmatch {
|
||||||
|
expected: MIN_CUC_LEN,
|
||||||
|
found: buf.len(),
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let (cntr_len, fractions_len, total_len) =
|
||||||
|
Self::len_components_and_total_from_pfield(buf[0]);
|
||||||
|
if buf.len() < total_len {
|
||||||
|
return Err(TimestampError::ByteConversionError(
|
||||||
|
ByteConversionError::FromSliceTooSmall(SizeMissmatch {
|
||||||
|
expected: total_len,
|
||||||
|
found: buf.len(),
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let mut current_idx = 1;
|
||||||
|
let counter =
|
||||||
|
match cntr_len {
|
||||||
|
1 => buf[current_idx] as u32,
|
||||||
|
2 => u16::from_be_bytes(buf[current_idx..current_idx + 2].try_into().unwrap())
|
||||||
|
as u32,
|
||||||
|
3 => {
|
||||||
|
let mut tmp_buf: [u8; 4] = [0; 4];
|
||||||
|
tmp_buf[1..4].copy_from_slice(&buf[current_idx..current_idx + 3]);
|
||||||
|
u32::from_be_bytes(tmp_buf) as u32
|
||||||
|
}
|
||||||
|
4 => u32::from_be_bytes(buf[current_idx..current_idx + 4].try_into().unwrap())
|
||||||
|
as u32,
|
||||||
|
_ => panic!("unreachable match arm"),
|
||||||
|
};
|
||||||
|
current_idx += cntr_len as usize;
|
||||||
|
let mut fractions = None;
|
||||||
|
if fractions_len > 0 {
|
||||||
|
match fractions_len {
|
||||||
|
1 => fractions = Some(WidthCounterPair(fractions_len, buf[current_idx] as u32)),
|
||||||
|
2 => {
|
||||||
|
fractions = Some(WidthCounterPair(
|
||||||
|
fractions_len,
|
||||||
|
u16::from_be_bytes(
|
||||||
|
buf[current_idx..current_idx + 2].try_into().unwrap(),
|
||||||
|
) as u32,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
let mut tmp_buf: [u8; 4] = [0; 4];
|
||||||
|
tmp_buf[1..4].copy_from_slice(&buf[current_idx..current_idx + 3]);
|
||||||
|
fractions = Some(WidthCounterPair(
|
||||||
|
fractions_len,
|
||||||
|
u32::from_be_bytes(tmp_buf) as u32,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => panic!("unreachable match arm"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let provider = Self::new(WidthCounterPair(cntr_len, counter), fractions)?;
|
||||||
|
Ok(provider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,45 +1067,52 @@ pub mod cuc {
|
|||||||
fn write_to_bytes(&self, bytes: &mut [u8]) -> Result<usize, TimestampError> {
|
fn write_to_bytes(&self, bytes: &mut [u8]) -> Result<usize, TimestampError> {
|
||||||
// Cross check the sizes of the counters against byte widths in the ctor
|
// Cross check the sizes of the counters against byte widths in the ctor
|
||||||
if bytes.len() < self.len_packed() {
|
if bytes.len() < self.len_packed() {
|
||||||
return Err(TimestampError::ByteConversionError(ByteConversionError::ToSliceTooSmall(SizeMissmatch {
|
return Err(TimestampError::ByteConversionError(
|
||||||
found: bytes.len(),
|
ByteConversionError::ToSliceTooSmall(SizeMissmatch {
|
||||||
expected: self.len_packed()
|
found: bytes.len(),
|
||||||
})))
|
expected: self.len_packed(),
|
||||||
|
}),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
bytes[0] = self.pfield;
|
bytes[0] = self.pfield;
|
||||||
let mut current_idx: usize = 1;
|
let mut current_idx: usize = 1;
|
||||||
match self.counter.0 {
|
match self.counter.0 {
|
||||||
1 => {
|
1 => {
|
||||||
bytes[1] = self.counter.1 as u8;
|
bytes[current_idx] = self.counter.1 as u8;
|
||||||
},
|
}
|
||||||
2 => {
|
2 => {
|
||||||
bytes[1..3].copy_from_slice(&(self.counter.1 as u16).to_be_bytes());
|
bytes[current_idx..current_idx + 2]
|
||||||
},
|
.copy_from_slice(&(self.counter.1 as u16).to_be_bytes());
|
||||||
|
}
|
||||||
3 => {
|
3 => {
|
||||||
bytes[1..4].copy_from_slice(&self.counter.1.to_be_bytes()[1..4]);
|
bytes[current_idx..current_idx + 3]
|
||||||
},
|
.copy_from_slice(&self.counter.1.to_be_bytes()[1..4]);
|
||||||
|
}
|
||||||
4 => {
|
4 => {
|
||||||
bytes[1..5].copy_from_slice(&self.counter.1.to_be_bytes());
|
bytes[current_idx..current_idx + 4]
|
||||||
},
|
.copy_from_slice(&self.counter.1.to_be_bytes());
|
||||||
|
}
|
||||||
// Should never happen
|
// Should never happen
|
||||||
_ => panic!("invalid counter width value")
|
_ => panic!("invalid counter width value"),
|
||||||
}
|
}
|
||||||
current_idx += self.counter.0 as usize;
|
current_idx += self.counter.0 as usize;
|
||||||
if let Some(fractions) = self.fractions {
|
if let Some(fractions) = self.fractions {
|
||||||
match fractions.0 {
|
match fractions.0 {
|
||||||
1 => bytes[current_idx] = fractions.1 as u8,
|
1 => bytes[current_idx] = fractions.1 as u8,
|
||||||
2 => bytes[current_idx..current_idx + 2].copy_from_slice(&(fractions.1 as u16).to_be_bytes()),
|
2 => bytes[current_idx..current_idx + 2]
|
||||||
3 => bytes[current_idx..current_idx + 3].copy_from_slice(&fractions.1.to_be_bytes()[1..4]),
|
.copy_from_slice(&(fractions.1 as u16).to_be_bytes()),
|
||||||
|
3 => bytes[current_idx..current_idx + 3]
|
||||||
|
.copy_from_slice(&fractions.1.to_be_bytes()[1..4]),
|
||||||
// Should also never happen
|
// Should also never happen
|
||||||
_ => panic!("invalid fractions value")
|
_ => panic!("invalid fractions value"),
|
||||||
}
|
}
|
||||||
current_idx += fractions.0 as usize;
|
current_idx += fractions.0 as usize;
|
||||||
}
|
}
|
||||||
Ok(current_idx)
|
Ok(current_idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Module to generate the ASCII timecodes specified in
|
/// Module to generate the ASCII timecodes specified in
|
||||||
/// [CCSDS 301.0-B-4](https://public.ccsds.org/Pubs/301x0b4e1.pdf) section 3.5 .
|
/// [CCSDS 301.0-B-4](https://public.ccsds.org/Pubs/301x0b4e1.pdf) section 3.5 .
|
||||||
/// See [chrono::DateTime::format] for a usage example of the generated
|
/// See [chrono::DateTime::format] for a usage example of the generated
|
||||||
@ -1006,7 +1185,7 @@ pub mod ascii {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::cds::TimeProvider;
|
use super::cds::TimeProvider;
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::time::cds::{DaysLen16Bits, DaysLen24Bits, SubmillisPrecision};
|
use crate::time::cds::{DaysLen16Bits, DaysLen24Bits, LengthOfDaySegment, SubmillisPrecision};
|
||||||
use crate::time::TimestampError::{ByteConversionError, InvalidTimeCode};
|
use crate::time::TimestampError::{ByteConversionError, InvalidTimeCode};
|
||||||
use crate::ByteConversionError::{FromSliceTooSmall, ToSliceTooSmall};
|
use crate::ByteConversionError::{FromSliceTooSmall, ToSliceTooSmall};
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
@ -1163,8 +1342,9 @@ mod tests {
|
|||||||
let faulty_ctor = TimeProvider::<DaysLen16Bits>::from_bytes(&buf);
|
let faulty_ctor = TimeProvider::<DaysLen16Bits>::from_bytes(&buf);
|
||||||
assert!(faulty_ctor.is_err());
|
assert!(faulty_ctor.is_err());
|
||||||
let error = faulty_ctor.unwrap_err();
|
let error = faulty_ctor.unwrap_err();
|
||||||
if let TimestampError::CdsError(CdsError::InvalidCtorForDaysOfLenInPreamble(len_of_day)) =
|
if let TimestampError::CdsError(cds::CdsError::InvalidCtorForDaysOfLenInPreamble(
|
||||||
error
|
len_of_day,
|
||||||
|
)) = error
|
||||||
{
|
{
|
||||||
assert_eq!(len_of_day, LengthOfDaySegment::Long24Bits);
|
assert_eq!(len_of_day, LengthOfDaySegment::Long24Bits);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user