leodos_protocols/datalink/reliability/
mod.rs1use cop1::farm::{FarmActions, FarmConfig, FarmEvent, FarmMachine};
8use cop1::fop::{FopActions, FopConfig, FopEvent, FopMachine};
9
10use crate::datalink::framing::sdlp::tc::{BypassFlag, ControlFlag};
11
12pub mod cop1;
14
15pub trait ReliabilityWrite {
17 type Action;
19 fn write(&mut self, frame: &[u8]) -> Self::Action;
21}
22
23pub trait ReliabilityRead {
25 type Action;
27 fn read(&mut self, frame: &[u8]) -> Self::Action;
29}
30
31pub struct Cop1Writer<const WIN: usize, const BUF: usize> {
38 fop: FopMachine<WIN, BUF>,
39}
40
41impl<const WIN: usize, const BUF: usize> Cop1Writer<WIN, BUF> {
42 pub fn new(config: FopConfig) -> Self {
44 Self {
45 fop: FopMachine::new(config),
46 }
47 }
48
49 pub fn fop(&self) -> &FopMachine<WIN, BUF> {
51 &self.fop
52 }
53
54 pub fn fop_mut(&mut self) -> &mut FopMachine<WIN, BUF> {
56 &mut self.fop
57 }
58}
59
60impl<const WIN: usize, const BUF: usize> ReliabilityWrite
61 for Cop1Writer<WIN, BUF>
62{
63 type Action = FopActions;
64
65 fn write(&mut self, frame: &[u8]) -> FopActions {
66 let mut actions = FopActions::new();
67 self.fop
68 .handle(FopEvent::SendAd { fdu: frame }, &mut actions);
69 actions
70 }
71}
72
73#[derive(Debug, Copy, Clone, Eq, PartialEq)]
75pub enum Cop1ReadResult {
76 Accept,
78 Discard,
80}
81
82pub struct Cop1Reader {
91 farm: FarmMachine,
92}
93
94impl Cop1Reader {
95 pub fn new(config: FarmConfig) -> Self {
97 Self {
98 farm: FarmMachine::new(config),
99 }
100 }
101
102 pub fn farm(&self) -> &FarmMachine {
104 &self.farm
105 }
106
107 pub fn farm_mut(&mut self) -> &mut FarmMachine {
109 &mut self.farm
110 }
111}
112
113impl ReliabilityRead for Cop1Reader {
114 type Action = Cop1ReadResult;
115
116 fn read(&mut self, frame: &[u8]) -> Cop1ReadResult {
117 use cop1::farm::FarmAction;
118 use crate::datalink::framing::sdlp::tc::TelecommandTransferFrame;
119
120 let mut actions = FarmActions::new();
121
122 let Ok(tc_frame) = TelecommandTransferFrame::parse(frame)
123 else {
124 self.farm
125 .handle(FarmEvent::InvalidFrame, &mut actions);
126 return Cop1ReadResult::Discard;
127 };
128
129 let bypass = tc_frame.header().bypass_flag();
130 let control = tc_frame.header().control_flag();
131 let seq = tc_frame.header().sequence_num();
132 let fdu = tc_frame.data_field();
133
134 match (bypass, control) {
135 (BypassFlag::TypeA, ControlFlag::TypeD) => {
136 self.farm.handle(
138 FarmEvent::AdFrame {
139 seq,
140 buffer_available: true,
141 fdu,
142 },
143 &mut actions,
144 );
145 }
146 (BypassFlag::TypeB, ControlFlag::TypeD) => {
147 self.farm.handle(
149 FarmEvent::BdFrame { fdu },
150 &mut actions,
151 );
152 }
153 _ => {
154 self.farm
157 .handle(FarmEvent::InvalidFrame, &mut actions);
158 return Cop1ReadResult::Discard;
159 }
160 }
161
162 for action in &actions {
163 if matches!(action, FarmAction::Accept { .. }) {
164 return Cop1ReadResult::Accept;
165 }
166 }
167
168 Cop1ReadResult::Discard
169 }
170}
171
172pub struct NoReliability;
176
177impl ReliabilityWrite for NoReliability {
178 type Action = ();
179
180 fn write(&mut self, _frame: &[u8]) {}
181}
182
183impl ReliabilityRead for NoReliability {
184 type Action = ();
185
186 fn read(&mut self, _frame: &[u8]) {}
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192 use crate::ids::{Scid, Vcid};
193 use cop1::fop::{FopAction, FopState};
194
195 fn fop_config() -> FopConfig {
196 FopConfig::builder()
197 .window_width(4)
198 .transmission_limit(3)
199 .timeout_type(0)
200 .build()
201 }
202
203 fn farm_config() -> FarmConfig {
204 FarmConfig::builder().vcid(Vcid::new(0)).window_width(10).build()
205 }
206
207 #[test]
208 fn cop1_writer_rejects_in_initial_state() {
209 let mut writer: Cop1Writer<8, 1024> =
210 Cop1Writer::new(fop_config());
211
212 let actions = writer.write(&[1, 2, 3]);
213 assert!(actions.iter().any(|a| matches!(a, FopAction::Reject)));
214 }
215
216 #[test]
217 fn cop1_writer_sends_ad_when_active() {
218 let mut writer: Cop1Writer<8, 1024> =
219 Cop1Writer::new(fop_config());
220
221 let mut init_actions = FopActions::new();
222 writer
223 .fop_mut()
224 .handle(FopEvent::InitAdNoClcw, &mut init_actions);
225 assert_eq!(writer.fop().state(), FopState::Active);
226
227 let actions = writer.write(&[0xAA, 0xBB]);
228 assert!(actions
229 .iter()
230 .any(|a| matches!(a, FopAction::TransmitAd { seq: 0 })));
231 }
232
233 #[test]
234 fn cop1_reader_accepts_in_sequence_ad() {
235 let mut reader = Cop1Reader::new(farm_config());
236
237 let mut buf = [0u8; 64];
238 let frame =
239 crate::datalink::framing::sdlp::tc::TelecommandTransferFrame::builder()
240 .buffer(&mut buf)
241 .scid(Scid::new(1))
242 .vcid(Vcid::new(0))
243 .bypass_flag(BypassFlag::TypeA)
244 .control_flag(ControlFlag::TypeD)
245 .seq(0)
246 .data_field_len(4)
247 .build()
248 .unwrap();
249 frame.data_field_mut().copy_from_slice(&[1, 2, 3, 4]);
250 let frame_len = frame.frame_len();
251
252 let result = reader.read(&buf[..frame_len]);
253 assert_eq!(result, Cop1ReadResult::Accept);
254 assert_eq!(reader.farm().vr(), 1);
255 }
256
257 #[test]
258 fn cop1_reader_accepts_bd_frame() {
259 let mut reader = Cop1Reader::new(farm_config());
260
261 let mut buf = [0u8; 64];
262 let frame =
263 crate::datalink::framing::sdlp::tc::TelecommandTransferFrame::builder()
264 .buffer(&mut buf)
265 .scid(Scid::new(1))
266 .vcid(Vcid::new(0))
267 .bypass_flag(BypassFlag::TypeB)
268 .control_flag(ControlFlag::TypeD)
269 .seq(0)
270 .data_field_len(2)
271 .build()
272 .unwrap();
273 frame.data_field_mut().copy_from_slice(&[0xAA, 0xBB]);
274 let frame_len = frame.frame_len();
275
276 let result = reader.read(&buf[..frame_len]);
277 assert_eq!(result, Cop1ReadResult::Accept);
278 }
279
280 #[test]
281 fn no_reliability_passthrough() {
282 let mut writer = NoReliability;
283 let mut reader = NoReliability;
284
285 writer.write(&[1, 2, 3]);
286 reader.read(&[1, 2, 3]);
287 }
288}