/* * 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 #include #include /* * 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, 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, 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(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(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(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; 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; 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_ */