leodos_protocols/network/isl/routing/
packet.rs1use crate::network::cfe::tc::Telecommand;
8use crate::network::cfe::tc::TelecommandError;
9use crate::network::cfe::tc::TelecommandSecondaryHeader;
10use crate::network::isl::address::Address;
11use crate::network::isl::address::RawAddress;
12use crate::network::spp::Apid;
13use crate::network::spp::PrimaryHeader;
14use crate::network::spp::SequenceCount;
15use crate::utils::checksum_u8;
16use crate::utils::validate_checksum_u8;
17use bon::bon;
18use core::mem::size_of;
19use zerocopy::FromBytes;
20use zerocopy::Immutable;
21use zerocopy::IntoBytes;
22use zerocopy::KnownLayout;
23use zerocopy::Unaligned;
24
25#[repr(C, packed)]
51#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable)]
52pub struct IslRoutingTelecommand {
53 pub primary: PrimaryHeader,
55 pub secondary: TelecommandSecondaryHeader,
57 pub(crate) isl_header: IslRoutingTelecommandHeader,
58 pub payload: [u8],
60}
61
62#[repr(C, packed)]
65#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, Copy, Clone, Debug)]
66pub(crate) struct IslRoutingTelecommandHeader {
67 target: RawAddress,
68}
69
70#[derive(Debug, Copy, Clone, Eq, PartialEq, thiserror::Error)]
72pub enum IslMessageError {
73 #[error("CFE Telecommand error: {0}")]
75 Cfe(#[from] TelecommandError),
76 #[error("ISL message payload is too small to contain a valid ISL header")]
79 PayloadTooSmall,
80 #[error("ISL message payload size {provided} exceeds maximum allowed {max}")]
82 PayloadTooLarge {
83 max: usize,
85 provided: usize,
87 },
88}
89
90impl IslRoutingTelecommandHeader {
91 pub fn target(&self) -> Address {
92 self.target.parse()
93 }
94
95 pub fn set_target(&mut self, target: Address) {
96 self.target = RawAddress::from(target);
97 }
98}
99
100#[bon]
101impl IslRoutingTelecommand {
102 #[builder]
104 pub fn new<'a>(
105 buffer: &'a mut [u8],
106 apid: Apid,
107 function_code: u8,
108 target: Address,
109 payload_len: usize,
110 ) -> Result<&'a mut Self, IslMessageError> {
111 let tc = Telecommand::builder()
112 .buffer(buffer)
113 .apid(apid)
114 .sequence_count(SequenceCount::new())
115 .function_code(function_code)
116 .payload_len(size_of::<IslRoutingTelecommandHeader>() + payload_len)
117 .build()
118 .map_err(IslMessageError::Cfe)?;
119
120 let buffer = tc.as_mut_bytes();
121 let provided_len = buffer.len();
122 let isl_tc = Self::mut_from_bytes_with_elems(buffer, payload_len).map_err(|_| {
123 TelecommandError::BufferTooSmall {
124 required_len: size_of::<PrimaryHeader>()
125 + size_of::<TelecommandSecondaryHeader>()
126 + size_of::<IslRoutingTelecommandHeader>()
127 + payload_len,
128 provided_len,
129 }
130 })?;
131
132 isl_tc.isl_header.set_target(target);
133
134 isl_tc.set_cfe_checksum();
135
136 Ok(isl_tc)
137 }
138}
139
140impl IslRoutingTelecommand {
141 pub fn set_cfe_checksum(&mut self) {
146 self.secondary.set_checksum(0);
147 self.secondary.set_checksum(checksum_u8(self.as_bytes()));
148 }
149
150 pub fn validate_cfe_checksum(&self) -> bool {
154 validate_checksum_u8(self.as_bytes())
155 }
156
157 pub fn from_telecommand(tc: &Telecommand) -> Result<&Self, IslMessageError> {
159 if tc.payload().len() < size_of::<IslRoutingTelecommandHeader>() {
160 return Err(IslMessageError::PayloadTooSmall);
161 }
162 Ok(Self::ref_from_bytes(tc.as_bytes()).unwrap())
164 }
165
166 pub fn as_telecommand(&self) -> &Telecommand {
168 Telecommand::ref_from_bytes(self.as_bytes()).unwrap()
169 }
170
171 pub fn payload(&self) -> &[u8] {
173 &self.payload
174 }
175
176 pub fn payload_mut(&mut self) -> &mut [u8] {
178 &mut self.payload
179 }
180
181 pub fn target(&self) -> Address {
184 self.isl_header.target()
185 }
186
187 pub fn apid(&self) -> Apid {
189 self.primary.apid()
190 }
191
192 pub fn parse<'a>(bytes: &'a [u8]) -> Result<&'a IslRoutingTelecommand, IslMessageError> {
194 let tc = Telecommand::parse(bytes).map_err(IslMessageError::Cfe)?;
195 Self::from_telecommand(tc)
196 }
197}