GCC Code Coverage Report


Directory: ./
File: firmware/controllers/can/isotp/isotp.h
Date: 2025-12-07 16:27:22
Coverage Exec Excl Total
Lines: 62.5% 15 0 24
Functions: 50.0% 3 0 6
Branches: 50.0% 2 0 4
Decisions: 50.0% 2 - 4

Line Branch Decision Exec Source
1 #pragma once
2
3 #include "fifo_buffer.h"
4 #include "can.h"
5 #include "can_msg_tx.h"
6 #include "can_listener.h"
7
8 #if EFI_UNIT_TEST
9 #define PRINT printf
10 #define PRINT_EOL "\n"
11 #else
12 #define PRINT efiPrintf
13 #define PRINT_EOL ""
14 #endif
15
16 #if EFI_PROD_CODE | EFI_SIMULATOR
17 #define can_msg_t msg_t
18 #define can_sysinterval_t sysinterval_t
19 #define CAN_MSG_OK MSG_OK
20 #define CAN_MSG_TIMEOUT MSG_TIMEOUT
21 #else
22 #include "can_mocks.h"
23 #endif /* EFI_UNIT_TEST */
24
25 #define CAN_FLOW_STATUS_OK 0
26 #define CAN_FLOW_STATUS_WAIT_MORE 1
27 #define CAN_FLOW_STATUS_ABORT 2
28
29 enum IsoTpFrameType {
30 ISO_TP_FRAME_SINGLE = 0,
31 ISO_TP_FRAME_FIRST = 1,
32 ISO_TP_FRAME_CONSECUTIVE = 2,
33 ISO_TP_FRAME_FLOW_CONTROL = 3,
34 };
35
36 class IsoTpFrameHeader {
37 public:
38 IsoTpFrameType frameType;
39
40 // used for 'single' or 'first' frames
41 int numBytes;
42 // used for 'consecutive' frames
43 int index;
44 // used for 'flow control' frames
45 int fcFlag;
46 int blockSize;
47 int separationTime;
48 };
49
50 // todo: what's the point of this wrapper/holder class anyway?
51 class CanRxMessage {
52 public:
53 CanRxMessage() {}
54
55 CanRxMessage(const CANRxFrame &f) {
56 frame = f;
57 }
58
59 CanRxMessage(const CanRxMessage& msg) : frame(msg.frame) {}
60
61 CanRxMessage& operator=(const CanRxMessage& msg) {
62 // full content copy
63 frame = msg.frame;
64 return *this;
65 }
66
67 public:
68 CANRxFrame frame;
69 };
70
71 class CanRxMessageSource {
72 public:
73 virtual bool get(CanRxMessage &item, int timeout) = 0;
74 };
75
76 class ICanTransmitter {
77 public:
78 virtual can_msg_t transmit(CanTxMessage &ctfp, can_sysinterval_t timeout) = 0;
79 };
80
81 class ICanReceiver {
82 public:
83 virtual can_msg_t receive(CANRxFrame *crfp, can_sysinterval_t timeout) = 0;
84 virtual void onTpFirstFrame() = 0;
85 };
86
87 class IsoTpBase {
88 public:
89 13 IsoTpBase(ICanTransmitter *p_txTransport, size_t p_busIndex, uint32_t p_rxFrameId, uint32_t p_txFrameId)
90 13 :
91 13 txTransport(p_txTransport),
92 13 busIndex(p_busIndex),
93 13 rxFrameId(p_rxFrameId),
94 13 txFrameId(p_txFrameId)
95 13 {}
96
97 int sendFrame(const IsoTpFrameHeader & header, const uint8_t *data, int num, can_sysinterval_t timeout);
98
99 52 can_msg_t transmit(CanTxMessage &ctfp, can_sysinterval_t timeout) {
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 52 times.
52 if (isoHeaderByteIndex) {
101 // yes that would be truncated to byte, that's expected
102 ctfp[0] = rxFrameId & 0xff;
103 }
104
1/2
✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 52 times.
✗ Decision 'false' not taken.
52 if (txTransport) {
105 52 return txTransport->transmit(ctfp, timeout);
106 }
107 return CAN_MSG_OK;
108 }
109
110 // Offset of first ISO-TP byte, usually 0
111 // but some vendors add some specific data in first CAN byte
112 size_t isoHeaderByteIndex = 0;
113
114 ICanTransmitter *txTransport;
115
116 size_t busIndex;
117 uint32_t rxFrameId;
118 uint32_t txFrameId;
119 };
120
121 // We need an abstraction layer for unit-testing
122 // todo: no reason for composite entity to exist, keep splitting CanStreamerState into RX and TX!
123 class ICanTransport : public ICanTransmitter, public ICanReceiver {
124 };
125
126 // most efficient sizes are 6 + x * 7 that way whole buffer is transmitted as (x+1) full packets
127 #ifndef CAN_FIFO_BUF_SIZE
128 #define CAN_FIFO_BUF_SIZE 76
129 #endif // CAN_FIFO_BUF_SIZE
130
131 #define CAN_FIFO_FRAME_SIZE 8
132
133 class CanStreamerState : public IsoTpBase {
134 public:
135 // serial_can uses fifo_buffer_sync, unify?
136 fifo_buffer<uint8_t, CAN_FIFO_BUF_SIZE> rxFifoBuf;
137 fifo_buffer<uint8_t, CAN_FIFO_BUF_SIZE> txFifoBuf;
138
139 /*
140 #if defined(TS_CAN_DEVICE_SHORT_PACKETS_IN_ONE_FRAME)
141 // used to restore the original packet with CRC
142 uint8_t shortCrcPacketStagingArea[13];
143 #endif
144 */
145 // used for multi-frame ISO-TP packets
146 int waitingForNumBytes = 0;
147 int waitingForFrameIndex = 0;
148
149 ICanReceiver *rxTransport;
150
151 public:
152 13 CanStreamerState(ICanTransmitter *p_txTransport, ICanReceiver *p_rxTransport, size_t p_busIndex, uint32_t p_rxFrameId, uint32_t p_txFrameId)
153 13 :
154 IsoTpBase(p_txTransport, p_busIndex, p_rxFrameId, p_txFrameId),
155 13 rxTransport(p_rxTransport)
156 13 {}
157
158 bool isComplete{};
159
160 void reset();
161
162 int sendFrame(const IsoTpFrameHeader & header, const uint8_t *data, int num, can_sysinterval_t timeout);
163 int receiveFrame(const CANRxFrame &rxmsg, uint8_t *buf, int num, can_sysinterval_t timeout);
164 int getDataFromFifo(uint8_t *rxbuf, size_t &numBytes);
165 // returns the number of bytes sent
166 int sendDataTimeout(const uint8_t *txbuf, int numBytes, can_sysinterval_t timeout);
167
168 // streaming support for TS I/O (see tunerstudio_io.cpp)
169 can_msg_t streamAddToTxTimeout(size_t *np, const uint8_t *txbuf, can_sysinterval_t timeout);
170 can_msg_t streamFlushTx(can_sysinterval_t timeout);
171 can_msg_t streamReceiveTimeout(size_t *np, uint8_t *rxbuf, can_sysinterval_t timeout);
172 };
173
174 #define ISOTP_RX_QUEUE_LEN 4
175
176 class IsoTpRx : public CanListener, public IsoTpBase {
177 public:
178 IsoTpRx(size_t p_busIndex, uint32_t p_rxFrameId, uint32_t p_txFrameId)
179 :
180 CanListener(p_rxFrameId),
181 IsoTpBase(nullptr, p_busIndex, p_rxFrameId, p_txFrameId)
182 {
183 rxFifoBuf.clear();
184 registerCanListener(*this);
185 }
186
187 ~IsoTpRx() {
188 unregisterCanListener(*this);
189 }
190
191 void reset() {
192 rxFifoBuf.clear();
193 waitingForNumBytes = 0;
194 waitingForFrameIndex = 0;
195 }
196
197 /* CAN messages entry point */
198 virtual void decodeFrame(const CANRxFrame& frame, efitick_t nowNt)
199 {
200 if (frame.DLC < 1 + isoHeaderByteIndex) {
201 // invalid++;
202 return;
203 }
204
205 if (isoHeaderByteIndex) {
206 if (frame.data8[0] != (txFrameId & 0xff)) {
207 return;
208 }
209 }
210
211 if (!rxFifoBuf.put(frame)) {
212 // overruns++;
213 }
214 }
215
216 /* User app entry point */
217 int readTimeout(uint8_t *rxbuf, size_t *size, sysinterval_t timeout);
218
219 private:
220 // used for multi-frame ISO-TP packets
221 int waitingForNumBytes = 0;
222 uint8_t waitingForFrameIndex = 0;
223
224 protected:
225 fifo_buffer_sync<CANRxFrame, ISOTP_RX_QUEUE_LEN> rxFifoBuf;
226 };
227
228 class IsoTpRxTx : public IsoTpRx {
229 public:
230 IsoTpRxTx(size_t p_busIndex, uint32_t p_rxFrameId, uint32_t p_txFrameId)
231 :
232 IsoTpRx(p_busIndex, p_rxFrameId, p_txFrameId)
233 {}
234
235 int writeTimeout(const uint8_t *txbuf, size_t size, sysinterval_t timeout);
236 };
237