leodos_protocols/network/cfe/
tm.rs1use crate::network::spp::Apid;
4use crate::network::spp::PacketType;
5use crate::network::spp::PrimaryHeader;
6use crate::network::spp::SecondaryHeaderFlag;
7use crate::network::spp::SequenceCount;
8use crate::network::spp::SequenceFlag;
9use crate::network::spp::SpacePacket;
10
11use bon::bon;
12use core::mem::size_of;
13use core::ops::Deref;
14use core::ops::DerefMut;
15use zerocopy::FromBytes;
16use zerocopy::Immutable;
17use zerocopy::IntoBytes;
18use zerocopy::KnownLayout;
19use zerocopy::Unaligned;
20use zerocopy::network_endian::U64;
21
22#[repr(C)]
45#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
46pub struct Telemetry {
47 pub primary: PrimaryHeader,
49 pub secondary: TelemetrySecondaryHeader,
51 pub payload: [u8],
53}
54
55#[repr(C)]
57#[derive(IntoBytes, FromBytes, Unaligned, KnownLayout, Immutable, Default, Copy, Clone, Debug)]
58pub struct TelemetrySecondaryHeader {
59 time: U64,
60 spare: [u8; 2],
61}
62
63pub mod bitmask {
65 pub const TIME_MASK: u64 = 0x0000_FFFF_FFFF_FFFF;
67}
68
69use bitmask::*;
70
71#[derive(Debug, Copy, Clone, Eq, PartialEq)]
73pub enum TelemetryError {
74 BufferTooSmall {
76 required: usize,
78 provided: usize,
80 },
81 InvalidTimeValue,
83 SpacePacketError(crate::network::spp::BuildError),
85 MissingSecondaryHeader,
87 PayloadMismatch,
89 TypeMismatch,
91}
92
93impl Deref for Telemetry {
94 type Target = SpacePacket;
95
96 fn deref(&self) -> &Self::Target {
97 SpacePacket::ref_from_bytes(self.as_bytes())
98 .expect("Telemetry should always be a valid SpacePacket")
99 }
100}
101
102impl DerefMut for Telemetry {
103 fn deref_mut(&mut self) -> &mut Self::Target {
104 SpacePacket::mut_from_bytes(self.as_mut_bytes())
105 .expect("Telemetry should always be a valid SpacePacket")
106 }
107}
108
109impl<'a> TryFrom<&'a SpacePacket> for &'a Telemetry {
110 type Error = TelemetryError;
111
112 fn try_from(sp: &'a SpacePacket) -> Result<Self, Self::Error> {
113 if sp.secondary_header_flag() != SecondaryHeaderFlag::Present {
114 return Err(TelemetryError::MissingSecondaryHeader);
115 }
116
117 let bytes = sp.as_bytes();
118
119 match sp.packet_type() {
120 PacketType::Telecommand => Err(TelemetryError::TypeMismatch),
121 PacketType::Telemetry => {
122 Telemetry::ref_from_bytes(bytes).map_err(|_| TelemetryError::PayloadMismatch)
123 }
124 }
125 }
126}
127
128#[bon]
129impl Telemetry {
130 #[builder]
132 pub fn new<'a>(
133 buffer: &'a mut [u8],
134 apid: Apid,
135 sequence_count: SequenceCount,
136 time: u64,
137 payload_len: usize,
138 ) -> Result<&'a mut Telemetry, TelemetryError> {
139 let sp = SpacePacket::builder()
140 .buffer(buffer)
141 .apid(apid)
142 .sequence_count(sequence_count)
143 .packet_type(PacketType::Telemetry)
144 .secondary_header(SecondaryHeaderFlag::Present)
145 .sequence_flag(SequenceFlag::Unsegmented)
146 .data_len(size_of::<TelemetrySecondaryHeader>() + payload_len)
147 .build()
148 .map_err(TelemetryError::SpacePacketError)?;
149
150 let buffer = sp.as_mut_bytes();
151 let provided_len = buffer.len();
152 let required_len = payload_len;
153
154 let tm = Telemetry::mut_from_bytes_with_elems(buffer, required_len).map_err(|_| {
155 TelemetryError::BufferTooSmall {
156 required: required_len,
157 provided: provided_len,
158 }
159 })?;
160
161 tm.set_time(time)?;
162
163 Ok(tm)
164 }
165
166 pub fn time(&self) -> u64 {
168 self.secondary.time.get() & TIME_MASK
169 }
170 pub fn set_time(&mut self, time: u64) -> Result<(), TelemetryError> {
172 if time & !TIME_MASK != 0 {
173 return Err(TelemetryError::InvalidTimeValue);
174 }
175 self.secondary.time.set(time);
176 Ok(())
177 }
178
179 pub fn payload(&self) -> &[u8] {
181 self.payload.as_bytes()
182 }
183 pub fn payload_mut(&mut self) -> &mut [u8] {
185 self.payload.as_mut_bytes()
186 }
187
188 pub fn parse<'a>(bytes: &'a [u8]) -> Result<&'a Telemetry, TelemetryError> {
190 let sp = SpacePacket::ref_from_bytes(bytes).map_err(|_| TelemetryError::PayloadMismatch)?;
191 <&Telemetry>::try_from(sp)
192 }
193}