| /* |
| * 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_ISOTP_H_ |
| #define ZEPHYR_INCLUDE_ISOTP_H_ |
| |
| /** |
| * @brief CAN ISO-TP Interf |
| * @defgroup can_isotp CAN ISO-TP Interface |
| * @ingroup CAN |
| * @{ |
| */ |
| |
| #include <drivers/can.h> |
| #include <zephyr/types.h> |
| #include <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 |
| * FS Flow Status |
| * AE Adders Extension |
| */ |
| |
| /* |
| * 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 |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @brief ISO-TP message id struct |
| * |
| * Used to pass addresses to the bind and send functions. |
| */ |
| struct isotp_msg_id { |
| /** Message identifier*/ |
| union { |
| uint32_t std_id : 11; |
| uint32_t ext_id : 29; |
| }; |
| /** extended address */ |
| uint8_t ext_addr; |
| /** Indicates the identifier type (standard or extended) */ |
| uint8_t id_type : 1; |
| /** Indicates if extended addressing is used */ |
| uint8_t use_ext_addr : 1; |
| }; |
| |
| /* |
| * 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 */ |
| }; |
| |
| 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 ctx 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 *ctx, 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 ctx Context that should be unbound. |
| */ |
| void isotp_unbind(struct isotp_recv_ctx *ctx); |
| |
| /** |
| * @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 ctx 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_WAIT_TIMEOUT when "timeout" timed out |
| * @retval ISOTP_N_* on error |
| */ |
| int isotp_recv(struct isotp_recv_ctx *ctx, 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 ctx 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_WAIT_TIMEOUT when "timeout" timed out |
| * @retval ISOTP_N_* on error |
| */ |
| int isotp_recv_net(struct isotp_recv_ctx *ctx, 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 ctx 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 *ctx, 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 _timeout timeout; |
| union { |
| struct isotp_callback fin_cb; |
| struct k_sem fin_sem; |
| }; |
| struct isotp_fc_opts opts; |
| uint8_t state; |
| uint8_t tx_backlog; |
| 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; |
| sys_snode_t alloc_node; |
| uint32_t length; |
| int error_nr; |
| struct k_work work; |
| struct _timeout timeout; |
| 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_ISOTP_H_ */ |