165 lines
5.4 KiB
Rust
165 lines
5.4 KiB
Rust
|
#![allow(dead_code)]
|
||
|
use core::mem::size_of;
|
||
|
use serde::{Deserialize, Serialize};
|
||
|
use spacepackets::ecss::{Ptc, RealPfc, UnsignedPfc};
|
||
|
use spacepackets::time::cds::TimeProvider;
|
||
|
use spacepackets::time::{CcsdsTimeProvider, TimeWriter};
|
||
|
|
||
|
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<T> {
|
||
|
valid: bool,
|
||
|
val: T,
|
||
|
}
|
||
|
|
||
|
struct TestMgmHk {
|
||
|
temp: f32,
|
||
|
mgm_vals: [u16; 3],
|
||
|
}
|
||
|
|
||
|
struct TestMgmHkWithIndividualValidity {
|
||
|
temp: ParamWithValidity<f32>,
|
||
|
mgm_vals: ParamWithValidity<[u16; 3]>,
|
||
|
}
|
||
|
|
||
|
#[derive(Serialize, Deserialize)]
|
||
|
struct TestMgmHkWithGroupValidity {
|
||
|
last_valid_stamp: TimeProvider,
|
||
|
valid: bool,
|
||
|
temp: f32,
|
||
|
mgm_vals: [u16; 3],
|
||
|
}
|
||
|
|
||
|
impl TestMgmHk {
|
||
|
pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ()> {
|
||
|
let mut curr_idx = 0;
|
||
|
buf[curr_idx..curr_idx + size_of::<f32>()].copy_from_slice(&self.temp.to_be_bytes());
|
||
|
curr_idx += size_of::<f32>();
|
||
|
for val in self.mgm_vals {
|
||
|
buf[curr_idx..curr_idx + size_of::<u16>()].copy_from_slice(&val.to_be_bytes());
|
||
|
curr_idx += size_of::<u16>();
|
||
|
}
|
||
|
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<usize, ()> {
|
||
|
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::<f32>()].copy_from_slice(&self.temp.val.to_be_bytes());
|
||
|
curr_idx += size_of::<f32>();
|
||
|
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::<u16>()].copy_from_slice(&val.to_be_bytes());
|
||
|
curr_idx += size_of::<u16>();
|
||
|
}
|
||
|
Ok(curr_idx)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl TestMgmHkWithGroupValidity {
|
||
|
pub fn write_to_be_bytes_self_describing(&self, buf: &mut [u8]) -> Result<usize, ()> {
|
||
|
let mut curr_idx = 0;
|
||
|
buf[curr_idx] = self.valid as u8;
|
||
|
curr_idx += 1;
|
||
|
self.last_valid_stamp
|
||
|
.write_to_bytes(&mut buf[curr_idx..curr_idx + self.last_valid_stamp.len_as_bytes()])
|
||
|
.unwrap();
|
||
|
curr_idx += self.last_valid_stamp.len_as_bytes();
|
||
|
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::<f32>()].copy_from_slice(&self.temp.to_be_bytes());
|
||
|
curr_idx += size_of::<f32>();
|
||
|
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::<u16>()].copy_from_slice(&val.to_be_bytes());
|
||
|
curr_idx += size_of::<u16>();
|
||
|
}
|
||
|
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: TimeProvider::from_now_with_u16_days().unwrap(),
|
||
|
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!(
|
||
|
"JSON string with length {}: {}",
|
||
|
mgm_as_json_str.len(),
|
||
|
mgm_as_json_str
|
||
|
);
|
||
|
}
|