/** @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_ */
