diff --git a/Cargo.lock b/Cargo.lock index b783648..78cdaf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -567,6 +567,7 @@ dependencies = [ "paste", "postcard", "serde", + "serde_json", "spacepackets", "zerocopy", ] diff --git a/satrs-core/Cargo.toml b/satrs-core/Cargo.toml index 9969718..4918158 100644 --- a/satrs-core/Cargo.toml +++ b/satrs-core/Cargo.toml @@ -40,6 +40,7 @@ path = "../spacepackets" serde = "1.0" zerocopy = "0.6" once_cell = "1.13" +serde_json = "1" [dev-dependencies.postcard] version = "1.0" diff --git a/satrs-core/tests/hk_helpers.rs b/satrs-core/tests/hk_helpers.rs new file mode 100644 index 0000000..9a30368 --- /dev/null +++ b/satrs-core/tests/hk_helpers.rs @@ -0,0 +1,157 @@ +#![allow(dead_code)] +use core::mem::size_of; +use serde::{Deserialize, Serialize}; +use spacepackets::ecss::{Ptc, RealPfc, UnsignedPfc}; + +enum NumOfParamsInfo { + /// The parameter entry is a scalar field + Scalar = 0b00, + /// The parameter entry is a vector, and its length field is one byte wide (max. 255 entries) + VecLenFieldOneByte = 0b01, + /// The parameter entry is a vecotr, and its length field is two bytes wide (max. 65565 entries) + VecLenFieldTwoBytes = 0b10, + /// The parameter entry is a matrix, and its length field contains a one byte row number + /// and a one byte column number. + MatrixRowsAndColumns = 0b11, +} + +const HAS_VALIDITY_MASK: u8 = 1 << 7; + +struct ParamWithValidity { + valid: bool, + val: T, +} + +struct TestMgmHk { + temp: f32, + mgm_vals: [u16; 3], +} + +struct TestMgmHkWithIndividualValidity { + temp: ParamWithValidity, + mgm_vals: ParamWithValidity<[u16; 3]>, +} + +#[derive(Serialize, Deserialize)] +struct TestMgmHkWithGroupValidity { + last_valid_stamp: [u8; 7], + valid: bool, + temp: f32, + mgm_vals: [u16; 3], +} + +impl TestMgmHk { + pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + let mut curr_idx = 0; + buf[curr_idx..curr_idx + size_of::()].copy_from_slice(&self.temp.to_be_bytes()); + curr_idx += size_of::(); + for val in self.mgm_vals { + buf[curr_idx..curr_idx + size_of::()].copy_from_slice(&val.to_be_bytes()); + curr_idx += size_of::(); + } + Ok(curr_idx) + } +} + +/// This could in principle be auto-generated. +impl TestMgmHkWithIndividualValidity { + pub fn write_to_be_bytes_self_describing(&self, buf: &mut [u8]) -> Result { + let mut curr_idx = 0; + buf[curr_idx] = 0; + buf[curr_idx] |= HAS_VALIDITY_MASK | (self.temp.valid as u8) << 6; + curr_idx += 1; + buf[curr_idx] = Ptc::Real as u8; + curr_idx += 1; + buf[curr_idx] = RealPfc::Float as u8; + curr_idx += 1; + buf[curr_idx..curr_idx + size_of::()].copy_from_slice(&self.temp.val.to_be_bytes()); + curr_idx += size_of::(); + buf[curr_idx] = 0; + buf[curr_idx] |= HAS_VALIDITY_MASK + | (self.mgm_vals.valid as u8) << 6 + | (NumOfParamsInfo::VecLenFieldOneByte as u8) << 4; + curr_idx += 1; + buf[curr_idx] = Ptc::UnsignedInt as u8; + curr_idx += 1; + buf[curr_idx] = UnsignedPfc::TwoBytes as u8; + curr_idx += 1; + buf[curr_idx] = 3; + curr_idx += 1; + for val in self.mgm_vals.val { + buf[curr_idx..curr_idx + size_of::()].copy_from_slice(&val.to_be_bytes()); + curr_idx += size_of::(); + } + Ok(curr_idx) + } +} + +impl TestMgmHkWithGroupValidity { + pub fn write_to_be_bytes_self_describing(&self, buf: &mut [u8]) -> Result { + let mut curr_idx = 0; + buf[curr_idx] = self.valid as u8; + curr_idx += 1; + buf[curr_idx..curr_idx + self.last_valid_stamp.len()] + .copy_from_slice(&self.last_valid_stamp); + curr_idx += self.last_valid_stamp.len(); + buf[curr_idx] = 0; + curr_idx += 1; + buf[curr_idx] = Ptc::Real as u8; + curr_idx += 1; + buf[curr_idx] = RealPfc::Float as u8; + curr_idx += 1; + buf[curr_idx..curr_idx + size_of::()].copy_from_slice(&self.temp.to_be_bytes()); + curr_idx += size_of::(); + buf[curr_idx] = 0; + buf[curr_idx] |= (NumOfParamsInfo::VecLenFieldOneByte as u8) << 4; + curr_idx += 1; + buf[curr_idx] = Ptc::UnsignedInt as u8; + curr_idx += 1; + buf[curr_idx] = UnsignedPfc::TwoBytes as u8; + curr_idx += 1; + buf[curr_idx] = 3; + for val in self.mgm_vals { + buf[curr_idx..curr_idx + size_of::()].copy_from_slice(&val.to_be_bytes()); + curr_idx += size_of::(); + } + Ok(curr_idx) + } +} + +#[test] +pub fn main() { + let mut raw_buf: [u8; 32] = [0; 32]; + let mgm_hk = TestMgmHk { + temp: 20.0, + mgm_vals: [0x1f1f, 0x2f2f, 0x3f3f], + }; + // 4 byte float + 3 * 2 bytes MGM values + let written = mgm_hk.write_to_be_bytes(&mut raw_buf).unwrap(); + assert_eq!(written, 10); + + let mgm_hk_individual_validity = TestMgmHkWithIndividualValidity { + temp: ParamWithValidity { + valid: true, + val: 20.0, + }, + mgm_vals: ParamWithValidity { + valid: true, + val: [0x1f1f, 0x2f2f, 0x3f3f], + }, + }; + let written = mgm_hk_individual_validity + .write_to_be_bytes_self_describing(&mut raw_buf) + .unwrap(); + // 3 byte float description, 4 byte float, 4 byte MGM val description, 3 * 2 bytes MGM values + assert_eq!(written, 17); + + // The easiest and probably best approach, trading off big advantages for TM downlink capacity: + // Use a JSON format + let mgm_hk_group_validity = TestMgmHkWithGroupValidity { + last_valid_stamp: [0; 7], + valid: false, + temp: 20.0, + mgm_vals: [0x1f1f, 0x2f2f, 0x3f3f], + }; + let mgm_as_json_str = serde_json::to_string(&mgm_hk_group_validity).unwrap(); + println!("{}", mgm_as_json_str); +} diff --git a/spacepackets b/spacepackets index fc05eaa..251fcdd 160000 --- a/spacepackets +++ b/spacepackets @@ -1 +1 @@ -Subproject commit fc05eaa925059a23ab0c9d2f0be50105ae969d48 +Subproject commit 251fcdd6c8d366484e10fb9480925f0160d569ff