blob: c9d2d840bc30938e18fdd7b8c675621846a2b7dc [file] [log] [blame]
/** @file
* @brief IPv6 Networking over CAN definitions.
*
* Definitions for IPv6 Networking over CAN support.
*/
/*
* Copyright (c) 2019 Alexander Wachter
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_NET_CAN_H_
#define ZEPHYR_INCLUDE_NET_CAN_H_
#include <zephyr/types.h>
#include <net/net_ip.h>
#include <net/net_if.h>
#include <drivers/can.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief IPv6 over CAN library
* @defgroup net_can Network Core Library
* @ingroup networking
* @{
*/
/**
* CAN L2 driver API. Used by 6loCAN.
*/
/*
* 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
*/
/** @cond INTERNAL_HIDDEN */
#define NET_CAN_DL 8
#define NET_CAN_MTU 0x0FFF
/* 0x3DFF - bit 4 to 10 must not be zero. Also prevent stuffing bit*/
#define NET_CAN_MULTICAST_ADDR 0x3DFF
#define NET_CAN_DAD_ADDR 0x3DFE
#define NET_CAN_ETH_TRANSLATOR_ADDR 0x3DF0
#define NET_CAN_MAX_ADDR 0x3DEF
#define NET_CAN_MIN_ADDR 0x0100
#define CAN_NET_IF_ADDR_MASK 0x3FFF
#define CAN_NET_IF_ADDR_BYTE_LEN 2U
#define CAN_NET_IF_ADDR_DEST_POS 14U
#define CAN_NET_IF_ADDR_DEST_MASK (CAN_NET_IF_ADDR_MASK << CAN_NET_IF_ADDR_DEST_POS)
#define CAN_NET_IF_ADDR_SRC_POS 0U
#define CAN_NET_IF_ADDR_SRC_MASK (CAN_NET_IF_ADDR_MASK << CAN_NET_IF_ADDR_SRC_POS)
#define CAN_NET_IF_ADDR_MCAST_POS 28U
#define CAN_NET_IF_ADDR_MCAST_MASK (1UL << CAN_NET_IF_ADDR_MCAST_POS)
#define CAN_NET_IF_IS_MCAST_BIT (1U << 14)
#define CAN_NET_FILTER_NOT_SET -1
/** @endcond */
/*
* +-----------+ +-----------+
* | | | |
* | IPv6 | | IPv6 |
* | 6LoCAN | | 6LoCAN |
* | | | |
* +----+-+----+ +----+-+----+
* | | | | +---+
* +----+ | | | | / \ +-+
* | | | | | | +--+ / \_/ \
* +++ +---+ +--+----+ +-------+ +--+----+ +--/ \_/ \
* | | \ / | \ / \ / | \ / / |
* | | X | X CAN X | X | Internet |
* | | / \ | / \ / \ | / \ \ /
* +++ +---+ +----+--+ +-------+ +----+--+ +--+ /
* | | +-------------------+
* +----+
*/
struct net_can_api {
/**
* The net_if_api must be placed in first position in this
* struct so that we are compatible with network interface API.
*/
struct net_if_api iface_api;
/** Send a single CAN frame */
int (*send)(const struct device *dev, const struct zcan_frame *frame,
can_tx_callback_t cb, void *cb_arg, k_timeout_t timeout);
/** Attach a filter with it's callback */
int (*attach_filter)(const struct device *dev, can_rx_callback_t cb,
void *cb_arg, const struct zcan_filter *filter);
/** Detach a filter */
void (*detach_filter)(const struct device *dev, int filter_id);
/** Enable or disable the reception of frames for net CAN */
int (*enable)(const struct device *dev, bool enable);
};
/* Make sure that the network interface API is properly setup inside
* net_can_api struct (it is the first one).
*/
BUILD_ASSERT(offsetof(struct net_can_api, iface_api) == 0);
/** @cond INTERNAL_HIDDEN */
#define CANBUS_L2_CTX_TYPE struct net_canbus_context *
/**
* Context for canbus net device.
*/
struct canbus_net_ctx {
/** Filter ID for link layer duplicate address detection. */
int dad_filter_id;
/** Work item for responding to link layer DAD requests. */
struct k_work dad_work;
/** The interface associated with this device */
struct net_if *iface;
/** The link layer address chosen for this interface */
uint16_t ll_addr;
/** TX queue */
struct k_fifo tx_queue;
/** RX error queue */
struct k_fifo rx_err_queue;
/** Queue handler thread */
struct k_thread queue_handler;
/** Queue handler thread stack */
K_KERNEL_STACK_MEMBER(queue_stack, 512);
};
/**
* Canbus link layer addresses have a length of 14 bit for source and destination.
* Both together are 28 bit to fit a CAN extended identifier with 29 bit length.
*/
struct net_canbus_lladdr {
uint16_t addr : 14;
};
/**
* STmin is split in two valid ranges:
* 0-127: 0ms-127ms
* 128-240: Reserved
* 241-249: 100us-900us (multiples of 100us)
* 250- : Reserved
*/
struct canbus_fc_opts {
/** Block size. Number of CF PDUs before next CF is sent */
uint8_t bs;
/**< Minimum separation time. Min time between frames */
uint8_t stmin;
};
/**
* Context for a transmission of messages that didn't fit in a single frame.
* These messages Start with a FF (First Frame) that is in case of unicast
* acknowledged by a FC (Frame Control). After that, one or more CF
* (Consecutive frames) carry the rest of the message.
*/
struct canbus_isotp_tx_ctx {
/** Pkt containing the data to transmit */
struct net_pkt *pkt;
/** Timeout for TX Timeout and separation time */
struct _timeout timeout;
/** Frame Control options received from FC frame */
struct canbus_fc_opts opts;
/** CAN destination address */
struct net_canbus_lladdr dest_addr;
/** Remaining data to transmit in bytes */
uint16_t rem_len;
/** Number of bytes in the tx queue */
int8_t tx_backlog;
/** State of the transmission */
uint8_t state;
/** Actual block number that is transmitted. Counts from BS to 0 */
uint8_t act_block_nr;
/** Number of WAIT frames received */
uint8_t wft;
/** Sequence number that is added to CF */
uint8_t sn : 4;
/** Transmission is multicast */
uint8_t is_mcast : 1;
};
/**
* Context for reception of messages that are not single frames.
* This is the counterpart of the canbus_isotp_tx_ctx.
*/
struct canbus_isotp_rx_ctx {
/** Pkt that is large enough to hold the entire message */
struct net_pkt *pkt;
/** Timeout for RX timeout*/
struct _timeout timeout;
/** Remaining data to receive. Goes from message length to zero */
uint16_t rem_len;
/** State of the reception */
uint8_t state;
/** Number of frames received in this block. Counts from BS to 0 */
uint8_t act_block_nr;
/** Number of WAIT frames transmitted */
uint8_t wft;
/** Expected sequence number in CF */
uint8_t sn : 4;
};
/**
* Initialization of the canbus L2.
*
* This function starts the TX workqueue and does some initialization.
*/
void net_6locan_init(struct net_if *iface);
/**
* Ethernet frame input function for Ethernet to 6LoCAN translation
*
* This function checks the destination link layer address for addresses
* that has to be forwarded. Frames that need to be forwarded are forwarded here.
*/
enum net_verdict net_canbus_translate_eth_frame(struct net_if *iface,
struct net_pkt *pkt);
/** @endcond */
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_NET_CAN_H_ */