| /* |
| * Copyright (c) 2019 Alexander Wachter |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /** |
| * @file |
| * @brief Public API for ISO-TP (ISO 15765-2:2016) |
| * |
| * ISO-TP is a transport protocol for CAN (Controller Area Network) |
| */ |
| |
| #ifndef ZEPHYR_INCLUDE_CANBUS_ISOTP_H_ |
| #define ZEPHYR_INCLUDE_CANBUS_ISOTP_H_ |
| |
| /** |
| * @brief CAN ISO-TP Protocol |
| * @defgroup can_isotp CAN ISO-TP Protocol |
| * @ingroup connectivity |
| * @{ |
| */ |
| |
| #include <zephyr/drivers/can.h> |
| #include <zephyr/types.h> |
| #include <zephyr/net/buf.h> |
| |
| /* |
| * Abbreviations |
| * BS Block Size |
| * CAN_DL CAN LL data size |
| * CF Consecutive Frame |
| * CTS Continue to send |
| * DLC Data length code |
| * FC Flow Control |
| * FF First Frame |
| * SF Single Frame |
| * FS Flow Status |
| * AE Address Extension |
| * SN Sequence Number |
| * ST Separation time |
| * SA Source Address |
| * TA Target Address |
| * RX_DL CAN RX LL data size |
| * TX_DL CAN TX LL data size |
| * PCI Process Control Information |
| */ |
| |
| /* |
| * N_Result according to ISO 15765-2:2016 |
| * ISOTP_ prefix is used to be zephyr conform |
| */ |
| |
| /** Completed successfully */ |
| #define ISOTP_N_OK 0 |
| |
| /** Ar/As has timed out */ |
| #define ISOTP_N_TIMEOUT_A -1 |
| |
| /** Reception of next FC has timed out */ |
| #define ISOTP_N_TIMEOUT_BS -2 |
| |
| /** Cr has timed out */ |
| #define ISOTP_N_TIMEOUT_CR -3 |
| |
| /** Unexpected sequence number */ |
| #define ISOTP_N_WRONG_SN -4 |
| |
| /** Invalid flow status received*/ |
| #define ISOTP_N_INVALID_FS -5 |
| |
| /** Unexpected PDU received */ |
| #define ISOTP_N_UNEXP_PDU -6 |
| |
| /** Maximum number of WAIT flowStatus PDUs exceeded */ |
| #define ISOTP_N_WFT_OVRN -7 |
| |
| /** FlowStatus OVFLW PDU was received */ |
| #define ISOTP_N_BUFFER_OVERFLW -8 |
| |
| /** General error */ |
| #define ISOTP_N_ERROR -9 |
| |
| /** Implementation specific errors */ |
| |
| /** Can't bind or send because the CAN device has no filter left*/ |
| #define ISOTP_NO_FREE_FILTER -10 |
| |
| /** No net buffer left to allocate */ |
| #define ISOTP_NO_NET_BUF_LEFT -11 |
| |
| /** Not sufficient space in the buffer left for the data */ |
| #define ISOTP_NO_BUF_DATA_LEFT -12 |
| |
| /** No context buffer left to allocate */ |
| #define ISOTP_NO_CTX_LEFT -13 |
| |
| /** Timeout for recv */ |
| #define ISOTP_RECV_TIMEOUT -14 |
| |
| /* |
| * CAN ID filtering for ISO-TP fixed addressing according to SAE J1939 |
| * |
| * Format of 29-bit CAN identifier: |
| * ------------------------------------------------------ |
| * | 28 .. 26 | 25 | 24 | 23 .. 16 | 15 .. 8 | 7 .. 0 | |
| * ------------------------------------------------------ |
| * | Priority | EDP | DP | N_TAtype | N_TA | N_SA | |
| * ------------------------------------------------------ |
| */ |
| |
| /** Position of fixed source address (SA) */ |
| #define ISOTP_FIXED_ADDR_SA_POS (CONFIG_ISOTP_FIXED_ADDR_SA_POS) |
| |
| /** Mask to obtain fixed source address (SA) */ |
| #define ISOTP_FIXED_ADDR_SA_MASK (CONFIG_ISOTP_FIXED_ADDR_SA_MASK) |
| |
| /** Position of fixed target address (TA) */ |
| #define ISOTP_FIXED_ADDR_TA_POS (CONFIG_ISOTP_FIXED_ADDR_TA_POS) |
| |
| /** Mask to obtain fixed target address (TA) */ |
| #define ISOTP_FIXED_ADDR_TA_MASK (CONFIG_ISOTP_FIXED_ADDR_TA_MASK) |
| |
| /** Position of priority in fixed addressing mode */ |
| #define ISOTP_FIXED_ADDR_PRIO_POS (CONFIG_ISOTP_FIXED_ADDR_PRIO_POS) |
| |
| /** Mask for priority in fixed addressing mode */ |
| #define ISOTP_FIXED_ADDR_PRIO_MASK (CONFIG_ISOTP_FIXED_ADDR_PRIO_MASK) |
| |
| /** CAN filter RX mask to match any priority and source address (SA) */ |
| #define ISOTP_FIXED_ADDR_RX_MASK (CONFIG_ISOTP_FIXED_ADDR_RX_MASK) |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @name ISO-TP message ID flags |
| * @anchor ISOTP_MSG_FLAGS |
| * |
| * @{ |
| */ |
| |
| /** Message uses ISO-TP extended addressing (first payload byte of CAN frame) */ |
| #define ISOTP_MSG_EXT_ADDR BIT(0) |
| |
| /** |
| * Message uses ISO-TP fixed addressing (according to SAE J1939). Only valid in combination with |
| * ``ISOTP_MSG_IDE``. |
| */ |
| #define ISOTP_MSG_FIXED_ADDR BIT(1) |
| |
| /** Message uses extended (29-bit) CAN ID */ |
| #define ISOTP_MSG_IDE BIT(2) |
| |
| /** Message uses CAN FD format (FDF) */ |
| #define ISOTP_MSG_FDF BIT(3) |
| |
| /** Message uses CAN FD Baud Rate Switch (BRS). Only valid in combination with ``ISOTP_MSG_FDF``. */ |
| #define ISOTP_MSG_BRS BIT(4) |
| |
| /** @} */ |
| |
| /** |
| * @brief ISO-TP message id struct |
| * |
| * Used to pass addresses to the bind and send functions. |
| */ |
| struct isotp_msg_id { |
| /** |
| * CAN identifier |
| * |
| * If ISO-TP fixed addressing is used, isotp_bind ignores SA and |
| * priority sections and modifies TA section in flow control frames. |
| */ |
| union { |
| uint32_t std_id : 11; |
| uint32_t ext_id : 29; |
| }; |
| /** ISO-TP extended address (if used) */ |
| uint8_t ext_addr; |
| /** |
| * ISO-TP frame data length (TX_DL for TX address or RX_DL for RX address). |
| * |
| * Valid values are 8 for classical CAN or 8, 12, 16, 20, 24, 32, 48 and 64 for CAN FD. |
| * |
| * 0 will be interpreted as 8 or 64 (if ISOTP_MSG_FDF is set). |
| * |
| * The value for incoming transmissions (RX_DL) is determined automatically based on the |
| * received first frame and does not need to be set during initialization. |
| */ |
| uint8_t dl; |
| /** Flags. @see @ref ISOTP_MSG_FLAGS. */ |
| uint8_t flags; |
| }; |
| |
| /* |
| * STmin is split in two valid ranges: |
| * 0-127: 0ms-127ms |
| * 128-240: Reserved |
| * 241-249: 100us-900us (multiples of 100us) |
| * 250- : Reserved |
| */ |
| |
| /** |
| * @brief ISO-TP frame control options struct |
| * |
| * Used to pass the options to the bind and send functions. |
| */ |
| struct isotp_fc_opts { |
| uint8_t bs; /**< Block size. Number of CF PDUs before next CF is sent */ |
| uint8_t stmin; /**< Minimum separation time. Min time between frames */ |
| }; |
| |
| /** |
| * @brief Transmission callback |
| * |
| * This callback is called when a transmission is completed. |
| * |
| * @param error_nr ISOTP_N_OK on success, ISOTP_N_* on error |
| * @param arg Callback argument passed to the send function |
| */ |
| typedef void (*isotp_tx_callback_t)(int error_nr, void *arg); |
| |
| struct isotp_send_ctx; |
| struct isotp_recv_ctx; |
| |
| /** |
| * @brief Bind an address to a receiving context. |
| * |
| * This function binds an RX and TX address combination to an RX context. |
| * When data arrives from the specified address, it is buffered and can be read |
| * by calling isotp_recv. |
| * When calling this routine, a filter is applied in the CAN device, and the |
| * context is initialized. The context must be valid until calling unbind. |
| * |
| * @param rctx Context to store the internal states. |
| * @param can_dev The CAN device to be used for sending and receiving. |
| * @param rx_addr Identifier for incoming data. |
| * @param tx_addr Identifier for FC frames. |
| * @param opts Flow control options. |
| * @param timeout Timeout for FF SF buffer allocation. |
| * |
| * @retval ISOTP_N_OK on success |
| * @retval ISOTP_NO_FREE_FILTER if CAN device has no filters left. |
| */ |
| int isotp_bind(struct isotp_recv_ctx *rctx, const struct device *can_dev, |
| const struct isotp_msg_id *rx_addr, |
| const struct isotp_msg_id *tx_addr, |
| const struct isotp_fc_opts *opts, |
| k_timeout_t timeout); |
| |
| /** |
| * @brief Unbind a context from the interface |
| * |
| * This function removes the binding from isotp_bind. |
| * The filter is detached from the CAN device, and if a transmission is ongoing, |
| * buffers are freed. |
| * The context can be discarded safely after calling this function. |
| * |
| * @param rctx Context that should be unbound. |
| */ |
| void isotp_unbind(struct isotp_recv_ctx *rctx); |
| |
| /** |
| * @brief Read out received data from fifo. |
| * |
| * This function reads the data from the receive FIFO of the context. |
| * It blocks if the FIFO is empty. |
| * If an error occurs, the function returns a negative number and leaves the |
| * data buffer unchanged. |
| * |
| * @param rctx Context that is already bound. |
| * @param data Pointer to a buffer where the data is copied to. |
| * @param len Size of the buffer. |
| * @param timeout Timeout for incoming data. |
| * |
| * @retval Number of bytes copied on success |
| * @retval ISOTP_RECV_TIMEOUT when "timeout" timed out |
| * @retval ISOTP_N_* on error |
| */ |
| int isotp_recv(struct isotp_recv_ctx *rctx, uint8_t *data, size_t len, k_timeout_t timeout); |
| |
| /** |
| * @brief Get the net buffer on data reception |
| * |
| * This function reads incoming data into net-buffers. |
| * It blocks until the entire packet is received, BS is reached, or an error |
| * occurred. If BS was zero, the data is in a single net_buf. Otherwise, |
| * the data is fragmented in chunks of BS size. |
| * The net-buffers are referenced and must be freed with net_buf_unref after the |
| * data is processed. |
| * |
| * @param rctx Context that is already bound. |
| * @param buffer Pointer where the net_buf pointer is written to. |
| * @param timeout Timeout for incoming data. |
| * |
| * @retval Remaining data length for this transfer if BS > 0, 0 for BS = 0 |
| * @retval ISOTP_RECV_TIMEOUT when "timeout" timed out |
| * @retval ISOTP_N_* on error |
| */ |
| int isotp_recv_net(struct isotp_recv_ctx *rctx, struct net_buf **buffer, k_timeout_t timeout); |
| |
| /** |
| * @brief Send data |
| * |
| * This function is used to send data to a peer that listens to the tx_addr. |
| * An internal work-queue is used to transfer the segmented data. |
| * Data and context must be valid until the transmission has finished. |
| * If a complete_cb is given, this function is non-blocking, and the callback |
| * is called on completion with the return value as a parameter. |
| * |
| * @param sctx Context to store the internal states. |
| * @param can_dev The CAN device to be used for sending and receiving. |
| * @param data Data to be sent. |
| * @param len Length of the data to be sent. |
| * @param rx_addr Identifier for FC frames. |
| * @param tx_addr Identifier for outgoing frames the receiver listens on. |
| * @param complete_cb Function called on completion or NULL. |
| * @param cb_arg Argument passed to the complete callback. |
| * |
| * @retval ISOTP_N_OK on success |
| * @retval ISOTP_N_* on error |
| */ |
| int isotp_send(struct isotp_send_ctx *sctx, const struct device *can_dev, |
| const uint8_t *data, size_t len, |
| const struct isotp_msg_id *tx_addr, |
| const struct isotp_msg_id *rx_addr, |
| isotp_tx_callback_t complete_cb, void *cb_arg); |
| |
| #ifdef CONFIG_ISOTP_ENABLE_CONTEXT_BUFFERS |
| /** |
| * @brief Send data with buffered context |
| * |
| * This function is similar to isotp_send, but the context is automatically |
| * allocated from an internal pool. |
| * |
| * @param can_dev The CAN device to be used for sending and receiving. |
| * @param data Data to be sent. |
| * @param len Length of the data to be sent. |
| * @param rx_addr Identifier for FC frames. |
| * @param tx_addr Identifier for outgoing frames the receiver listens on. |
| * @param complete_cb Function called on completion or NULL. |
| * @param cb_arg Argument passed to the complete callback. |
| * @param timeout Timeout for buffer allocation. |
| * |
| * @retval ISOTP_N_OK on success |
| * @retval ISOTP_N_* on error |
| */ |
| int isotp_send_ctx_buf(const struct device *can_dev, |
| const uint8_t *data, size_t len, |
| const struct isotp_msg_id *tx_addr, |
| const struct isotp_msg_id *rx_addr, |
| isotp_tx_callback_t complete_cb, void *cb_arg, |
| k_timeout_t timeout); |
| |
| /** |
| * @brief Send data with buffered context |
| * |
| * This function is similar to isotp_send_ctx_buf, but the data is carried in |
| * a net_buf. net_buf_unref is called on the net_buf when sending is completed. |
| * |
| * @param can_dev The CAN device to be used for sending and receiving. |
| * @param data Data to be sent. |
| * @param len Length of the data to be sent. |
| * @param rx_addr Identifier for FC frames. |
| * @param tx_addr Identifier for outgoing frames the receiver listens on. |
| * @param complete_cb Function called on completion or NULL. |
| * @param cb_arg Argument passed to the complete callback. |
| * @param timeout Timeout for buffer allocation. |
| * |
| * @retval ISOTP_N_OK on success |
| * @retval ISOTP_* on error |
| */ |
| int isotp_send_net_ctx_buf(const struct device *can_dev, |
| struct net_buf *data, |
| const struct isotp_msg_id *tx_addr, |
| const struct isotp_msg_id *rx_addr, |
| isotp_tx_callback_t complete_cb, void *cb_arg, |
| k_timeout_t timeout); |
| |
| #endif /*CONFIG_ISOTP_ENABLE_CONTEXT_BUFFERS*/ |
| |
| #if defined(CONFIG_ISOTP_USE_TX_BUF) && \ |
| defined(CONFIG_ISOTP_ENABLE_CONTEXT_BUFFERS) |
| /** |
| * @brief Send data with buffered context |
| * |
| * This function is similar to isotp_send, but the context is automatically |
| * allocated from an internal pool and the data to be send is buffered in an |
| * internal net_buff. |
| * |
| * @param can_dev The CAN device to be used for sending and receiving. |
| * @param data Data to be sent. |
| * @param len Length of the data to be sent. |
| * @param rx_addr Identifier for FC frames. |
| * @param tx_addr Identifier for outgoing frames the receiver listens on. |
| * @param complete_cb Function called on completion or NULL. |
| * @param cb_arg Argument passed to the complete callback. |
| * @param timeout Timeout for buffer allocation. |
| * |
| * @retval ISOTP_N_OK on success |
| * @retval ISOTP_* on error |
| */ |
| int isotp_send_buf(const struct device *can_dev, |
| const uint8_t *data, size_t len, |
| const struct isotp_msg_id *tx_addr, |
| const struct isotp_msg_id *rx_addr, |
| isotp_tx_callback_t complete_cb, void *cb_arg, |
| k_timeout_t timeout); |
| #endif |
| |
| /** @cond INTERNAL_HIDDEN */ |
| |
| struct isotp_callback { |
| isotp_tx_callback_t cb; |
| void *arg; |
| }; |
| |
| struct isotp_send_ctx { |
| int filter_id; |
| uint32_t error_nr; |
| const struct device *can_dev; |
| union { |
| struct net_buf *buf; |
| struct { |
| const uint8_t *data; |
| size_t len; |
| }; |
| }; |
| struct k_work work; |
| struct k_timer timer; |
| union { |
| struct isotp_callback fin_cb; |
| struct k_sem fin_sem; |
| }; |
| struct isotp_fc_opts opts; |
| uint8_t state; |
| uint8_t tx_backlog; |
| struct k_sem tx_sem; |
| struct isotp_msg_id rx_addr; |
| struct isotp_msg_id tx_addr; |
| uint8_t wft; |
| uint8_t bs; |
| uint8_t sn : 4; |
| uint8_t is_net_buf : 1; |
| uint8_t is_ctx_slab : 1; |
| uint8_t has_callback: 1; |
| }; |
| |
| struct isotp_recv_ctx { |
| int filter_id; |
| const struct device *can_dev; |
| struct net_buf *buf; |
| struct net_buf *act_frag; |
| /* buffer currently processed in isotp_recv */ |
| struct net_buf *recv_buf; |
| sys_snode_t alloc_node; |
| uint32_t length; |
| int error_nr; |
| struct k_work work; |
| struct k_timer timer; |
| struct k_fifo fifo; |
| struct isotp_msg_id rx_addr; |
| struct isotp_msg_id tx_addr; |
| struct isotp_fc_opts opts; |
| uint8_t state; |
| uint8_t bs; |
| uint8_t wft; |
| uint8_t sn_expected : 4; |
| }; |
| |
| /** @endcond */ |
| |
| /** |
| * @} |
| */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* ZEPHYR_INCLUDE_CANBUS_ISOTP_H_ */ |