diff --git a/fsrc-core/src/events.rs b/fsrc-core/src/events.rs index d0ea2f2..eded68e 100644 --- a/fsrc-core/src/events.rs +++ b/fsrc-core/src/events.rs @@ -411,7 +411,7 @@ impl EcssEnumeration for EventU32 { 32 } - fn write_to_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError> { + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError> { self.base.write_to_bytes(self.raw(), buf, self.byte_width()) } } @@ -420,7 +420,7 @@ impl EcssEnumeration for EventU32 { impl EcssEnumeration for EventU32TypedSev { delegate!(to self.event { fn pfc(&self) -> u8; - fn write_to_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError>; + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError>; }); } @@ -542,11 +542,12 @@ impl EventU16TypedSev { impl_event_provider!(EventU16, EventU16TypedSev, u16, u8, u8); impl EcssEnumeration for EventU16 { + #[inline] fn pfc(&self) -> u8 { 16 } - fn write_to_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError> { + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError> { self.base.write_to_bytes(self.raw(), buf, self.byte_width()) } } @@ -555,7 +556,7 @@ impl EcssEnumeration for EventU16 { impl EcssEnumeration for EventU16TypedSev { delegate!(to self.event { fn pfc(&self) -> u8; - fn write_to_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError>; + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError>; }); } @@ -574,6 +575,34 @@ try_from_impls!(SeverityLow, Severity::LOW, u16, EventU16TypedSev); try_from_impls!(SeverityMedium, Severity::MEDIUM, u16, EventU16TypedSev); try_from_impls!(SeverityHigh, Severity::HIGH, u16, EventU16TypedSev); +impl PartialEq for EventU32TypedSev { + #[inline] + fn eq(&self, other: &EventU32) -> bool { + self.raw() == other.raw() + } +} + +impl PartialEq> for EventU32 { + #[inline] + fn eq(&self, other: &EventU32TypedSev) -> bool { + self.raw() == other.raw() + } +} + +impl PartialEq for EventU16TypedSev { + #[inline] + fn eq(&self, other: &EventU16) -> bool { + self.raw() == other.raw() + } +} + +impl PartialEq> for EventU16 { + #[inline] + fn eq(&self, other: &EventU16TypedSev) -> bool { + self.raw() == other.raw() + } +} + #[cfg(test)] mod tests { use super::EventU32TypedSev; @@ -713,7 +742,7 @@ mod tests { #[test] fn write_to_buf() { let mut buf: [u8; 4] = [0; 4]; - assert!(HIGH_SEV_EVENT.write_to_bytes(&mut buf).is_ok()); + assert!(HIGH_SEV_EVENT.write_to_be_bytes(&mut buf).is_ok()); let val_from_raw = u32::from_be_bytes(buf); assert_eq!(val_from_raw, 0xFFFFFFFF); } @@ -721,7 +750,7 @@ mod tests { #[test] fn write_to_buf_small() { let mut buf: [u8; 2] = [0; 2]; - assert!(HIGH_SEV_EVENT_SMALL.write_to_bytes(&mut buf).is_ok()); + assert!(HIGH_SEV_EVENT_SMALL.write_to_be_bytes(&mut buf).is_ok()); let val_from_raw = u16::from_be_bytes(buf); assert_eq!(val_from_raw, 0xFFFF); } @@ -729,7 +758,7 @@ mod tests { #[test] fn write_to_buf_insufficient_buf() { let mut buf: [u8; 3] = [0; 3]; - let err = HIGH_SEV_EVENT.write_to_bytes(&mut buf); + let err = HIGH_SEV_EVENT.write_to_be_bytes(&mut buf); assert!(err.is_err()); let err = err.unwrap_err(); if let ByteConversionError::ToSliceTooSmall(missmatch) = err { @@ -741,7 +770,7 @@ mod tests { #[test] fn write_to_buf_small_insufficient_buf() { let mut buf: [u8; 1] = [0; 1]; - let err = HIGH_SEV_EVENT_SMALL.write_to_bytes(&mut buf); + let err = HIGH_SEV_EVENT_SMALL.write_to_be_bytes(&mut buf); assert!(err.is_err()); let err = err.unwrap_err(); if let ByteConversionError::ToSliceTooSmall(missmatch) = err { diff --git a/fsrc-core/src/pus/event.rs b/fsrc-core/src/pus/event.rs index f7b7e36..a4867e6 100644 --- a/fsrc-core/src/pus/event.rs +++ b/fsrc-core/src/pus/event.rs @@ -152,7 +152,7 @@ impl EventReporterBase { time_stamp, ); let mut current_idx = 0; - event_id.write_to_bytes(&mut buf[0..event_id.byte_width()])?; + event_id.write_to_be_bytes(&mut buf[0..event_id.byte_width()])?; current_idx += event_id.byte_width(); if let Some(aux_data) = aux_data { buf[current_idx..current_idx + aux_data.len()].copy_from_slice(aux_data); diff --git a/fsrc-core/src/pus/verification.rs b/fsrc-core/src/pus/verification.rs index 0908b01..da56f69 100644 --- a/fsrc-core/src/pus/verification.rs +++ b/fsrc-core/src/pus/verification.rs @@ -536,7 +536,7 @@ impl VerificationReporterBasic { idx += RequestId::SIZE_AS_BYTES; if let Some(step) = step { // Size check was done beforehand - step.write_to_bytes(&mut buf[idx..idx + step.byte_width() as usize]) + step.write_to_be_bytes(&mut buf[idx..idx + step.byte_width() as usize]) .unwrap(); } let mut sp_header = SpHeader::tm(self.apid(), 0, 0).unwrap(); @@ -571,13 +571,13 @@ impl VerificationReporterBasic { idx += RequestId::SIZE_AS_BYTES; if let Some(step) = step { // Size check done beforehand - step.write_to_bytes(&mut buf[idx..idx + step.byte_width() as usize]) + step.write_to_be_bytes(&mut buf[idx..idx + step.byte_width() as usize]) .unwrap(); idx += step.byte_width() as usize; } params .failure_code - .write_to_bytes(&mut buf[idx..idx + params.failure_code.byte_width() as usize])?; + .write_to_be_bytes(&mut buf[idx..idx + params.failure_code.byte_width() as usize])?; idx += params.failure_code.byte_width() as usize; if let Some(failure_data) = params.failure_data { buf[idx..idx + failure_data.len()].copy_from_slice(failure_data); @@ -1344,7 +1344,7 @@ mod tests { let fail_code = EcssEnumU8::new(10); let fail_data = EcssEnumU32::new(12); let mut fail_data_raw = [0; 4]; - fail_data.write_to_bytes(&mut fail_data_raw).unwrap(); + fail_data.write_to_be_bytes(&mut fail_data_raw).unwrap(); let fail_params = FailParams::new(&EMPTY_STAMP, &fail_code, Some(fail_data_raw.as_slice())); b.vr.acceptance_failure(tok, &mut sender, fail_params) .expect("Sending acceptance success failed"); diff --git a/fsrc-core/src/util.rs b/fsrc-core/src/util.rs index 27afd18..3967fee 100644 --- a/fsrc-core/src/util.rs +++ b/fsrc-core/src/util.rs @@ -32,7 +32,40 @@ use core::fmt::Debug; use core::mem::size_of; use paste::paste; pub use spacepackets::ecss::ToBeBytes; -use spacepackets::ecss::{EcssEnumU16, EcssEnumU32, EcssEnumU64, EcssEnumU8}; +use spacepackets::ecss::{EcssEnumU16, EcssEnumU32, EcssEnumU64, EcssEnumU8, EcssEnumeration}; +use spacepackets::ByteConversionError; +use spacepackets::SizeMissmatch; + +/// Generic trait which is used for objects which can be converted into a raw network (big) endian +/// byte format. +pub trait WritableAsBeBytes { + fn raw_len(&self) -> usize; + /// Writes the object to a raw buffer in network endianness (big) + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result; +} + +macro_rules! param_to_be_bytes_impl { + ($Newtype: ident) => { + impl WritableAsBeBytes for $Newtype { + #[inline] + fn raw_len(&self) -> usize { + size_of::<::ByteArray>() + } + + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + let raw_len = self.raw_len(); + if buf.len() < raw_len { + return Err(ByteConversionError::ToSliceTooSmall(SizeMissmatch { + found: buf.len(), + expected: raw_len, + })); + } + buf[0..raw_len].copy_from_slice(&self.to_be_bytes()); + Ok(raw_len) + } + } + }; +} macro_rules! primitive_newtypes_with_eq { ($($ty: ty,)+) => { @@ -45,6 +78,10 @@ macro_rules! primitive_newtypes_with_eq { #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct [<$ty:upper Triplet>](pub $ty, pub $ty, pub $ty); + param_to_be_bytes_impl!([<$ty:upper>]); + param_to_be_bytes_impl!([<$ty:upper Pair>]); + param_to_be_bytes_impl!([<$ty:upper Triplet>]); + impl From<$ty> for [<$ty:upper>] { fn from(v: $ty) -> Self { Self(v) @@ -76,6 +113,10 @@ macro_rules! primitive_newtypes { #[derive(Debug, Copy, Clone, PartialEq)] pub struct [<$ty:upper Triplet>](pub $ty, pub $ty, pub $ty); + param_to_be_bytes_impl!([<$ty:upper>]); + param_to_be_bytes_impl!([<$ty:upper Pair>]); + param_to_be_bytes_impl!([<$ty:upper Triplet>]); + impl From<$ty> for [<$ty:upper>] { fn from(v: $ty) -> Self { Self(v) @@ -99,7 +140,7 @@ macro_rules! primitive_newtypes { primitive_newtypes_with_eq!(u8, u16, u32, u64, i8, i16, i32, i64,); primitive_newtypes!(f32, f64,); -macro_rules! scalar_to_be_bytes_impl { +macro_rules! scalar_byte_conversions_impl { ($($ty: ty,)+) => { $( paste! { @@ -109,12 +150,26 @@ macro_rules! scalar_to_be_bytes_impl { self.0.to_be_bytes() } } + + impl TryFrom<&[u8]> for [<$ty:upper>] { + type Error = ByteConversionError; + + fn try_from(v: &[u8]) -> Result { + if v.len() < size_of::<$ty>() { + return Err(ByteConversionError::FromSliceTooSmall(SizeMissmatch { + expected: size_of::<$ty>(), + found: v.len() + })); + } + Ok([<$ty:upper>]($ty::from_be_bytes(v[0..size_of::<$ty>()].try_into().unwrap()))) + } + } } )+ } } -macro_rules! pair_to_be_bytes_impl { +macro_rules! pair_byte_conversions_impl { ($($ty: ty,)+) => { $( paste! { @@ -129,6 +184,23 @@ macro_rules! pair_to_be_bytes_impl { array } } + + impl TryFrom<&[u8]> for [<$ty:upper Pair>] { + type Error = ByteConversionError; + + fn try_from(v: &[u8]) -> Result { + if v.len() < 2 * size_of::<$ty>() { + return Err(ByteConversionError::FromSliceTooSmall(SizeMissmatch { + expected: 2 * size_of::<$ty>(), + found: v.len() + })); + } + Ok([<$ty:upper Pair>]( + $ty::from_be_bytes(v[0..size_of::<$ty>()].try_into().unwrap()), + $ty::from_be_bytes(v[size_of::<$ty>()..2 * size_of::<$ty>()].try_into().unwrap()) + )) + } + } } )+ } @@ -144,20 +216,37 @@ macro_rules! triplet_to_be_bytes_impl { let mut array = [0; size_of::<$ty>() * 3]; array[0..size_of::<$ty>()].copy_from_slice(&self.0.to_be_bytes()); array[ - size_of::<$ty>()..2* size_of::<$ty>() + size_of::<$ty>()..2 * size_of::<$ty>() ].copy_from_slice(&self.1.to_be_bytes()); array[ - 2 * size_of::<$ty>()..3* size_of::<$ty>() + 2 * size_of::<$ty>()..3 * size_of::<$ty>() ].copy_from_slice(&self.2.to_be_bytes()); array } } + impl TryFrom<&[u8]> for [<$ty:upper Triplet>] { + type Error = ByteConversionError; + + fn try_from(v: &[u8]) -> Result { + if v.len() < 3 * size_of::<$ty>() { + return Err(ByteConversionError::FromSliceTooSmall(SizeMissmatch { + expected: 3 * size_of::<$ty>(), + found: v.len() + })); + } + Ok([<$ty:upper Triplet>]( + $ty::from_be_bytes(v[0..size_of::<$ty>()].try_into().unwrap()), + $ty::from_be_bytes(v[size_of::<$ty>()..2 * size_of::<$ty>()].try_into().unwrap()), + $ty::from_be_bytes(v[2 * size_of::<$ty>()..3 * size_of::<$ty>()].try_into().unwrap()) + )) + } + } } )+ } } -scalar_to_be_bytes_impl!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64,); +scalar_byte_conversions_impl!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64,); impl ToBeBytes for U8Pair { type ByteArray = [u8; 2]; @@ -205,7 +294,7 @@ impl ToBeBytes for I8Triplet { } } -pair_to_be_bytes_impl!(u16, u32, u64, i16, i32, i64, f32, f64,); +pair_byte_conversions_impl!(u16, u32, u64, i16, i32, i64, f32, f64,); triplet_to_be_bytes_impl!(u16, u32, u64, i16, i32, i64, f32, f64,); /// Generic enumeration for additonal parameters only consisting of primitive data types. @@ -237,6 +326,66 @@ pub enum ParamsRaw { F64(F64), } +impl WritableAsBeBytes for ParamsRaw { + fn raw_len(&self) -> usize { + match self { + ParamsRaw::U8(v) => v.raw_len(), + ParamsRaw::U8Pair(v) => v.raw_len(), + ParamsRaw::U8Triplet(v) => v.raw_len(), + ParamsRaw::I8(v) => v.raw_len(), + ParamsRaw::I8Pair(v) => v.raw_len(), + ParamsRaw::I8Triplet(v) => v.raw_len(), + ParamsRaw::U16(v) => v.raw_len(), + ParamsRaw::U16Pair(v) => v.raw_len(), + ParamsRaw::U16Triplet(v) => v.raw_len(), + ParamsRaw::I16(v) => v.raw_len(), + ParamsRaw::I16Pair(v) => v.raw_len(), + ParamsRaw::I16Triplet(v) => v.raw_len(), + ParamsRaw::U32(v) => v.raw_len(), + ParamsRaw::U32Pair(v) => v.raw_len(), + ParamsRaw::U32Triplet(v) => v.raw_len(), + ParamsRaw::I32(v) => v.raw_len(), + ParamsRaw::I32Pair(v) => v.raw_len(), + ParamsRaw::I32Triplet(v) => v.raw_len(), + ParamsRaw::F32(v) => v.raw_len(), + ParamsRaw::F32Pair(v) => v.raw_len(), + ParamsRaw::F32Triplet(v) => v.raw_len(), + ParamsRaw::U64(v) => v.raw_len(), + ParamsRaw::I64(v) => v.raw_len(), + ParamsRaw::F64(v) => v.raw_len(), + } + } + + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + match self { + ParamsRaw::U8(v) => v.write_to_be_bytes(buf), + ParamsRaw::U8Pair(v) => v.write_to_be_bytes(buf), + ParamsRaw::U8Triplet(v) => v.write_to_be_bytes(buf), + ParamsRaw::I8(v) => v.write_to_be_bytes(buf), + ParamsRaw::I8Pair(v) => v.write_to_be_bytes(buf), + ParamsRaw::I8Triplet(v) => v.write_to_be_bytes(buf), + ParamsRaw::U16(v) => v.write_to_be_bytes(buf), + ParamsRaw::U16Pair(v) => v.write_to_be_bytes(buf), + ParamsRaw::U16Triplet(v) => v.write_to_be_bytes(buf), + ParamsRaw::I16(v) => v.write_to_be_bytes(buf), + ParamsRaw::I16Pair(v) => v.write_to_be_bytes(buf), + ParamsRaw::I16Triplet(v) => v.write_to_be_bytes(buf), + ParamsRaw::U32(v) => v.write_to_be_bytes(buf), + ParamsRaw::U32Pair(v) => v.write_to_be_bytes(buf), + ParamsRaw::U32Triplet(v) => v.write_to_be_bytes(buf), + ParamsRaw::I32(v) => v.write_to_be_bytes(buf), + ParamsRaw::I32Pair(v) => v.write_to_be_bytes(buf), + ParamsRaw::I32Triplet(v) => v.write_to_be_bytes(buf), + ParamsRaw::F32(v) => v.write_to_be_bytes(buf), + ParamsRaw::F32Pair(v) => v.write_to_be_bytes(buf), + ParamsRaw::F32Triplet(v) => v.write_to_be_bytes(buf), + ParamsRaw::U64(v) => v.write_to_be_bytes(buf), + ParamsRaw::I64(v) => v.write_to_be_bytes(buf), + ParamsRaw::F64(v) => v.write_to_be_bytes(buf), + } + } +} + macro_rules! params_raw_from_newtype { ($($newtype: ident,)+) => { $( @@ -263,6 +412,45 @@ pub enum EcssEnumParams { U64(EcssEnumU64), } +macro_rules! writable_as_be_bytes_ecss_enum_impl { + ($EnumIdent: ident) => { + impl WritableAsBeBytes for $EnumIdent { + fn raw_len(&self) -> usize { + self.byte_width() + } + + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + EcssEnumeration::write_to_be_bytes(self, buf).map(|_| self.byte_width()) + } + } + }; +} + +writable_as_be_bytes_ecss_enum_impl!(EcssEnumU8); +writable_as_be_bytes_ecss_enum_impl!(EcssEnumU16); +writable_as_be_bytes_ecss_enum_impl!(EcssEnumU32); +writable_as_be_bytes_ecss_enum_impl!(EcssEnumU64); + +impl WritableAsBeBytes for EcssEnumParams { + fn raw_len(&self) -> usize { + match self { + EcssEnumParams::U8(e) => e.byte_width(), + EcssEnumParams::U16(e) => e.byte_width(), + EcssEnumParams::U32(e) => e.byte_width(), + EcssEnumParams::U64(e) => e.byte_width(), + } + } + + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + match self { + EcssEnumParams::U8(e) => WritableAsBeBytes::write_to_be_bytes(e, buf), + EcssEnumParams::U16(e) => WritableAsBeBytes::write_to_be_bytes(e, buf), + EcssEnumParams::U32(e) => WritableAsBeBytes::write_to_be_bytes(e, buf), + EcssEnumParams::U64(e) => WritableAsBeBytes::write_to_be_bytes(e, buf), + } + } +} + /// Generic enumeration for parameters which do not rely on heap allocations. #[derive(Debug, Copy, Clone, PartialEq)] pub enum ParamsHeapless { diff --git a/fsrc-core/tests/pus_events.rs b/fsrc-core/tests/pus_events.rs index 058b0f6..9d402e7 100644 --- a/fsrc-core/tests/pus_events.rs +++ b/fsrc-core/tests/pus_events.rs @@ -2,7 +2,9 @@ use fsrc_core::event_man::{EventManager, MpscEventReceiver, MpscEventU32SendProv use fsrc_core::events::{EventU32, EventU32TypedSev, Severity, SeverityInfo}; use fsrc_core::pus::event_man::{DefaultPusMgmtBackendProvider, EventReporter, PusEventTmManager}; use fsrc_core::pus::{EcssTmError, EcssTmSender}; -use fsrc_core::util::Params; +use fsrc_core::util::U32Pair; +use fsrc_core::util::{Params, ParamsHeapless, WritableAsBeBytes}; +use spacepackets::ecss::PusPacket; use spacepackets::tm::PusTm; use std::sync::mpsc::{channel, SendError, TryRecvError}; use std::thread; @@ -42,28 +44,48 @@ fn test_threaded_usage() { // PUS + Generic event manager thread let jh0 = thread::spawn(move || { let mut sender = EventTmSender { sender: event_tx }; + let mut event_cnt = 0; + let mut params_array: [u8; 128] = [0; 128]; loop { let res = event_man.try_event_handling(); assert!(res.is_ok()); match pus_event_man_rx.try_recv() { Ok((event, aux_data)) => { - // TODO: Convert auxiliary data into raw byte format - if let Some(aux_data) = aux_data { + let mut gen_event = |aux_data| { + pus_event_man.generate_pus_event_tm_generic( + &mut sender, + &EMPTY_STAMP, + event, + aux_data, + ) + }; + let res = if let Some(aux_data) = aux_data { match aux_data { - Params::Heapless(_) => {} - Params::Vec(_) => {} - Params::String(_) => {} + Params::Heapless(heapless) => match heapless { + ParamsHeapless::Raw(raw) => { + raw.write_to_be_bytes(&mut params_array) + .expect("Writing raw parameter failed"); + gen_event(Some(¶ms_array[0..raw.raw_len()])) + } + ParamsHeapless::EcssEnum(e) => { + e.write_to_be_bytes(&mut params_array) + .expect("Writing ECSS enum failed"); + gen_event(Some(¶ms_array[0..e.raw_len()])) + } + ParamsHeapless::Store(_) => gen_event(None), + }, + Params::Vec(vec) => gen_event(Some(vec.as_slice())), + Params::String(str) => gen_event(Some(str.as_bytes())), } - } - let res = pus_event_man.generate_pus_event_tm_generic( - &mut sender, - &EMPTY_STAMP, - event, - None, - ); + } else { + gen_event(None) + }; + event_cnt += 1; assert!(res.is_ok()); assert!(res.unwrap()); - break; + if event_cnt == 2 { + break; + } } Err(e) => { if let TryRecvError::Disconnected = e { @@ -82,7 +104,20 @@ fn test_threaded_usage() { loop { match event_rx.try_recv() { // Event TM received successfully - Ok(_) => break, + Ok(event_tm) => { + let tm = + PusTm::from_bytes(event_tm.as_slice(), 7).expect("Deserializing TM failed"); + assert_eq!(tm.0.service(), 5); + assert_eq!(tm.0.subservice(), 1); + let src_data = tm.0.source_data(); + assert!(src_data.is_some()); + let src_data = src_data.unwrap(); + assert_eq!(src_data.len(), 4); + let event = + EventU32::from(u32::from_be_bytes(src_data[0..4].try_into().unwrap())); + assert_eq!(event, INFO_EVENT); + break; + } Err(e) => { if let TryRecvError::Disconnected = e { panic!("Event sender disconnected!") @@ -99,7 +134,24 @@ fn test_threaded_usage() { loop { match event_rx.try_recv() { // Event TM received successfully - Ok(_) => break, + Ok(event_tm) => { + let tm = + PusTm::from_bytes(event_tm.as_slice(), 7).expect("Deserializing TM failed"); + assert_eq!(tm.0.service(), 5); + assert_eq!(tm.0.subservice(), 2); + let src_data = tm.0.source_data(); + assert!(src_data.is_some()); + let src_data = src_data.unwrap(); + assert_eq!(src_data.len(), 12); + let event = + EventU32::from(u32::from_be_bytes(src_data[0..4].try_into().unwrap())); + assert_eq!(event, LOW_SEV_EVENT); + let u32_pair: U32Pair = + src_data[4..].try_into().expect("Creating U32Pair failed"); + assert_eq!(u32_pair.0, 2); + assert_eq!(u32_pair.1, 3); + break; + } Err(e) => { if let TryRecvError::Disconnected = e { panic!("Event sender disconnected!") diff --git a/spacepackets b/spacepackets index 38b789c..f8199ca 160000 --- a/spacepackets +++ b/spacepackets @@ -1 +1 @@ -Subproject commit 38b789ca6d061239e6cecc76f0843d6ba8b9bd01 +Subproject commit f8199ca87a8fc97a51d09bf8bfa57627cd54f74d