Dawn Framework 1.0
Universal data acquisition framework for embedded systems
isotp.cxx
1// dawn/src/proto/can/isotp.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/proto/can/isotp.hxx"
7
8#include <cstring>
9#include <errno.h>
10
11#include "dawn/porting/can.hxx"
12
13using namespace dawn;
14
15//***************************************************************************
16// Public Methods
17//***************************************************************************
18
19void CIsoTp::initState(State &state)
20{
21 state.offset = 0;
22 state.seq_next = 0;
23 state.total_len = 0;
24 state.active = false;
25 state.timestamp = 0;
26}
27
28void CIsoTp::resetState(State &state)
29{
30 state.offset = 0;
31 state.seq_next = 0;
32 state.total_len = 0;
33 state.active = false;
34}
35
36uint8_t CIsoTp::getFrameType(uint8_t pci)
37{
38 return pci & FRAME_TYPE_MASK;
39}
40
41uint8_t CIsoTp::getSequence(uint8_t pci)
42{
43 return pci & SEQ_MASK;
44}
45
46uint8_t CIsoTp::nextSequence(uint8_t seq)
47{
48 return (seq + 1) & SEQ_MASK;
49}
50
51int CIsoTp::handleFirstFrame(const porting::canmsg_s &msg,
52 State &state,
53 void *data_buf,
54 size_t buf_size)
55{
56 size_t total_len;
57 size_t payload_len;
58 const uint8_t *payload;
59
60 if (msg.len < 2)
61 {
62 return -EINVAL;
63 }
64
65 // Extract total length from FF: [0x10][LL]
66
67 total_len = msg.data[1];
68 if (total_len == 0 || total_len > buf_size)
69 {
70 return -EINVAL;
71 }
72
73 // Payload starts at byte 2
74
75 payload = msg.data + 2;
76 payload_len = msg.len - 2;
77
78 if (payload_len > total_len)
79 {
80 payload_len = total_len;
81 }
82
83 // Initialize state
84
85 state.total_len = total_len;
86 state.offset = 0;
87 state.seq_next = 0;
88 state.active = true;
89
90 // Copy first chunk
91
92 std::memcpy(data_buf, payload, payload_len);
93 state.offset = payload_len;
94
95 return static_cast<int>(payload_len);
96}
97
98int CIsoTp::handleConsecutiveFrame(const porting::canmsg_s &msg,
99 State &state,
100 void *data_buf,
101 size_t buf_size)
102{
103 uint8_t seq;
104 size_t payload_len;
105 const uint8_t *payload;
106 size_t remaining;
107
108 if (!state.active)
109 {
110 return -EINVAL;
111 }
112
113 if (msg.len < 1)
114 {
115 return -EINVAL;
116 }
117
118 // Check sequence number
119
120 seq = getSequence(msg.data[0]);
121 if (seq != state.seq_next)
122 {
123 resetState(state);
124 return -EINVAL;
125 }
126
127 // Payload starts at byte 1
128
129 payload = msg.data + 1;
130 payload_len = msg.len - 1;
131
132 // Check buffer overflow
133
134 remaining = state.total_len - state.offset;
135 if (payload_len > remaining)
136 {
137 payload_len = remaining;
138 }
139
140 if (state.offset + payload_len > buf_size)
141 {
142 resetState(state);
143 return -EINVAL;
144 }
145
146 // Copy data
147
148 std::memcpy(static_cast<uint8_t *>(data_buf) + state.offset, payload, payload_len);
149
150 state.offset += payload_len;
151 state.seq_next = nextSequence(state.seq_next);
152
153 // Check if complete
154
155 if (state.offset >= state.total_len)
156 {
157 return 1; // Transfer complete
158 }
159
160 return static_cast<int>(payload_len);
161}
162
163bool CIsoTp::isComplete(const State &state)
164{
165 return state.active && (state.offset >= state.total_len);
166}
167
168bool CIsoTp::isTimeout(const State &state, uint64_t now, uint64_t timeout)
169{
170 if (!state.active || timeout == 0)
171 {
172 return false;
173 }
174
175 return (now - state.timestamp) > timeout;
176}
177
179 State &state,
180 void *data_buf,
181 size_t buf_size,
182 uint64_t now,
183 uint64_t timeout)
184{
185 uint8_t frame_type;
186 int ret;
187
188 if (msg.len < 1)
189 {
190 return -ENOMSG;
191 }
192
193 frame_type = getFrameType(msg.data[0]);
194
195 if (frame_type != FRAME_FF && frame_type != FRAME_CF)
196 {
197 return -ENOMSG;
198 }
199
200 // Check timeout
201
202 if (isTimeout(state, now, timeout))
203 {
204 resetState(state);
205 return -ETIMEDOUT;
206 }
207
208 // Handle First Frame
209
210 if (frame_type == FRAME_FF)
211 {
212 ret = handleFirstFrame(msg, state, data_buf, buf_size);
213 if (ret < 0)
214 {
215 return ret;
216 }
217
218 state.timestamp = now;
219 return 0; // In progress
220 }
221
222 // Handle Consecutive Frame
223
224 ret = handleConsecutiveFrame(msg, state, data_buf, buf_size);
225 if (ret < 0)
226 {
227 return ret;
228 }
229
230 state.timestamp = now;
231
232 // Check if complete
233
234 if (ret == 1)
235 {
236 return 1; // Complete
237 }
238
239 return 0; // In progress
240}
241
243 State &state,
244 void *data_buf,
245 size_t buf_size,
246 uint8_t seg_no,
247 bool seg_last,
248 uint64_t now,
249 uint64_t timeout)
250{
251 size_t payload_len = msg.len - 2;
252
253 if (!state.active)
254 {
255 if (seg_no != 0)
256 {
257 return -EINVAL;
258 }
259
260 state.active = true;
261 state.seq_next = 0;
262 state.offset = 0;
263 state.timestamp = now;
264 }
265 else if (timeout > 0 && (now - state.timestamp) > timeout)
266 {
267 state.active = false;
268 if (seg_no != 0)
269 {
270 return -ETIMEDOUT;
271 }
272
273 state.active = true;
274 state.seq_next = 0;
275 state.offset = 0;
276 state.timestamp = now;
277 }
278
279 if (seg_no != state.seq_next)
280 {
281 state.active = false;
282 return -EINVAL;
283 }
284
285 if (state.offset + payload_len > buf_size)
286 {
287 state.active = false;
288 return -EINVAL;
289 }
290
291 std::memcpy(static_cast<uint8_t *>(data_buf) + state.offset, msg.data + 2, payload_len);
292
293 state.offset += payload_len;
294 state.timestamp = now;
295
296 if (seg_last)
297 {
298 if (state.offset != buf_size)
299 {
300 state.active = false;
301 return -EINVAL;
302 }
303
304 resetState(state);
305 return 1; // Complete
306 }
307
308 state.seq_next += 1;
309 return 0; // In progress
310}
static int receiveCustom(const porting::canmsg_s &msg, State &state, void *data_buf, size_t buf_size, uint8_t seg_no, bool seg_last, uint64_t now, uint64_t timeout)
Process incoming Custom Segmented frame (Dawn specific).
Definition isotp.cxx:242
static int receive(const porting::canmsg_s &msg, State &state, void *data_buf, size_t buf_size, uint64_t now, uint64_t timeout)
Process incoming ISO-TP frame.
Definition isotp.cxx:178
static uint8_t FRAME_CF
Consecutive Frame (0x2N)
Definition isotp.hxx:38
static uint8_t FRAME_FF
First Frame (0x1N)
Definition isotp.hxx:37
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
Common CAN message format for chardev and socketCAN.
Definition can.hxx:20