5d5249d85b
Unify spelling of CAN Flexible Data-rate abbreviation to "CAN FD" instead of "CAN-FD". The former aligns with the CAN in Automation (CiA) recommendation. Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
484 lines
14 KiB
C
484 lines
14 KiB
C
/*
|
|
* 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_ */
|