1use crate::error::IsoTpError;
2use crate::isotp::address::IsoTpAddressingMode;
3use crate::isotp::pci::{FlowStatus, PciFrame};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct SegmenterConfig {
10 pub addressing_mode: IsoTpAddressingMode,
11
12 pub max_frame_data_len: usize,
14}
15
16impl SegmenterConfig {
17 pub fn classic(addressing_mode: IsoTpAddressingMode) -> Self {
18 Self {
19 addressing_mode,
20 max_frame_data_len: 8,
21 }
22 }
23
24 pub fn fd(addressing_mode: IsoTpAddressingMode) -> Self {
25 Self {
26 addressing_mode,
27 max_frame_data_len: 64,
28 }
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
37enum SegmenterState {
38 Idle,
39
40 WaitingForFlowControl {
41 next_sequence: u8,
42 sent: usize,
43 },
44
45 Sending {
46 next_sequence: u8,
47 sent: usize,
48 block_remaining: u8,
50 st_min: u8,
51 },
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
60pub enum SegmentResult {
61 Frame { len: usize },
66
67 Complete,
69
70 WaitForFlowControl,
73}
74
75pub struct Segmenter<const N: usize = 4096> {
90 config: SegmenterConfig,
91 payload: heapless::Vec<u8, N>,
92 state: SegmenterState,
93}
94
95impl<const N: usize> Segmenter<N> {
96 pub fn new(config: SegmenterConfig) -> Self {
97 Self {
98 config,
99 payload: heapless::Vec::new(),
100 state: SegmenterState::Idle,
101 }
102 }
103
104 pub fn start(&mut self, payload: &[u8]) -> Result<(), IsoTpError> {
106 if payload.is_empty() {
107 return Err(IsoTpError::InvalidLength);
108 }
109
110 if payload.len() > N {
111 return Err(IsoTpError::PayloadTooLarge);
112 }
113
114 if payload.len() > u32::MAX as usize {
115 return Err(IsoTpError::PayloadTooLarge);
116 }
117
118 self.payload.clear();
119 self.payload
120 .extend_from_slice(payload)
121 .map_err(|_| IsoTpError::PayloadTooLarge)?;
122
123 self.state = SegmenterState::Sending {
124 next_sequence: 1,
125 sent: 0,
126 block_remaining: 0,
127 st_min: 0,
128 };
129
130 Ok(())
131 }
132
133 pub fn reset(&mut self) {
135 self.payload.clear();
136 self.state = SegmenterState::Idle;
137 }
138
139 pub fn handle_flow_control(&mut self, pci_bytes: &[u8]) -> Result<(), IsoTpError> {
144 let pci = PciFrame::parse(pci_bytes)?;
145
146 let (next_sequence, sent) = match &self.state {
147 SegmenterState::WaitingForFlowControl {
148 next_sequence,
149 sent,
150 } => (*next_sequence, *sent),
151 _ => return Err(IsoTpError::UnknownFrameType(0x3)),
152 };
153
154 match pci {
155 PciFrame::FlowControl {
156 status,
157 block_size,
158 st_min,
159 } => match status {
160 FlowStatus::ContinueToSend => {
161 self.state = SegmenterState::Sending {
162 next_sequence,
163 sent,
164 block_remaining: block_size,
165 st_min,
166 };
167 Ok(())
168 }
169 FlowStatus::Wait => Ok(()),
170 FlowStatus::Overflow => {
171 self.reset();
172 Err(IsoTpError::PayloadTooLarge)
173 }
174 },
175 _ => Err(IsoTpError::UnknownFrameType(0x0)),
176 }
177 }
178
179 pub fn next_frame(&mut self, out_buf: &mut [u8]) -> Result<SegmentResult, IsoTpError> {
184 match self.state.clone() {
185 SegmenterState::Idle => Ok(SegmentResult::Complete),
186
187 SegmenterState::WaitingForFlowControl { .. } => Ok(SegmentResult::WaitForFlowControl),
188
189 SegmenterState::Sending {
190 next_sequence,
191 sent,
192 block_remaining,
193 st_min,
194 } => {
195 let total = self.payload.len();
196 let max_data = self.config.max_frame_data_len;
197
198 let max_sf = match max_data {
200 8 => self.config.addressing_mode.max_sf_payload_classic(),
201 _ => self.config.addressing_mode.max_sf_payload_fd(),
202 };
203
204 if sent == 0 && total <= max_sf {
207 let pci = PciFrame::SingleFrame {
208 len: total as u8,
209 data: &self.payload,
210 };
211
212 let pci_len = pci.encode_header(out_buf)?;
213 let end = pci_len + total;
214
215 if out_buf.len() < end {
216 return Err(IsoTpError::FrameTooShort {
217 actual: out_buf.len(),
218 });
219 }
220 out_buf[pci_len..end].copy_from_slice(&self.payload);
221
222 self.state = SegmenterState::Idle;
223
224 return Ok(SegmentResult::Frame { len: end });
225 }
226
227 if sent == 0 {
232 let pci = PciFrame::FirstFrame {
233 total_len: total as u32,
234 data: &self.payload,
235 };
236
237 let pci_len = pci.encode_header(out_buf)?;
238 let data_in_ff = (max_data - pci_len).min(total);
239 let end = pci_len + data_in_ff;
240
241 if out_buf.len() < end {
242 return Err(IsoTpError::FrameTooShort {
243 actual: out_buf.len(),
244 });
245 }
246 out_buf[pci_len..end].copy_from_slice(&self.payload[..data_in_ff]);
247
248 self.state = SegmenterState::WaitingForFlowControl {
249 next_sequence: 1,
250 sent: data_in_ff,
251 };
252
253 return Ok(SegmentResult::Frame { len: end });
254 }
255
256 let remaining = &self.payload[sent..];
261 let pci = PciFrame::ConsecutiveFrame {
262 sequence_number: next_sequence,
263 data: remaining,
264 };
265
266 let pci_len = pci.encode_header(out_buf)?;
267 let data_in_cf = (max_data - pci_len).min(remaining.len());
268 let end = pci_len + data_in_cf;
269
270 if out_buf.len() < end {
271 return Err(IsoTpError::FrameTooShort {
272 actual: out_buf.len(),
273 });
274 }
275
276 out_buf[pci_len..end].copy_from_slice(&remaining[..data_in_cf]);
277
278 let new_sent = sent + data_in_cf;
279 let new_sequence = (next_sequence + 1) & 0x0F;
280
281 if new_sent >= total {
282 self.state = SegmenterState::Idle;
283 return Ok(SegmentResult::Frame { len: end });
284 }
285
286 let new_block = if block_remaining == 0 {
287 0
288 } else if block_remaining == 1 {
289 self.state = SegmenterState::WaitingForFlowControl {
290 next_sequence: new_sequence,
291 sent: new_sent,
292 };
293 return Ok(SegmentResult::Frame { len: end });
294 } else {
295 block_remaining - 1
296 };
297
298 self.state = SegmenterState::Sending {
299 next_sequence: new_sequence,
300 sent: new_sent,
301 block_remaining: new_block,
302 st_min,
303 };
304
305 Ok(SegmentResult::Frame { len: end })
306
307 }
309 }
310 }
311}
312
313