ace_can/isotp/
reassembler.rs1use crate::constants::NIBBLE_MASK;
2use crate::error::IsoTpError;
3use crate::isotp::address::IsoTpAddressingMode;
4use crate::isotp::pci::{FlowStatus, PciFrame};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct ReassemblerConfig {
11 pub addressing_mode: IsoTpAddressingMode,
12 pub block_size: u8,
15 pub st_min: u8,
17}
18
19impl ReassemblerConfig {
20 pub fn new(addressing_mode: IsoTpAddressingMode) -> Self {
21 Self {
22 addressing_mode,
23 block_size: 0,
24 st_min: 0,
25 }
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq)]
34enum ReassemblerState {
35 Idle,
36 Active {
37 total_len: u32,
38 received: usize,
39 next_sequence: u8,
40 },
41}
42
43#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum ReassembleResult {
50 InProgress,
52 Complete { len: usize },
54 FlowControl { frame: [u8; 3], len: usize },
60 SessionAborted {
63 flow_control: [u8; 3],
64 fc_len: usize,
65 },
66}
67
68pub struct Reassembler<const N: usize> {
82 config: ReassemblerConfig,
83 buf: [u8; N],
84 state: ReassemblerState,
85}
86
87impl<const N: usize> Reassembler<N> {
88 pub fn new(config: ReassemblerConfig) -> Self {
89 Self {
90 config,
91 buf: [0u8; N],
92 state: ReassemblerState::Idle,
93 }
94 }
95
96 pub fn reset(&mut self) {
98 self.state = ReassemblerState::Idle;
99 }
100
101 pub fn message(&self, len: usize) -> Option<&[u8]> {
104 match &self.state {
105 ReassemblerState::Idle => Some(&self.buf[..len]),
106 ReassemblerState::Active { .. } => None,
107 }
108 }
109
110 pub fn feed(&mut self, pci_bytes: &[u8]) -> Result<ReassembleResult, IsoTpError> {
115 let pci = PciFrame::parse(pci_bytes)?;
116
117 match pci {
118 PciFrame::SingleFrame { len, data } => {
120 let len = len as usize;
121 if len == 0 {
122 return Err(IsoTpError::EmptySingleFrame);
123 }
124 if len > N {
125 return Err(IsoTpError::PayloadTooLarge);
126 }
127 let copy_len = data.len().min(len).min(N);
128 self.buf[..copy_len].copy_from_slice(&data[..copy_len]);
129 self.state = ReassemblerState::Idle;
130 Ok(ReassembleResult::Complete { len })
131 }
132 PciFrame::FirstFrame { total_len, data } => {
136 let total = total_len as usize;
137 if total == 0 {
138 return Err(IsoTpError::InvalidLength);
139 }
140 if total > N {
141 return Err(IsoTpError::PayloadTooLarge);
142 }
143
144 let was_active = matches!(self.state, ReassemblerState::Active { .. });
145
146 let copy_len = data.len().min(total).min(N);
147 self.buf[..copy_len].copy_from_slice(&data[..copy_len]);
148
149 self.state = ReassemblerState::Active {
150 total_len,
151 received: copy_len,
152 next_sequence: 1,
153 };
154
155 let fc_pci = PciFrame::FlowControl {
156 status: FlowStatus::ContinueToSend,
157 block_size: self.config.block_size,
158 st_min: self.config.st_min,
159 };
160 let mut fc_buf = [0u8; 3];
161 fc_pci.encode_header(&mut fc_buf)?;
162
163 if was_active {
164 Ok(ReassembleResult::SessionAborted {
165 flow_control: fc_buf,
166 fc_len: 3,
167 })
168 } else {
169 Ok(ReassembleResult::FlowControl {
170 frame: fc_buf,
171 len: 3,
172 })
173 }
174 }
175 PciFrame::ConsecutiveFrame {
179 sequence_number,
180 data,
181 } => {
182 let (total_len, received, next_sequence) = match &self.state {
183 ReassemblerState::Active {
184 total_len,
185 received,
186 next_sequence,
187 } => (*total_len, *received, *next_sequence),
188 ReassemblerState::Idle => return Err(IsoTpError::UnexpectedConsecutiveFrame),
189 };
190
191 if sequence_number != next_sequence {
192 self.reset();
193 return Err(IsoTpError::SequenceError {
194 expected: next_sequence,
195 actual: sequence_number,
196 });
197 }
198
199 let total = total_len as usize;
200 let remaining = total - received;
201 let copy_len = data.len().min(remaining);
202
203 self.buf[received..received + copy_len].copy_from_slice(&data[..copy_len]);
204
205 let new_received = received + copy_len;
206 let new_sequence = (next_sequence + 1) & NIBBLE_MASK;
207
208 if new_received >= total {
209 self.state = ReassemblerState::Idle;
210 Ok(ReassembleResult::Complete { len: total })
211 } else {
212 self.state = ReassemblerState::Active {
213 total_len,
214 received: new_received,
215 next_sequence: new_sequence,
216 };
217 Ok(ReassembleResult::InProgress)
218 }
219 }
220 PciFrame::FlowControl { .. } => Err(IsoTpError::UnknownFrameType(0x3)),
224 }
225 }
226}
227
228