Simplify low level PUS API #145

Merged
muellerr merged 1 commits from simplify-low-level-pus-api into main 2024-03-29 23:41:14 +01:00
18 changed files with 547 additions and 736 deletions
Showing only changes of commit a5941751d7 - Show all commits

View File

@ -25,7 +25,7 @@ path = "../satrs"
[dependencies.satrs-mib]
version = "0.1.1"
# path = "../satrs-mib"
path = "../satrs-mib"
[features]
dyn_tmtc = []

View File

@ -9,7 +9,7 @@ use satrs::{
hk::HkRequest,
spacepackets::{
ecss::tm::{PusTmCreator, PusTmSecondaryHeader},
time::cds::{DaysLen16Bits, TimeProvider},
time::cds::{CdsTime, DaysLen16Bits},
SequenceFlags, SpHeader,
},
};
@ -23,7 +23,7 @@ use crate::{
pub struct AcsTask<VerificationReporter: VerificationReportingProvider> {
timestamp: [u8; 7],
time_provider: TimeProvider<DaysLen16Bits>,
time_provider: CdsTime<DaysLen16Bits>,
verif_reporter: VerificationReporter,
tm_sender: Box<dyn EcssTmSender>,
request_rx: mpsc::Receiver<RequestWithToken>,
@ -37,7 +37,7 @@ impl<VerificationReporter: VerificationReportingProvider> AcsTask<VerificationRe
) -> Self {
Self {
timestamp: [0; 7],
time_provider: TimeProvider::new_with_u16_days(0, 0),
time_provider: CdsTime::new_with_u16_days(0, 0),
verif_reporter,
tm_sender: Box::new(tm_sender),
request_rx,

View File

@ -14,7 +14,7 @@ use satrs::{
verification::{TcStateStarted, VerificationReportingProvider, VerificationToken},
EcssTmSender,
},
spacepackets::time::cds::{self, TimeProvider},
spacepackets::time::cds::{self, CdsTime},
};
use satrs_example::config::PUS_APID;
@ -25,7 +25,7 @@ pub struct PusEventHandler<VerificationReporter: VerificationReportingProvider>
pus_event_dispatcher: DefaultPusEventU32Dispatcher<()>,
pus_event_man_rx: mpsc::Receiver<(EventU32, Option<Params>)>,
tm_sender: Box<dyn EcssTmSender>,
time_provider: TimeProvider,
time_provider: CdsTime,
timestamp: [u8; 7],
verif_handler: VerificationReporter,
}
@ -57,7 +57,7 @@ impl<VerificationReporter: VerificationReportingProvider> PusEventHandler<Verifi
event_request_rx,
pus_event_dispatcher,
pus_event_man_rx,
time_provider: cds::TimeProvider::new_with_u16_days(0, 0),
time_provider: cds::CdsTime::new_with_u16_days(0, 0),
timestamp: [0; 7],
verif_handler,
tm_sender: Box::new(tm_sender),

View File

@ -45,7 +45,7 @@ use crate::udp::{StaticUdpTmHandler, UdpTmtcServer};
use satrs::pus::event_man::EventRequestWithToken;
use satrs::pus::verification::{VerificationReporterCfg, VerificationReporterWithSender};
use satrs::pus::{EcssTmSender, TmAsVecSenderWithId, TmInSharedPoolSenderWithId};
use satrs::spacepackets::{time::cds::TimeProvider, time::TimeWriter};
use satrs::spacepackets::{time::cds::CdsTime, time::TimeWriter};
use satrs::tmtc::CcsdsDistributor;
use satrs::ChannelId;
use std::net::{IpAddr, SocketAddr};
@ -513,7 +513,7 @@ fn main() {
dyn_tmtc_pool_main();
}
pub fn update_time(time_provider: &mut TimeProvider, timestamp: &mut [u8]) {
pub fn update_time(time_provider: &mut CdsTime, timestamp: &mut [u8]) {
time_provider
.update_from_now()
.expect("Could not get current time");

View File

@ -6,7 +6,7 @@ use satrs::pus::{
};
use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::PusServiceId;
use satrs::spacepackets::time::cds::TimeProvider;
use satrs::spacepackets::time::cds::CdsTime;
use satrs::spacepackets::time::TimeWriter;
use satrs_example::config::{tmtc_err, CustomPusServiceId};
use std::sync::mpsc::Sender;
@ -33,14 +33,14 @@ pub struct PusReceiver<VerificationReporter: VerificationReportingProvider> {
}
struct TimeStampHelper {
stamper: TimeProvider,
stamper: CdsTime,
time_stamp: [u8; 7],
}
impl TimeStampHelper {
pub fn new() -> Self {
Self {
stamper: TimeProvider::new_with_u16_days(0, 0),
stamper: CdsTime::new_with_u16_days(0, 0),
time_stamp: [0; 7],
}
}

View File

@ -14,7 +14,7 @@ use satrs::pus::{
};
use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::PusPacket;
use satrs::spacepackets::time::cds::TimeProvider;
use satrs::spacepackets::time::cds::CdsTime;
use satrs::spacepackets::time::TimeWriter;
use satrs::tmtc::tm_helper::SharedTmPool;
use satrs::ChannelId;
@ -139,7 +139,7 @@ impl<
.tc_slice_raw(),
)
.unwrap();
let time_stamper = TimeProvider::from_now_with_u16_days().unwrap();
let time_stamper = CdsTime::now_with_u16_days().unwrap();
let mut stamp_buf: [u8; 7] = [0; 7];
time_stamper.write_to_bytes(&mut stamp_buf).unwrap();
if subservice == 128 {

View File

@ -23,6 +23,7 @@ version = "1"
optional = true
[dependencies.satrs-shared]
path = "../satrs-shared"
version = "0.1.2"
features = ["serde"]

View File

@ -26,7 +26,10 @@ features = ["full"]
[dev-dependencies]
trybuild = { version = "1", features = ["diff"] }
satrs-shared = "0.1.2"
[dev-dependencies.satrs-shared]
version = "0.1.2"
path = "../../satrs-shared"
[dev-dependencies.satrs-mib]
path = ".."

View File

@ -18,7 +18,9 @@ default-features = false
optional = true
[dependencies.spacepackets]
version = "0.10"
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git"
version = "0.11.0-rc.0"
branch = "main"
default-features = false
[features]

View File

@ -17,7 +17,10 @@ delegate = ">0.7, <=0.10"
paste = "1"
smallvec = "1"
crc = "3"
satrs-shared = "0.1.2"
[dependencies.satrs-shared]
version = "0.1.2"
path = "../satrs-shared"
[dependencies.num_enum]
version = ">0.5, <=0.7"
@ -68,7 +71,9 @@ features = ["all"]
optional = true
[dependencies.spacepackets]
version = "0.10"
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git"
version = "0.11.0-rc.0"
branch = "main"
default-features = false
[dependencies.cobs]

View File

@ -2,6 +2,7 @@ use crate::pus::{source_buffer_large_enough, EcssTmtcError};
use spacepackets::ecss::tm::PusTmCreator;
use spacepackets::ecss::tm::PusTmSecondaryHeader;
use spacepackets::ecss::{EcssEnumeration, PusError};
use spacepackets::ByteConversionError;
use spacepackets::{SpHeader, MAX_APID};
use crate::pus::EcssTmSenderCore;
@ -9,145 +10,125 @@ use crate::pus::EcssTmSenderCore;
pub use alloc_mod::EventReporter;
pub use spacepackets::ecss::event::*;
pub struct EventReporterBase {
msg_count: u16,
pub struct EventReportCreator {
apid: u16,
pub dest_id: u16,
}
impl EventReporterBase {
impl EventReportCreator {
pub fn new(apid: u16) -> Option<Self> {
if apid > MAX_APID {
return None;
}
Some(Self {
msg_count: 0,
// msg_count: 0,
dest_id: 0,
apid,
})
}
pub fn event_info(
pub fn event_info<'time, 'src_data>(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
src_data_buf: &'src_data mut [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm(
buf,
src_data_buf,
Subservice::TmInfoReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_low_severity(
pub fn event_low_severity<'time, 'src_data>(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
src_data_buf: &'src_data mut [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm(
buf,
src_data_buf,
Subservice::TmLowSeverityReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_medium_severity(
pub fn event_medium_severity<'time, 'src_data>(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
buf: &'src_data mut [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm(
buf,
Subservice::TmMediumSeverityReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_high_severity(
pub fn event_high_severity<'time, 'src_data>(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
src_data_buf: &'src_data mut [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm(
buf,
src_data_buf,
Subservice::TmHighSeverityReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
fn generate_and_send_generic_tm(
fn generate_and_send_generic_tm<'time, 'src_data>(
&mut self,
buf: &mut [u8],
src_data_buf: &'src_data mut [u8],
subservice: Subservice,
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
let tm = self.generate_generic_event_tm(buf, subservice, time_stamp, event_id, aux_data)?;
sender.send_tm(tm.into())?;
self.msg_count += 1;
Ok(())
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_generic_event_tm(src_data_buf, subservice, time_stamp, event_id, aux_data)
}
fn generate_generic_event_tm<'a>(
&'a self,
buf: &'a mut [u8],
fn generate_generic_event_tm<'time, 'src_data>(
&self,
src_data_buf: &'src_data mut [u8],
subservice: Subservice,
time_stamp: &'a [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<PusTmCreator, EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
let mut src_data_len = event_id.size();
if let Some(aux_data) = aux_data {
src_data_len += aux_data.len();
}
source_buffer_large_enough(buf.len(), src_data_len)?;
source_buffer_large_enough(src_data_buf.len(), src_data_len)?;
let mut sp_header = SpHeader::tm_unseg(self.apid, 0, 0).unwrap();
let sec_header = PusTmSecondaryHeader::new(
5,
subservice.into(),
self.msg_count,
self.dest_id,
Some(time_stamp),
);
let sec_header =
PusTmSecondaryHeader::new(5, subservice.into(), 0, self.dest_id, Some(time_stamp));
let mut current_idx = 0;
event_id
.write_to_be_bytes(&mut buf[0..event_id.size()])
.map_err(PusError::ByteConversion)?;
event_id.write_to_be_bytes(&mut src_data_buf[0..event_id.size()])?;
current_idx += event_id.size();
if let Some(aux_data) = aux_data {
buf[current_idx..current_idx + aux_data.len()].copy_from_slice(aux_data);
src_data_buf[current_idx..current_idx + aux_data.len()].copy_from_slice(aux_data);
current_idx += aux_data.len();
}
Ok(PusTmCreator::new(
&mut sp_header,
sec_header,
&buf[0..current_idx],
&src_data_buf[0..current_idx],
true,
))
}
@ -161,12 +142,12 @@ mod alloc_mod {
pub struct EventReporter {
source_data_buf: Vec<u8>,
pub reporter: EventReporterBase,
pub reporter: EventReportCreator,
}
impl EventReporter {
pub fn new(apid: u16, max_event_id_and_aux_data_size: usize) -> Option<Self> {
let reporter = EventReporterBase::new(apid)?;
let reporter = EventReportCreator::new(apid)?;
Some(Self {
source_data_buf: vec![0; max_event_id_and_aux_data_size],
reporter,
@ -179,13 +160,17 @@ mod alloc_mod {
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
self.reporter.event_info(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
let tm_creator = self
.reporter
.event_info(
self.source_data_buf.as_mut_slice(),
time_stamp,
event_id,
aux_data,
)
.map_err(PusError::ByteConversion)?;
sender.send_tm(tm_creator.into())?;
Ok(())
}
pub fn event_low_severity(
@ -195,13 +180,17 @@ mod alloc_mod {
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
self.reporter.event_low_severity(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
let tm_creator = self
.reporter
.event_low_severity(
self.source_data_buf.as_mut_slice(),
time_stamp,
event_id,
aux_data,
)
.map_err(PusError::ByteConversion)?;
sender.send_tm(tm_creator.into())?;
Ok(())
}
pub fn event_medium_severity(
@ -211,13 +200,17 @@ mod alloc_mod {
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
self.reporter.event_medium_severity(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
let tm_creator = self
.reporter
.event_medium_severity(
self.source_data_buf.as_mut_slice(),
time_stamp,
event_id,
aux_data,
)
.map_err(PusError::ByteConversion)?;
sender.send_tm(tm_creator.into())?;
Ok(())
}
pub fn event_high_severity(
@ -227,13 +220,17 @@ mod alloc_mod {
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
self.reporter.event_high_severity(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
let tm_creator = self
.reporter
.event_high_severity(
self.source_data_buf.as_mut_slice(),
time_stamp,
event_id,
aux_data,
)
.map_err(PusError::ByteConversion)?;
sender.send_tm(tm_creator.into())?;
Ok(())
}
}
}

View File

@ -40,19 +40,19 @@ pub use alloc_mod::*;
pub use std_mod::*;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum PusTmWrapper<'tm> {
pub enum PusTmWrapper<'time, 'src_data> {
InStore(StoreAddr),
Direct(PusTmCreator<'tm>),
Direct(PusTmCreator<'time, 'src_data>),
}
impl From<StoreAddr> for PusTmWrapper<'_> {
impl From<StoreAddr> for PusTmWrapper<'_, '_> {
fn from(value: StoreAddr) -> Self {
Self::InStore(value)
}
}
impl<'tm> From<PusTmCreator<'tm>> for PusTmWrapper<'tm> {
fn from(value: PusTmCreator<'tm>) -> Self {
impl<'time, 'src_data> From<PusTmCreator<'time, 'src_data>> for PusTmWrapper<'time, 'src_data> {
fn from(value: PusTmCreator<'time, 'src_data>) -> Self {
Self::Direct(value)
}
}
@ -380,7 +380,7 @@ pub mod std_mod {
use spacepackets::ecss::tc::PusTcReader;
use spacepackets::ecss::tm::PusTmCreator;
use spacepackets::ecss::{PusError, WritablePusPacket};
use spacepackets::time::cds::TimeProvider;
use spacepackets::time::cds::CdsTime;
use spacepackets::time::StdTimestampError;
use spacepackets::time::TimeWriter;
use std::string::String;
@ -860,8 +860,7 @@ pub mod std_mod {
partial_error: &mut Option<PartialPusHandlingError>,
) -> [u8; 7] {
let mut time_stamp: [u8; 7] = [0; 7];
let time_provider =
TimeProvider::from_now_with_u16_days().map_err(PartialPusHandlingError::Time);
let time_provider = CdsTime::now_with_u16_days().map_err(PartialPusHandlingError::Time);
if let Ok(time_provider) = time_provider {
// Can't fail, we have a buffer with the exact required size.
time_provider.write_to_bytes(&mut time_stamp).unwrap();
@ -981,15 +980,16 @@ pub mod std_mod {
>;
}
pub(crate) fn source_buffer_large_enough(cap: usize, len: usize) -> Result<(), EcssTmtcError> {
pub(crate) fn source_buffer_large_enough(
cap: usize,
len: usize,
) -> Result<(), ByteConversionError> {
if len > cap {
return Err(
PusError::ByteConversion(ByteConversionError::ToSliceTooSmall {
found: cap,
expected: len,
})
.into(),
);
return Err(ByteConversionError::ToSliceTooSmall {
found: cap,
expected: len,
}
.into());
}
Ok(())
}

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ use crate::pool::PoolProvider;
use crate::pus::{PusPacketHandlerResult, PusPacketHandlingError};
use alloc::string::ToString;
use spacepackets::ecss::{scheduling, PusPacket};
use spacepackets::time::cds::TimeProvider;
use spacepackets::time::cds::CdsTime;
/// This is a helper class for [std] environments to handle generic PUS 11 (scheduling service)
/// packets. This handler is able to handle the most important PUS requests for a scheduling
@ -168,7 +168,7 @@ impl<
// let mut pool = self.sched_tc_pool.write().expect("locking pool failed");
self.scheduler
.insert_wrapped_tc::<TimeProvider>(&tc, sched_tc_pool)
.insert_wrapped_tc::<CdsTime>(&tc, sched_tc_pool)
.expect("insertion of activity into pool failed");
self.service_helper
@ -303,7 +303,7 @@ mod tests {
}
impl PusSchedulerProvider for TestScheduler {
type TimeProvider = cds::TimeProvider;
type TimeProvider = cds::CdsTime;
fn reset(
&mut self,
@ -329,7 +329,7 @@ mod tests {
fn insert_unwrapped_and_stored_tc(
&mut self,
_time_stamp: spacepackets::time::UnixTimestamp,
_time_stamp: spacepackets::time::UnixTime,
info: crate::pus::scheduler::TcInfo,
) -> Result<(), crate::pus::scheduler::ScheduleError> {
self.inserted_tcs.push_back(info);
@ -390,7 +390,7 @@ mod tests {
let mut sec_header = PusTcSecondaryHeader::new_simple(17, 1);
let ping_tc = PusTcCreator::new(&mut reply_header, sec_header, &[], true);
let req_id_ping_tc = scheduler::RequestId::from_tc(&ping_tc);
let stamper = cds::TimeProvider::from_now_with_u16_days().expect("time provider failed");
let stamper = cds::CdsTime::now_with_u16_days().expect("time provider failed");
let mut sched_app_data: [u8; 64] = [0; 64];
let mut written_len = stamper.write_to_bytes(&mut sched_app_data).unwrap();
let ping_raw = ping_tc.to_vec().expect("generating raw tc failed");

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@
//! use satrs::tmtc::{ReceivesTc, ReceivesTcCore};
//! use spacepackets::{CcsdsPacket, SpHeader};
//! use spacepackets::ecss::WritablePusPacket;
//! use spacepackets::ecss::tc::{PusTc, PusTcCreator};
//! use spacepackets::ecss::tc::PusTcCreator;
//!
//! #[derive (Default)]
//! struct ConcreteApidHandler {

View File

@ -1,5 +1,5 @@
use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
use spacepackets::time::cds::TimeProvider;
use spacepackets::time::cds::CdsTime;
use spacepackets::time::TimeWriter;
use spacepackets::SpHeader;
@ -66,7 +66,7 @@ impl PusTmWithCdsShortHelper {
source_data: &'a [u8],
seq_count: u16,
) -> PusTmCreator {
let time_stamp = TimeProvider::from_now_with_u16_days().unwrap();
let time_stamp = CdsTime::now_with_u16_days().unwrap();
time_stamp.write_to_bytes(&mut self.cds_short_buf).unwrap();
self.create_pus_tm_common(service, subservice, source_data, seq_count)
}
@ -76,7 +76,7 @@ impl PusTmWithCdsShortHelper {
service: u8,
subservice: u8,
source_data: &'a [u8],
stamper: &TimeProvider,
stamper: &CdsTime,
seq_count: u16,
) -> PusTmCreator {
stamper.write_to_bytes(&mut self.cds_short_buf).unwrap();
@ -98,14 +98,14 @@ impl PusTmWithCdsShortHelper {
#[cfg(test)]
mod tests {
use spacepackets::{ecss::PusPacket, time::cds::TimeProvider, CcsdsPacket};
use spacepackets::{ecss::PusPacket, time::cds::CdsTime, CcsdsPacket};
use super::PusTmWithCdsShortHelper;
#[test]
fn test_helper_with_stamper() {
let mut pus_tm_helper = PusTmWithCdsShortHelper::new(0x123);
let stamper = TimeProvider::new_with_u16_days(0, 0);
let stamper = CdsTime::new_with_u16_days(0, 0);
let tm = pus_tm_helper.create_pus_tm_with_stamper(17, 1, &[1, 2, 3, 4], &stamper, 25);
assert_eq!(tm.service(), 17);
assert_eq!(tm.subservice(), 1);

View File

@ -2,7 +2,7 @@
use core::mem::size_of;
use serde::{Deserialize, Serialize};
use spacepackets::ecss::{PfcReal, PfcUnsigned, Ptc};
use spacepackets::time::cds::TimeProvider;
use spacepackets::time::cds::CdsTime;
use spacepackets::time::{CcsdsTimeProvider, TimeWriter};
enum NumOfParamsInfo {
@ -36,7 +36,7 @@ struct TestMgmHkWithIndividualValidity {
#[derive(Serialize, Deserialize)]
struct TestMgmHkWithGroupValidity {
last_valid_stamp: TimeProvider,
last_valid_stamp: CdsTime,
valid: bool,
temp: f32,
mgm_vals: [u16; 3],
@ -150,7 +150,7 @@ pub fn main() {
// 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(),
last_valid_stamp: CdsTime::now_with_u16_days().unwrap(),
valid: false,
temp: 20.0,
mgm_vals: [0x1f1f, 0x2f2f, 0x3f3f],