leodos_protocols/transport/cfdp/pdu/tlv/
fault_handler_override.rs1use zerocopy::FromBytes;
2use zerocopy::Immutable;
3use zerocopy::IntoBytes;
4use zerocopy::KnownLayout;
5use zerocopy::Unaligned;
6
7use crate::transport::cfdp::pdu::file_directive::ConditionCode;
8use crate::transport::cfdp::CfdpError;
9use crate::utils::get_bits_u8;
10use crate::utils::set_bits_u8;
11
12#[repr(C)]
14#[derive(Copy, Clone, Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
15pub struct TlvFaultHandlerOverride {
16 packed: u8,
18}
19
20#[rustfmt::ignore]
21mod bitmasks {
23 pub const CONDITION_CODE_MASK: u8 = 0b_11110000;
25 pub const HANDLER_CODE_MASK: u8 = 0b_00001111;
27}
28
29use bitmasks::*;
30
31#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
33#[repr(u8)]
34pub enum HandlerCode {
35 #[default]
37 Cancel = 0x01,
38 Suspend = 0x02,
40 Ignore = 0x03,
42 Abandon = 0x04,
44}
45
46impl TryFrom<u8> for HandlerCode {
47 type Error = CfdpError;
48 fn try_from(value: u8) -> Result<Self, Self::Error> {
49 match value {
50 0x01 => Ok(Self::Cancel),
51 0x02 => Ok(Self::Suspend),
52 0x03 => Ok(Self::Ignore),
53 0x04 => Ok(Self::Abandon),
54 _ => Err(CfdpError::Custom("Invalid HandlerCode")),
55 }
56 }
57}
58
59impl TlvFaultHandlerOverride {
60 pub fn condition_code(&self) -> Result<ConditionCode, CfdpError> {
62 get_bits_u8(self.packed, CONDITION_CODE_MASK).try_into()
63 }
64 pub fn set_condition_code(&mut self, code: ConditionCode) {
66 set_bits_u8(&mut self.packed, CONDITION_CODE_MASK, code as u8);
67 }
68
69 pub fn handler_code(&self) -> Result<HandlerCode, CfdpError> {
71 get_bits_u8(self.packed, HANDLER_CODE_MASK).try_into()
72 }
73 pub fn set_handler_code(&mut self, code: HandlerCode) {
75 set_bits_u8(&mut self.packed, HANDLER_CODE_MASK, code as u8);
76 }
77}
78
79#[derive(Debug, Copy, Clone, PartialEq, Eq)]
85pub struct FaultHandlerSet(u32);
86
87impl Default for FaultHandlerSet {
88 fn default() -> Self {
91 let default_handler_bits = handler_to_bits(HandlerCode::default());
92 let mut packed_value = 0u32;
93 for i in 0..16 {
95 let shift = i * 2;
96 packed_value |= default_handler_bits << shift;
97 }
98 Self(packed_value)
99 }
100}
101
102impl FaultHandlerSet {
103 pub fn new(default_handler: HandlerCode) -> Self {
106 let handler_bits = handler_to_bits(default_handler);
107 let mut packed_value = 0u32;
108 for i in 0..16 {
109 let shift = i * 2;
110 packed_value |= handler_bits << shift;
111 }
112 Self(packed_value)
113 }
114
115 pub fn set_handler(&mut self, condition: ConditionCode, handler: HandlerCode) {
117 let condition_index = condition as u8;
119 let shift = condition_index * 2;
120 let handler_bits = handler_to_bits(handler);
121
122 let mask = !(0b11 << shift);
125
126 self.0 &= mask;
128
129 self.0 |= handler_bits << shift;
131 }
132
133 pub fn get_handler(&self, condition: ConditionCode) -> HandlerCode {
135 let condition_index = condition as u8;
136 let shift = condition_index * 2;
137
138 let bits = (self.0 >> shift) & 0b11;
140
141 bits_to_handler(bits)
143 }
144}
145
146const fn handler_to_bits(handler: HandlerCode) -> u32 {
155 match handler {
156 HandlerCode::Cancel => 0b00,
157 HandlerCode::Suspend => 0b01,
158 HandlerCode::Ignore => 0b10,
159 HandlerCode::Abandon => 0b11,
160 }
161}
162
163const fn bits_to_handler(bits: u32) -> HandlerCode {
165 match bits {
166 0b00 => HandlerCode::Cancel,
167 0b01 => HandlerCode::Suspend,
168 0b10 => HandlerCode::Ignore,
169 0b11 => HandlerCode::Abandon,
170 _ => HandlerCode::Cancel,
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn test_fault_handler_set_default() {
181 let set = FaultHandlerSet::default();
182 assert_eq!(
184 set.get_handler(ConditionCode::NoError),
185 HandlerCode::default()
186 );
187 assert_eq!(
188 set.get_handler(ConditionCode::FileChecksumFailure),
189 HandlerCode::default()
190 );
191 assert_eq!(
192 set.get_handler(ConditionCode::CancelReceived),
193 HandlerCode::default()
194 );
195 }
196
197 #[test]
198 fn test_fault_handler_set_and_get() {
199 let mut set = FaultHandlerSet::default();
200
201 assert_eq!(
203 set.get_handler(ConditionCode::FileChecksumFailure),
204 HandlerCode::Cancel
205 );
206
207 set.set_handler(ConditionCode::FileChecksumFailure, HandlerCode::Ignore);
209 assert_eq!(
210 set.get_handler(ConditionCode::FileChecksumFailure),
211 HandlerCode::Ignore
212 );
213
214 assert_eq!(
216 set.get_handler(ConditionCode::NakLimitReached),
217 HandlerCode::Cancel
218 );
219
220 set.set_handler(ConditionCode::NakLimitReached, HandlerCode::Suspend);
222 assert_eq!(
223 set.get_handler(ConditionCode::FileChecksumFailure),
224 HandlerCode::Ignore
225 );
226 assert_eq!(
227 set.get_handler(ConditionCode::NakLimitReached),
228 HandlerCode::Suspend
229 );
230
231 set.set_handler(ConditionCode::FileChecksumFailure, HandlerCode::Abandon);
233 assert_eq!(
234 set.get_handler(ConditionCode::FileChecksumFailure),
235 HandlerCode::Abandon
236 );
237 }
238}