GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Warnings: 1 unchecked decisions!
Coverage Exec / Excl / Total
Lines: 53.6% 148 / 0 / 276
Functions: 66.7% 8 / 0 / 12
Branches: 47.0% 71 / 0 / 151
Decisions: 40.4% 42 / - / 104

firmware/controllers/can/isotp/isotp.cpp
Line Branch Decision Exec Source
1 /**
2 *
3 * https://en.wikipedia.org/wiki/ISO_15765-2
4 */
5
6 #include "pch.h"
7 #include "isotp.h"
8 #include "can_rx.h"
9
10 #if HAL_USE_CAN || EFI_UNIT_TEST
11
12 static const size_t maxDlc = 8;
13
14 52 int IsoTpBase::sendFrame(const IsoTpFrameHeader &header, const uint8_t *data, int num, can_sysinterval_t timeout) {
15 // Calculate needed DLC and maximum payload
16 int offset, numBytes;
17
4/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
52 switch (header.frameType) {
18
1/1
✓ Decision 'true' taken 5 times.
5 case ISO_TP_FRAME_SINGLE:
19 5 offset = isoHeaderByteIndex + 1;
20
1/1
✓ Branch 1 taken 5 times.
5 numBytes = minI(num, maxDlc - offset);
21 5 break;
22
1/1
✓ Decision 'true' taken 8 times.
8 case ISO_TP_FRAME_FIRST:
23 8 offset = isoHeaderByteIndex + 2;
24
1/1
✓ Branch 1 taken 8 times.
8 numBytes = minI(num, maxDlc - offset);
25 8 break;
26
1/1
✓ Decision 'true' taken 31 times.
31 case ISO_TP_FRAME_CONSECUTIVE:
27 31 offset = isoHeaderByteIndex + 1;
28
1/1
✓ Branch 1 taken 31 times.
31 numBytes = minI(num, maxDlc - offset);
29 31 break;
30
1/1
✓ Decision 'true' taken 8 times.
8 case ISO_TP_FRAME_FLOW_CONTROL:
31 8 offset = isoHeaderByteIndex + 3;
32 8 numBytes = 0; // no data is sent with 'flow control' frame
33 8 break;
34 default:
35 // bad frame type
36 return 0;
37 }
38
39 52 int dlc = offset + numBytes;
40
1/1
✓ Branch 2 taken 52 times.
104 CanTxMessage txmsg(CanCategory::SERIAL, txFrameId, dlc, busIndex, IS_EXT_RANGE_ID(txFrameId));
41
42 // fill the frame data according to the CAN-TP protocol (ISO 15765-2)
43
1/1
✓ Branch 1 taken 52 times.
52 txmsg[isoHeaderByteIndex] = (uint8_t)((header.frameType & 0xf) << 4);
44
4/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
52 switch (header.frameType) {
45
1/1
✓ Decision 'true' taken 5 times.
5 case ISO_TP_FRAME_SINGLE:
46
1/1
✓ Branch 1 taken 5 times.
5 txmsg[isoHeaderByteIndex] |= numBytes;
47 5 break;
48
1/1
✓ Decision 'true' taken 8 times.
8 case ISO_TP_FRAME_FIRST:
49
1/1
✓ Branch 1 taken 8 times.
8 txmsg[isoHeaderByteIndex] |= (header.numBytes >> 8) & 0xf;
50
1/1
✓ Branch 1 taken 8 times.
8 txmsg[isoHeaderByteIndex + 1] = (uint8_t)(header.numBytes & 0xff);
51 8 break;
52
1/1
✓ Decision 'true' taken 31 times.
31 case ISO_TP_FRAME_CONSECUTIVE:
53
1/1
✓ Branch 1 taken 31 times.
31 txmsg[isoHeaderByteIndex] |= header.index & 0xf;
54 31 break;
55
1/1
✓ Decision 'true' taken 8 times.
8 case ISO_TP_FRAME_FLOW_CONTROL:
56
1/1
✓ Branch 1 taken 8 times.
8 txmsg[isoHeaderByteIndex] |= header.fcFlag & 0xf;
57
1/1
✓ Branch 1 taken 8 times.
8 txmsg[isoHeaderByteIndex + 1] = (uint8_t)(header.blockSize);
58
1/1
✓ Branch 1 taken 8 times.
8 txmsg[isoHeaderByteIndex + 2] = (uint8_t)(header.separationTime);
59 8 break;
60 default:
61 // bad frame type
62 return 0;
63 }
64
65 // copy the contents
66
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 8 times.
2/2
✓ Decision 'true' taken 44 times.
✓ Decision 'false' taken 8 times.
52 if (data != nullptr) {
67
2/2
✓ Branch 0 taken 258 times.
✓ Branch 1 taken 44 times.
2/2
✓ Decision 'true' taken 258 times.
✓ Decision 'false' taken 44 times.
302 for (int i = 0; i < numBytes; i++) {
68
1/1
✓ Branch 1 taken 258 times.
258 txmsg[i + offset] = data[i];
69 }
70 }
71
72 // send the frame!
73
2/3
✓ Branch 1 taken 52 times.
✓ Branch 3 taken 52 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 52 times.
✗ Decision 'false' not taken.
52 if (transmit(txmsg, timeout) == CAN_MSG_OK) {
74 52 return numBytes;
75 }
76
77 return 0;
78 }
79
80 8 void IsoTpBase::sendFlowControl(can_sysinterval_t timeout) {
81 8 IsoTpFrameHeader header;
82 8 header.frameType = ISO_TP_FRAME_FLOW_CONTROL;
83 8 header.fcFlag = 0; // = "continue to send"
84 8 header.blockSize = 0; // = the remaining "frames" to be sent without flow control or delay
85 8 header.separationTime = 0; // = wait 0 milliseconds, send immediately
86
1/1
✓ Branch 1 taken 8 times.
8 sendFrame(header, nullptr, 0, timeout);
87 8 }
88
89 // returns the number of copied bytes
90 44 int CanStreamerState::receiveFrame(const CANRxFrame &rxmsg, uint8_t *destinationBuff, int availableAtBuffer, can_sysinterval_t timeout) {
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 44 times.
44 if (rxmsg.DLC < 1 + isoHeaderByteIndex)
92 return 0;
93 44 engine->pauseCANdueToSerial = true;
94 44 int frameType = (rxmsg.data8[isoHeaderByteIndex] >> 4) & 0xf;
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 44 times.
44 if (engineConfiguration->verboseIsoTp) {
96 efiPrintf("receiveFrame frameType=%d", frameType);
97 #if EFI_PROD_CODE
98 printCANRxFrame(-1, rxmsg);
99 #endif // EFI_PROD_CODE
100 }
101 int numBytesAvailable, frameIdx;
102 const uint8_t *srcBuf;
103
3/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
44 switch (frameType) {
104
1/1
✓ Decision 'true' taken 5 times.
5 case ISO_TP_FRAME_SINGLE:
105 5 numBytesAvailable = rxmsg.data8[isoHeaderByteIndex] & 0xf;
106 5 this->waitingForNumBytes = numBytesAvailable;
107 5 srcBuf = rxmsg.data8 + 1 + isoHeaderByteIndex;
108 5 break;
109
1/1
✓ Decision 'true' taken 8 times.
8 case ISO_TP_FRAME_FIRST:
110 8 this->waitingForNumBytes = ((rxmsg.data8[isoHeaderByteIndex] & 0xf) << 8) | rxmsg.data8[isoHeaderByteIndex + 1];
111 8 this->waitingForFrameIndex = 1;
112 8 numBytesAvailable = minI(this->waitingForNumBytes, 6 - isoHeaderByteIndex);
113 8 srcBuf = rxmsg.data8 + 2 + isoHeaderByteIndex;
114
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 8 times.
✗ Decision 'false' not taken.
8 if (rxTransport) {
115 8 rxTransport->onTpFirstFrame(); // used to send flow control message
116 }
117 8 break;
118
1/1
✓ Decision 'true' taken 31 times.
31 case ISO_TP_FRAME_CONSECUTIVE:
119 31 frameIdx = rxmsg.data8[isoHeaderByteIndex] & 0xf;
120
2/4
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 31 times.
31 if (this->waitingForNumBytes < 0 || this->waitingForFrameIndex != frameIdx) {
121 // todo: that's an abnormal situation, and we probably should react?
122 return 0;
123 }
124 31 numBytesAvailable = minI(this->waitingForNumBytes, 7 - isoHeaderByteIndex);
125 31 srcBuf = rxmsg.data8 + 1 + isoHeaderByteIndex;
126 31 this->waitingForFrameIndex = (this->waitingForFrameIndex + 1) & 0xf;
127 31 break;
128 case ISO_TP_FRAME_FLOW_CONTROL:
129 // todo: currently we just ignore the FC frame
130 return 0;
131 default:
132 // bad frame type
133 return 0;
134 }
135
136 /** performance optimization specific to TS over CAN tunnelling
137 TODO: refactor into child class if we ever choose to revive this logic
138 #if defined(TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME)
139 if (frameType == ISO_TP_FRAME_SINGLE) {
140 // restore the CRC on the whole packet
141 uint32_t crc = crc32((void *) srcBuf, numBytesAvailable);
142 // we need a separate buffer for crc because srcBuf may not be word-aligned for direct copy
143 uint8_t crcBuffer[sizeof(uint32_t)];
144 *(uint32_t *) (crcBuffer) = SWAP_UINT32(crc);
145
146 // now set the packet size
147 *(uint16_t *) shortCrcPacketStagingArea = SWAP_UINT16(numBytesAvailable);
148 // copy the data
149 if (numBytesAvailable > 0)
150 memcpy(shortCrcPacketStagingArea + sizeof(uint16_t), srcBuf, numBytesAvailable);
151 // copy the crc to the end
152 memcpy(shortCrcPacketStagingArea + sizeof(uint16_t) + numBytesAvailable, crcBuffer, sizeof(crcBuffer));
153
154 // use the reconstructed tmp buffer as a source buffer
155 srcBuf = shortCrcPacketStagingArea;
156 // we added the 16-bit size & 32-bit crc bytes
157 numBytesAvailable += sizeof(uint16_t) + sizeof(crcBuffer);
158 }
159 #endif *//* TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME */
160
161 44 int numBytesToCopy = minI(availableAtBuffer, numBytesAvailable);
162
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 44 times.
✗ Decision 'false' not taken.
44 if (destinationBuff != nullptr) {
163 44 memcpy(destinationBuff, srcBuf, numBytesToCopy);
164 }
165 44 srcBuf += numBytesToCopy;
166 44 waitingForNumBytes -= numBytesAvailable;
167 44 isComplete = (waitingForNumBytes == 0);
168 44 numBytesAvailable -= numBytesToCopy;
169 // if there are some more bytes left, we save them for the next time
170
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 44 times.
2/2
✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 44 times.
68 for (int i = 0; i < numBytesAvailable; i++) {
171 24 rxFifoBuf.put(srcBuf[i]);
172 }
173
174 // according to the specs, we need to acknowledge the received multi-frame start frame
175
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 36 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 36 times.
44 if (frameType == ISO_TP_FRAME_FIRST) {
176 8 sendFlowControl(timeout);
177 }
178
179 44 return numBytesToCopy;
180 }
181
182 void CanStreamerState::reset() {
183 waitingForNumBytes = 0;
184 waitingForFrameIndex = 0;
185 isComplete = false;
186 }
187
188 13 int CanStreamerState::sendDataTimeout(const uint8_t *txbuf, int numBytes, can_sysinterval_t timeout) {
189 13 int offset = 0;
190
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 13 times.
13 if (engineConfiguration->verboseIsoTp) {
192 PRINT("*** INFO: sendDataTimeout %d" PRINT_EOL, numBytes);
193 }
194
195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 13 times.
13 if (numBytes < 1)
196 return 0;
197
198 // 1 frame
199
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 8 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 8 times.
13 if (numBytes <= 7 - isoHeaderByteIndex) {
200 5 IsoTpFrameHeader header;
201 5 header.frameType = ISO_TP_FRAME_SINGLE;
202 5 header.numBytes = numBytes;
203
1/1
✓ Branch 1 taken 5 times.
5 return IsoTpBase::sendFrame(header, txbuf, numBytes, timeout);
204 }
205
206 // multiple frames
207
208 // send the first header frame (FF)
209 8 IsoTpFrameHeader header;
210 8 header.frameType = ISO_TP_FRAME_FIRST;
211 8 header.numBytes = numBytes;
212
1/1
✓ Branch 1 taken 8 times.
8 int numSent = IsoTpBase::sendFrame(header, txbuf + offset, numBytes, timeout);
213 8 offset += numSent;
214 8 numBytes -= numSent;
215
216 // get a flow control (FC) frame
217 #if !EFI_UNIT_TEST // todo: add FC to unit-tests?
218 CANRxFrame rxmsg;
219 for (size_t numFcReceived = 0; ; numFcReceived++) {
220 if (rxTransport->receive(&rxmsg, timeout) != CAN_MSG_OK) {
221 #ifdef SERIAL_CAN_DEBUG
222 PRINT("*** ERROR: CAN Flow Control frame not received" PRINT_EOL);
223 #endif /* SERIAL_CAN_DEBUG */
224 //warning(ObdCode::CUSTOM_ERR_CAN_COMMUNICATION, "CAN Flow Control frame not received");
225 return 0;
226 }
227 receiveFrame(rxmsg, nullptr, 0, timeout);
228 uint8_t frameType = (rxmsg.data8[isoHeaderByteIndex] >> 4) & 0xf;
229 uint8_t flowStatus = rxmsg.data8[isoHeaderByteIndex] & 0xf;
230 // if something is not ok
231 if ((frameType != ISO_TP_FRAME_FLOW_CONTROL) || (flowStatus != CAN_FLOW_STATUS_OK)) {
232 // if the receiver is not ready yet and asks to wait for the next FC frame (give it 3 attempts)
233 if ((frameType == ISO_TP_FRAME_FLOW_CONTROL) && (flowStatus == CAN_FLOW_STATUS_WAIT_MORE) && (numFcReceived < 3)) {
234 continue;
235 }
236 #ifdef SERIAL_CAN_DEBUG
237 efiPrintf("*** ERROR: CAN Flow Control mode not supported");
238 #endif /* SERIAL_CAN_DEBUG */
239 //warning(ObdCode::CUSTOM_ERR_CAN_COMMUNICATION, "CAN Flow Control mode not supported");
240 return 0;
241 }
242 uint8_t blockSize = rxmsg.data8[isoHeaderByteIndex + 1];
243 uint8_t minSeparationTime = rxmsg.data8[isoHeaderByteIndex + 2];
244 if (blockSize != 0 || minSeparationTime != 0) {
245 // todo: process other Flow Control fields (see ISO 15765-2)
246 #ifdef SERIAL_CAN_DEBUG
247 efiPrintf("*** ERROR: CAN Flow Control fields not supported");
248 #endif /* SERIAL_CAN_DEBUG */
249 //warning(ObdCode::CUSTOM_ERR_CAN_COMMUNICATION, "CAN Flow Control fields not supported");
250 }
251 break;
252 }
253 #endif /* EFI_UNIT_TEST */
254
255 // send the rest of the data
256 8 int idx = 1;
257
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 8 times.
2/2
✓ Decision 'true' taken 31 times.
✓ Decision 'false' taken 8 times.
39 while (numBytes > 0) {
258
1/1
✓ Branch 1 taken 31 times.
31 int len = minI(numBytes, 7 - isoHeaderByteIndex);
259 // send the consecutive frames
260 31 header.frameType = ISO_TP_FRAME_CONSECUTIVE;
261 31 header.index = ((idx++) & 0x0f);
262 31 header.numBytes = len;
263
1/1
✓ Branch 1 taken 31 times.
31 numSent = IsoTpBase::sendFrame(header, txbuf + offset, len, timeout);
264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 31 times.
31 if (numSent < 1)
265 break;
266 31 offset += numSent;
267 31 numBytes -= numSent;
268 }
269 8 return offset;
270 }
271
272 23 int CanStreamerState::getDataFromFifo(uint8_t *rxbuf, size_t &numBytes) {
273
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 10 times.
2/2
✓ Decision 'true' taken 13 times.
✓ Decision 'false' taken 10 times.
23 if (rxFifoBuf.isEmpty())
274 13 return 0;
275 10 int numReadFromFifo = minI(numBytes, rxFifoBuf.getCount());
276 // move bytes from the FIFO buffer
277 int i;
278
6/6
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 10 times.
0/1
? Decision couldn't be analyzed.
34 for (i = 0; !rxFifoBuf.isEmpty() && i < numReadFromFifo; i++) {
279 24 rxbuf[i] = rxFifoBuf.get();
280 24 numBytes--;
281 }
282 10 return i;
283 }
284
285 23 can_msg_t CanStreamerState::streamAddToTxTimeout(size_t *np, const uint8_t *txbuf, can_sysinterval_t timeout) {
286 23 int numBytes = *np;
287 23 int offset = 0;
288
289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 23 times.
23 if (engineConfiguration->verboseIsoTp) {
290 PRINT("*** INFO: streamAddToTxTimeout adding %d, in buffer %d" PRINT_EOL, numBytes, txFifoBuf.getCount());
291 }
292
293 // we send here only if the TX FIFO buffer is getting overflowed
294
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 23 times.
23 while (numBytes >= txFifoBuf.getSize() - txFifoBuf.getCount()) {
295 int numBytesToAdd = txFifoBuf.getSize() - txFifoBuf.getCount();
296 txFifoBuf.put(txbuf + offset, numBytesToAdd);
297 int numSent = sendDataTimeout((const uint8_t *)txFifoBuf.getElements(), txFifoBuf.getCount(), timeout);
298
299 if (engineConfiguration->verboseIsoTp) {
300 PRINT("*** INFO: streamAddToTxTimeout numBytesToAdd %d / numSent %d / numBytes %d" PRINT_EOL, numBytesToAdd, numSent, numBytes);
301 }
302
303 if (numSent < 1)
304 break;
305 txFifoBuf.clear();
306 offset += numBytesToAdd;
307 numBytes -= numBytesToAdd;
308 }
309
310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 23 times.
23 if (engineConfiguration->verboseIsoTp) {
311 PRINT("*** INFO: streamAddToTxTimeout remaining goes to buffer %d" PRINT_EOL, numBytes);
312 }
313
314 // now we put the rest on hold
315 23 txFifoBuf.put(txbuf + offset, numBytes);
316
317
318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 23 times.
23 if (engineConfiguration->verboseIsoTp) {
319 PRINT("*** INFO: in buffer %d" PRINT_EOL, txFifoBuf.getCount());
320 }
321
322 23 return CAN_MSG_OK;
323 }
324
325 13 can_msg_t CanStreamerState::streamFlushTx(can_sysinterval_t timeout) {
326 13 int numSent = sendDataTimeout((const uint8_t *)txFifoBuf.getElements(), txFifoBuf.getCount(), timeout);
327 13 if (numSent != txFifoBuf.getCount()) {
328 //warning(ObdCode::CUSTOM_ERR_CAN_COMMUNICATION, "CAN sendDataTimeout() problems");
329 }
330 13 txFifoBuf.clear();
331
332 13 return CAN_MSG_OK;
333 }
334
335 23 can_msg_t CanStreamerState::streamReceiveTimeout(size_t *np, uint8_t *rxbuf, can_sysinterval_t timeout) {
336 23 size_t availableBufferSpace = *np;
337
338 // first, fill the data from the stored buffer (saved from the previous CAN frame)
339
1/1
✓ Branch 1 taken 23 times.
23 int receivedSoFar = getDataFromFifo(rxbuf, availableBufferSpace);
340
341 // if even more data is needed, then we receive more CAN frames
342
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 23 times.
2/2
✓ Decision 'true' taken 44 times.
✓ Decision 'false' taken 23 times.
67 while (availableBufferSpace > 0) {
343 44 CANRxFrame rxmsg;
344
2/3
✓ Branch 1 taken 44 times.
✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 44 times.
✗ Decision 'false' not taken.
44 if (rxTransport->receive(&rxmsg, timeout) == CAN_MSG_OK) {
345
1/1
✓ Branch 1 taken 44 times.
44 int numReceived = receiveFrame(rxmsg, rxbuf + receivedSoFar, availableBufferSpace, timeout);
346
347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 44 times.
44 if (numReceived < 1)
348 break;
349 44 availableBufferSpace -= numReceived;
350 44 receivedSoFar += numReceived;
351 } else {
352 break;
353 }
354 }
355 23 *np -= availableBufferSpace;
356
357 #ifdef SERIAL_CAN_DEBUG
358 efiPrintf("* ret: %d %d (%d)", i, *np, availableBufferSpace);
359 for (int j = 0; j < receivedSoFar; j++) {
360 efiPrintf("* [%d]: %02x", j, rxbuf[j]);
361 }
362 #endif /* SERIAL_CAN_DEBUG */
363
364 23 return CAN_MSG_OK;
365 }
366
367 int IsoTpRx::readTimeout(uint8_t *rxbuf, size_t *size, sysinterval_t timeout)
368 {
369 //is fxbuf is too small?
370 bool overflow = false;
371 bool isFirstFrame = true;
372 size_t availableAtBuffer = *size;
373 uint8_t *buf = rxbuf;
374
375 do {
376 CANRxFrame rxmsg;
377
378 // TODO: adjust timeout!
379 if (!rxFifoBuf.get(rxmsg, timeout)) {
380 // TODO: error codes
381 if (isFirstFrame) {
382 // this is not an error
383 //efiPrintf("IsoTp: rx timeout, nothing received");
384 *size = 0;
385 return 0;
386 }
387
388 efiPrintf("IsoTP: rx timeout, %d left to receive", waitingForNumBytes);
389 *size = buf - rxbuf;
390 return -1;
391 }
392
393 uint8_t frameType = (rxmsg.data8[isoHeaderByteIndex] >> 4) & 0xf;
394 if (engineConfiguration->verboseIsoTp) {
395 efiPrintf("receiveFrame frameType=%d", frameType);
396 #if EFI_PROD_CODE
397 printCANRxFrame(-1, rxmsg);
398 #endif // EFI_PROD_CODE
399 }
400 size_t numBytesAvailable;
401 uint8_t frameIdx;
402 const uint8_t *srcBuf;
403 switch (frameType) {
404 case ISO_TP_FRAME_SINGLE:
405 // TODO: check that this is first packet! see isFirstFrame
406 numBytesAvailable = rxmsg.data8[isoHeaderByteIndex] & 0xf;
407 waitingForNumBytes = numBytesAvailable;
408 srcBuf = rxmsg.data8 + 1 + isoHeaderByteIndex;
409 break;
410 case ISO_TP_FRAME_FIRST:
411 // TODO: check that this is first packet! see isFirstFrame
412 waitingForNumBytes = ((rxmsg.data8[isoHeaderByteIndex] & 0xf) << 8) | rxmsg.data8[isoHeaderByteIndex + 1];
413 waitingForFrameIndex = 1;
414 numBytesAvailable = minI(waitingForNumBytes, 6 - isoHeaderByteIndex);
415 srcBuf = rxmsg.data8 + 2 + isoHeaderByteIndex;
416 // rxTransport->onTpFirstFrame(); // used to send flow control message
417 break;
418 case ISO_TP_FRAME_CONSECUTIVE:
419 frameIdx = rxmsg.data8[isoHeaderByteIndex] & 0xf;
420 if (waitingForNumBytes < 0) {
421 // Should not happen
422 return -4;
423 }
424 if (waitingForFrameIndex != frameIdx) {
425 // todo: that's an abnormal situation, and we probably should react?
426 // TODO: error codes
427 efiPrintf("received frame index %d is not what expected %d",
428 frameIdx, waitingForFrameIndex);
429 return -2;
430 }
431 numBytesAvailable = minI(waitingForNumBytes, 7 - isoHeaderByteIndex);
432 srcBuf = rxmsg.data8 + 1 + isoHeaderByteIndex;
433 waitingForFrameIndex = (waitingForFrameIndex + 1) & 0xf;
434 break;
435 case ISO_TP_FRAME_FLOW_CONTROL:
436 // todo: currently we just ignore the FC frame
437 // TODO: we should not receive FC frame while receiving data
438 break;
439 default:
440 // bad frame type
441 // TODO: error codes
442 return -3;
443 }
444
445 if (isFirstFrame) {
446 if ((buf) && (waitingForNumBytes > availableAtBuffer)) {
447 efiPrintf("receive buffer is not enough %d > %d", waitingForNumBytes, availableAtBuffer);
448 }
449 isFirstFrame = false;
450 }
451
452 if (buf != nullptr) {
453 int numBytesToCopy = minI(availableAtBuffer, numBytesAvailable);
454
455 memcpy(buf, srcBuf, numBytesToCopy);
456 buf += numBytesToCopy;
457 availableAtBuffer -= numBytesToCopy;
458
459 // if there are some more bytes left, receive and drop
460 if (numBytesAvailable > numBytesToCopy) {
461 overflow = true;
462 }
463 }
464
465 // according to the specs, we need to acknowledge the received multi-frame start frame
466 if (frameType == ISO_TP_FRAME_FIRST) {
467 sendFlowControl(timeout);
468 }
469
470 waitingForNumBytes -= numBytesAvailable;
471 } while (waitingForNumBytes > 0);
472
473 // received size
474 *size = buf - rxbuf;
475
476 return overflow ? 1 : 0;
477 }
478
479 void IsoTpRx::resetRxVerbose() {
480 #if EFI_PROD_CODE || SIMULATOR
481 CANRxFrame rxmsg;
482
483 while (rxFifoBuf.get(rxmsg, 0)) {
484 printCANRxFrame(busIndex, rxmsg);
485 }
486 #endif
487
488 waitingForNumBytes = 0;
489 waitingForFrameIndex = 0;
490 }
491
492 int IsoTpRxTx::writeTimeout(const uint8_t *txbuf, size_t size, sysinterval_t timeout) {
493 int offset = 0;
494
495 if (engineConfiguration->verboseIsoTp) {
496 PRINT("*** INFO: sendDataTimeout %d" PRINT_EOL, size);
497 }
498
499 if (size < 1)
500 return 0;
501
502 // 1 frame
503 if (size <= 7 - isoHeaderByteIndex) {
504 IsoTpFrameHeader header;
505 header.frameType = ISO_TP_FRAME_SINGLE;
506 header.numBytes = size;
507 return IsoTpBase::sendFrame(header, txbuf, size, timeout);
508 }
509
510 // multiple frames
511
512 // send the first header frame (FF)
513 IsoTpFrameHeader header;
514 header.frameType = ISO_TP_FRAME_FIRST;
515 header.numBytes = size;
516 int numSent = IsoTpBase::sendFrame(header, txbuf + offset, size, timeout);
517 offset += numSent;
518 size -= numSent;
519
520 // get a flow control (FC) frame
521 #if !EFI_UNIT_TEST // todo: add FC to unit-tests?
522 CANRxFrame rxmsg;
523 size_t numFcReceived = 0;
524 int separationTimeUs = 0;
525 while (numFcReceived < 3) {
526 // TODO: adjust timeout!
527 if (!rxFifoBuf.get(rxmsg, timeout)) {
528 efiPrintf("IsoTp: Flow Control frame not received");
529 //warning(ObdCode::CUSTOM_ERR_CAN_COMMUNICATION, "CAN Flow Control frame not received");
530 return 0;
531 }
532 uint8_t frameType = (rxmsg.data8[isoHeaderByteIndex] >> 4) & 0xf;
533
534 // if something is not ok
535 if (frameType != ISO_TP_FRAME_FLOW_CONTROL) {
536 // should we expect only FC here?
537 continue;
538 }
539
540 // Ok, frame is FC
541 numFcReceived++;
542 uint8_t flowStatus = rxmsg.data8[isoHeaderByteIndex] & 0xf;
543
544 if (flowStatus == CAN_FLOW_STATUS_ABORT) {
545 efiPrintf("IsoTp: Flow Control ABORT");
546 // TODO: error codes
547 return -4;
548 }
549
550 if (flowStatus == CAN_FLOW_STATUS_WAIT_MORE) {
551 // if the receiver is not ready yet and asks to wait for the next FC frame (give it 3 attempts)
552 if (numFcReceived < 3) {
553 continue;
554 }
555 // TODO: error codes
556 return -5;
557 }
558
559 if (flowStatus != CAN_FLOW_STATUS_OK) {
560 efiPrintf("IsoTp: Flow Control unknown Status %d", flowStatus);
561 // TODO: error codes
562 return -6;
563 }
564
565 uint8_t blockSize = rxmsg.data8[isoHeaderByteIndex + 1];
566 uint8_t minSeparationTime = rxmsg.data8[isoHeaderByteIndex + 2];
567 if (blockSize != 0) {
568 // todo: process other Flow Control fields (see ISO 15765-2)
569 efiPrintf("IsoTp: Flow Control blockSize is not supported %d", blockSize);
570 // TODO: error codes
571 return -7;
572 }
573
574 if (minSeparationTime <= 0x7f) {
575 // mS units
576 separationTimeUs = minSeparationTime * 1000;
577 } else if ((minSeparationTime >= 0xf1) && (minSeparationTime <= 0xf9)) {
578 // 100 uS units
579 separationTimeUs = (minSeparationTime - 0xf0) * 100;
580 }
581
582 break;
583 }
584 #endif /* EFI_UNIT_TEST */
585
586 // send the rest of the data
587 uint8_t idx = 1;
588 while (size > 0) {
589 int len = minI(size, 7 - isoHeaderByteIndex);
590 // send the consecutive frames
591 header.frameType = ISO_TP_FRAME_CONSECUTIVE;
592 header.index = ((idx++) & 0x0f);
593 header.numBytes = len;
594 numSent = IsoTpBase::sendFrame(header, txbuf + offset, len, timeout);
595 if (numSent < 1)
596 break;
597 offset += numSent;
598 size -= numSent;
599
600 #if ! EFI_UNIT_TEST
601 if (separationTimeUs) {
602 chThdSleepMicroseconds(separationTimeUs);
603 }
604 #endif // EFI_UNIT_TEST
605 }
606 return offset;
607 }
608
609 #endif // HAL_USE_CAN || EFI_UNIT_TEST
610