can: isotp: Add ISO-TP library
This commit adds a ISO-TP (ISO15765-2) library. The library makes use of net buffers and spawns a workqueue thread. The CAN device that is passed to bind and send can be used concurrently beside this library. Signed-off-by: Alexander Wachter <alexander.wachter@student.tugraz.at>
This commit is contained in:
parent
07ecb817ff
commit
55baaf0365
7 changed files with 1924 additions and 0 deletions
393
include/canbus/isotp.h
Normal file
393
include/canbus/isotp.h
Normal file
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* 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 {
|
||||
u32_t std_id : 11;
|
||||
u32_t ext_id : 29;
|
||||
};
|
||||
/** extended address */
|
||||
u8_t ext_addr;
|
||||
/** Indicates the identifier type (standard or extended) */
|
||||
u8_t id_type : 1;
|
||||
/** Indicates if extended addressing is used */
|
||||
u8_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 {
|
||||
u8_t bs; /**< Block size. Number of CF PDUs before next CF is sent */
|
||||
u8_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,
|
||||
s32_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, u8_t *data, size_t len,
|
||||
s32_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,
|
||||
s32_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 u8_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 u8_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,
|
||||
s32_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,
|
||||
s32_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 u8_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,
|
||||
s32_t timeout);
|
||||
#endif
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
|
||||
struct isotp_callback {
|
||||
isotp_tx_callback_t cb;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
struct isotp_send_ctx {
|
||||
int filter_id;
|
||||
u32_t error_nr;
|
||||
struct device *can_dev;
|
||||
union {
|
||||
struct net_buf *buf;
|
||||
struct {
|
||||
const u8_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;
|
||||
u8_t state;
|
||||
u8_t tx_backlog;
|
||||
struct isotp_msg_id rx_addr;
|
||||
struct isotp_msg_id tx_addr;
|
||||
u8_t wft;
|
||||
u8_t bs;
|
||||
u8_t sn : 4;
|
||||
u8_t is_net_buf : 1;
|
||||
u8_t is_ctx_slab : 1;
|
||||
u8_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;
|
||||
u32_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;
|
||||
u8_t state;
|
||||
u8_t bs;
|
||||
u8_t wft;
|
||||
u8_t sn_expected : 4;
|
||||
};
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_ISOTP_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue