1 /*
2  * Copyright (c) 2019 Alexander Wachter
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Public API for ISO-TP (ISO 15765-2:2016)
10  *
11  * ISO-TP is a transport protocol for CAN (Controller Area Network)
12  */
13 
14 #ifndef ZEPHYR_INCLUDE_ISOTP_H_
15 #define ZEPHYR_INCLUDE_ISOTP_H_
16 
17 /**
18  * @brief CAN ISO-TP Interf
19  * @defgroup can_isotp CAN ISO-TP Interface
20  * @ingroup CAN
21  * @{
22  */
23 
24 #include <drivers/can.h>
25 #include <zephyr/types.h>
26 #include <net/buf.h>
27 
28 /*
29  * Abbreviations
30  * BS      Block Size
31  * CAN_DL  CAN LL data size
32  * CF      Consecutive Frame
33  * CTS     Continue to send
34  * DLC     Data length code
35  * FC      Flow Control
36  * FF      First Frame
37  * FS      Flow Status
38  * AE      Address Extension
39  * SA      Source Address
40  * TA      Target Address
41  */
42 
43 /*
44  * N_Result according to ISO 15765-2:2016
45  * ISOTP_ prefix is used to be zephyr conform
46  */
47 
48 /** Completed successfully */
49 #define ISOTP_N_OK              0
50 
51 /** Ar/As has timed out */
52 #define ISOTP_N_TIMEOUT_A      -1
53 
54 /** Reception of next FC has timed out */
55 #define ISOTP_N_TIMEOUT_BS     -2
56 
57 /** Cr has timed out */
58 #define ISOTP_N_TIMEOUT_CR     -3
59 
60 /** Unexpected sequence number */
61 #define ISOTP_N_WRONG_SN       -4
62 
63 /** Invalid flow status received*/
64 #define ISOTP_N_INVALID_FS     -5
65 
66 /** Unexpected PDU received */
67 #define ISOTP_N_UNEXP_PDU      -6
68 
69 /** Maximum number of WAIT flowStatus PDUs exceeded */
70 #define ISOTP_N_WFT_OVRN       -7
71 
72 /** FlowStatus OVFLW PDU was received */
73 #define ISOTP_N_BUFFER_OVERFLW -8
74 
75 /** General error */
76 #define ISOTP_N_ERROR          -9
77 
78 /** Implementation specific errors */
79 
80 /** Can't bind or send because the CAN device has no filter left*/
81 #define ISOTP_NO_FREE_FILTER    -10
82 
83 /** No net buffer left to allocate */
84 #define ISOTP_NO_NET_BUF_LEFT   -11
85 
86 /** Not sufficient space in the buffer left for the data */
87 #define ISOTP_NO_BUF_DATA_LEFT  -12
88 
89 /** No context buffer left to allocate */
90 #define ISOTP_NO_CTX_LEFT       -13
91 
92 /** Timeout for recv */
93 #define ISOTP_RECV_TIMEOUT      -14
94 
95 /*
96  * CAN ID filtering for ISO-TP fixed addressing according to SAE J1939
97  *
98  * Format of 29-bit CAN identifier:
99  * ------------------------------------------------------
100  * | 28 .. 26 | 25  | 24 | 23 .. 16 | 15 .. 8  | 7 .. 0 |
101  * ------------------------------------------------------
102  * | Priority | EDP | DP | N_TAtype |   N_TA   |  N_SA  |
103  * ------------------------------------------------------
104  */
105 
106 /** Position of fixed source address (SA) */
107 #define ISOTP_FIXED_ADDR_SA_POS         (0U)
108 
109 /** Mask to obtain fixed source address (SA) */
110 #define ISOTP_FIXED_ADDR_SA_MASK        (0xFF << ISOTP_FIXED_ADDR_SA_POS)
111 
112 /** Position of fixed target address (TA) */
113 #define ISOTP_FIXED_ADDR_TA_POS         (8U)
114 
115 /** Mask to obtain fixed target address (TA) */
116 #define ISOTP_FIXED_ADDR_TA_MASK        (0xFF << ISOTP_FIXED_ADDR_TA_POS)
117 
118 /** Position of priority in fixed addressing mode */
119 #define ISOTP_FIXED_ADDR_PRIO_POS       (26U)
120 
121 /** Mask for priority in fixed addressing mode */
122 #define ISOTP_FIXED_ADDR_PRIO_MASK      (0x7 << ISOTP_FIXED_ADDR_PRIO_POS)
123 
124 /* CAN filter RX mask to match any priority and source address (SA) */
125 #define ISOTP_FIXED_ADDR_RX_MASK        (0x03FFFF00)
126 
127 #ifdef __cplusplus
128 extern "C" {
129 #endif
130 
131 /**
132  * @brief ISO-TP message id struct
133  *
134  * Used to pass addresses to the bind and send functions.
135  */
136 struct isotp_msg_id {
137 	/**
138 	 * CAN identifier
139 	 *
140 	 * If ISO-TP fixed addressing is used, isotp_bind ignores SA and
141 	 * priority sections and modifies TA section in flow control frames.
142 	 */
143 	union {
144 		uint32_t std_id  : 11;
145 		uint32_t ext_id  : 29;
146 	};
147 	/** ISO-TP extended address (if used) */
148 	uint8_t ext_addr;
149 	/** Indicates the CAN identifier type (standard or extended) */
150 	uint8_t id_type : 1;
151 	/** Indicates if ISO-TP extended addressing is used */
152 	uint8_t use_ext_addr : 1;
153 	/** Indicates if ISO-TP fixed addressing (acc. to SAE J1939) is used */
154 	uint8_t use_fixed_addr : 1;
155 };
156 
157 /*
158  * STmin is split in two valid ranges:
159  *   0-127: 0ms-127ms
160  * 128-240: Reserved
161  * 241-249: 100us-900us (multiples of 100us)
162  * 250-   : Reserved
163  */
164 
165 /**
166  * @brief ISO-TP frame control options struct
167  *
168  * Used to pass the options to the bind and send functions.
169  */
170 struct isotp_fc_opts {
171 	uint8_t bs;    /**< Block size. Number of CF PDUs before next CF is sent */
172 	uint8_t stmin; /**< Minimum separation time. Min time between frames */
173 };
174 
175 typedef void (*isotp_tx_callback_t)(int error_nr, void *arg);
176 
177 struct isotp_send_ctx;
178 struct isotp_recv_ctx;
179 
180 /**
181  * @brief Bind an address to a receiving context.
182  *
183  * This function binds an RX and TX address combination to an RX context.
184  * When data arrives from the specified address, it is buffered and can be read
185  * by calling isotp_recv.
186  * When calling this routine, a filter is applied in the CAN device, and the
187  * context is initialized. The context must be valid until calling unbind.
188  *
189  * @param ctx     Context to store the internal states.
190  * @param can_dev The CAN device to be used for sending and receiving.
191  * @param rx_addr Identifier for incoming data.
192  * @param tx_addr Identifier for FC frames.
193  * @param opts    Flow control options.
194  * @param timeout Timeout for FF SF buffer allocation.
195  *
196  * @retval ISOTP_N_OK on success
197  * @retval ISOTP_NO_FREE_FILTER if CAN device has no filters left.
198  */
199 int isotp_bind(struct isotp_recv_ctx *ctx, const struct device *can_dev,
200 	       const struct isotp_msg_id *rx_addr,
201 	       const struct isotp_msg_id *tx_addr,
202 	       const struct isotp_fc_opts *opts,
203 	       k_timeout_t timeout);
204 
205 /**
206  * @brief Unbind a context from the interface
207  *
208  * This function removes the binding from isotp_bind.
209  * The filter is detached from the CAN device, and if a transmission is ongoing,
210  * buffers are freed.
211  * The context can be discarded safely after calling this function.
212  *
213  * @param ctx     Context that should be unbound.
214  */
215 void isotp_unbind(struct isotp_recv_ctx *ctx);
216 
217 /**
218  * @brief Read out received data from fifo.
219  *
220  * This function reads the data from the receive FIFO of the context.
221  * It blocks if the FIFO is empty.
222  * If an error occurs, the function returns a negative number and leaves the
223  * data buffer unchanged.
224  *
225  * @param ctx     Context that is already bound.
226  * @param data    Pointer to a buffer where the data is copied to.
227  * @param len     Size of the buffer.
228  * @param timeout Timeout for incoming data.
229  *
230  * @retval Number of bytes copied on success
231  * @retval ISOTP_WAIT_TIMEOUT when "timeout" timed out
232  * @retval ISOTP_N_* on error
233  */
234 int isotp_recv(struct isotp_recv_ctx *ctx, uint8_t *data, size_t len,
235 	       k_timeout_t timeout);
236 
237 /**
238  * @brief Get the net buffer on data reception
239  *
240  * This function reads incoming data into net-buffers.
241  * It blocks until the entire packet is received, BS is reached, or an error
242  * occurred. If BS was zero, the data is in a single net_buf. Otherwise,
243  * the data is fragmented in chunks of BS size.
244  * The net-buffers are referenced and must be freed with net_buf_unref after the
245  * data is processed.
246  *
247  * @param ctx     Context that is already bound.
248  * @param buffer  Pointer where the net_buf pointer is written to.
249  * @param timeout Timeout for incoming data.
250  *
251  * @retval Remaining data length for this transfer if BS > 0, 0 for BS = 0
252  * @retval ISOTP_WAIT_TIMEOUT when "timeout" timed out
253  * @retval ISOTP_N_* on error
254  */
255 int isotp_recv_net(struct isotp_recv_ctx *ctx, struct net_buf **buffer,
256 		   k_timeout_t timeout);
257 
258 /**
259  * @brief Send data
260  *
261  * This function is used to send data to a peer that listens to the tx_addr.
262  * An internal work-queue is used to transfer the segmented data.
263  * Data and context must be valid until the transmission has finished.
264  * If a complete_cb is given, this function is non-blocking, and the callback
265  * is called on completion with the return value as a parameter.
266  *
267  * @param ctx         Context to store the internal states.
268  * @param can_dev     The CAN device to be used for sending and receiving.
269  * @param data        Data to be sent.
270  * @param len         Length of the data to be sent.
271  * @param rx_addr     Identifier for FC frames.
272  * @param tx_addr     Identifier for outgoing frames the receiver listens on.
273  * @param complete_cb Function called on completion or NULL.
274  * @param cb_arg      Argument passed to the complete callback.
275  *
276  * @retval ISOTP_N_OK on success
277  * @retval ISOTP_N_* on error
278  */
279 int isotp_send(struct isotp_send_ctx *ctx, const struct device *can_dev,
280 	       const uint8_t *data, size_t len,
281 	       const struct isotp_msg_id *tx_addr,
282 	       const struct isotp_msg_id *rx_addr,
283 	       isotp_tx_callback_t complete_cb, void *cb_arg);
284 
285 #ifdef CONFIG_ISOTP_ENABLE_CONTEXT_BUFFERS
286 /**
287  * @brief Send data with buffered context
288  *
289  * This function is similar to isotp_send, but the context is automatically
290  * allocated from an internal pool.
291  *
292  * @param can_dev     The CAN device to be used for sending and receiving.
293  * @param data        Data to be sent.
294  * @param len         Length of the data to be sent.
295  * @param rx_addr     Identifier for FC frames.
296  * @param tx_addr     Identifier for outgoing frames the receiver listens on.
297  * @param complete_cb Function called on completion or NULL.
298  * @param cb_arg      Argument passed to the complete callback.
299  * @param timeout     Timeout for buffer allocation.
300  *
301  * @retval ISOTP_N_OK on success
302  * @retval ISOTP_N_* on error
303  */
304 int isotp_send_ctx_buf(const struct device *can_dev,
305 		       const uint8_t *data, size_t len,
306 		       const struct isotp_msg_id *tx_addr,
307 		       const struct isotp_msg_id *rx_addr,
308 		       isotp_tx_callback_t complete_cb, void *cb_arg,
309 		       k_timeout_t timeout);
310 
311 /**
312  * @brief Send data with buffered context
313  *
314  * This function is similar to isotp_send_ctx_buf, but the data is carried in
315  * a net_buf. net_buf_unref is called on the net_buf when sending is completed.
316  *
317  * @param can_dev     The CAN device to be used for sending and receiving.
318  * @param data        Data to be sent.
319  * @param len         Length of the data to be sent.
320  * @param rx_addr     Identifier for FC frames.
321  * @param tx_addr     Identifier for outgoing frames the receiver listens on.
322  * @param complete_cb Function called on completion or NULL.
323  * @param cb_arg      Argument passed to the complete callback.
324  * @param timeout     Timeout for buffer allocation.
325  *
326  * @retval ISOTP_N_OK on success
327  * @retval ISOTP_* on error
328  */
329 int isotp_send_net_ctx_buf(const struct device *can_dev,
330 			   struct net_buf *data,
331 			   const struct isotp_msg_id *tx_addr,
332 			   const struct isotp_msg_id *rx_addr,
333 			   isotp_tx_callback_t complete_cb, void *cb_arg,
334 			   k_timeout_t timeout);
335 
336 #endif /*CONFIG_ISOTP_ENABLE_CONTEXT_BUFFERS*/
337 
338 #if defined(CONFIG_ISOTP_USE_TX_BUF) && \
339 	defined(CONFIG_ISOTP_ENABLE_CONTEXT_BUFFERS)
340 /**
341  * @brief Send data with buffered context
342  *
343  * This function is similar to isotp_send, but the context is automatically
344  * allocated from an internal pool and the data to be send is buffered in an
345  * internal net_buff.
346  *
347  * @param can_dev     The CAN device to be used for sending and receiving.
348  * @param data        Data to be sent.
349  * @param len         Length of the data to be sent.
350  * @param rx_addr     Identifier for FC frames.
351  * @param tx_addr     Identifier for outgoing frames the receiver listens on.
352  * @param complete_cb Function called on completion or NULL.
353  * @param cb_arg      Argument passed to the complete callback.
354  * @param timeout     Timeout for buffer allocation.
355  *
356  * @retval ISOTP_N_OK on success
357  * @retval ISOTP_* on error
358  */
359 int isotp_send_buf(const struct device *can_dev,
360 		   const uint8_t *data, size_t len,
361 		   const struct isotp_msg_id *tx_addr,
362 		   const struct isotp_msg_id *rx_addr,
363 		   isotp_tx_callback_t complete_cb, void *cb_arg,
364 		   k_timeout_t timeout);
365 #endif
366 
367 /** @cond INTERNAL_HIDDEN */
368 
369 struct isotp_callback {
370 	isotp_tx_callback_t cb;
371 	void *arg;
372 };
373 
374 struct isotp_send_ctx {
375 	int filter_id;
376 	uint32_t error_nr;
377 	const struct device *can_dev;
378 	union {
379 		struct net_buf *buf;
380 		struct {
381 			const uint8_t *data;
382 			size_t len;
383 		};
384 	};
385 	struct k_work work;
386 	struct _timeout timeout;
387 	union {
388 		struct isotp_callback fin_cb;
389 		struct k_sem fin_sem;
390 	};
391 	struct isotp_fc_opts opts;
392 	uint8_t state;
393 	uint8_t tx_backlog;
394 	struct isotp_msg_id rx_addr;
395 	struct isotp_msg_id tx_addr;
396 	uint8_t wft;
397 	uint8_t bs;
398 	uint8_t sn : 4;
399 	uint8_t is_net_buf  : 1;
400 	uint8_t is_ctx_slab : 1;
401 	uint8_t has_callback: 1;
402 };
403 
404 struct isotp_recv_ctx {
405 	int filter_id;
406 	const struct device *can_dev;
407 	struct net_buf *buf;
408 	struct net_buf *act_frag;
409 	sys_snode_t alloc_node;
410 	uint32_t length;
411 	int error_nr;
412 	struct k_work work;
413 	struct _timeout timeout;
414 	struct k_fifo fifo;
415 	struct isotp_msg_id rx_addr;
416 	struct isotp_msg_id tx_addr;
417 	struct isotp_fc_opts opts;
418 	uint8_t state;
419 	uint8_t bs;
420 	uint8_t wft;
421 	uint8_t sn_expected : 4;
422 };
423 
424 /** @endcond */
425 
426 /**
427  * @}
428  */
429 
430 #ifdef __cplusplus
431 }
432 #endif
433 
434 #endif /* ZEPHYR_INCLUDE_ISOTP_H_ */
435