/*
 * CAN-FD extension to PEAK-System CAN products.
 *
 * Copyright (C) 2015 Stephane Grosjean <s.grosjean@peak-system.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published
 * by the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */
#ifndef __PCANFD_H__
#define __PCANFD_H__

#if 0
#include <linux/types.h>
#include <linux/ioctl.h>

/* ioctls values */
#define PCAN_MAGIC_NUMBER	'z'
#define PCAN_SEQ_START		0x80

#else

/* include the (old) CAN 2.0 API */
#include "pcan.h"

#endif

/* enable to define types including array with 0, 1 or more items */
#define __array_of_struct(_n, _x)					\
	_n##s_##_x {							\
		__u32		count;					\
		struct _n	list[_x];				\
	}

/* Type values */
#define PCANFD_TYPE_NOP		0
#define PCANFD_TYPE_CAN20_MSG	1
#define PCANFD_TYPE_CANFD_MSG	2
#define PCANFD_TYPE_STATUS	3

/* [PCANFD_TYPE_CAN20_MSG]
 * [PCANFD_TYPE_CANFD_MSG]
 *
 * flags bits definition (lowest byte is backward compatible with old MSGTYPE)
 */
#define PCANFD_MSG_STD		0x00000000
#define PCANFD_MSG_RTR		0x00000001
#define PCANFD_MSG_EXT		0x00000002
#define PCANFD_MSG_SLF		0x00000004
#define PCANFD_MSG_SNG		0x00000008

/* new bits indicate valid values in the corresponding fields */
#define PCANFD_TIMESTAMP	0x01000000
#define PCANFD_HWTIMESTAMP	0x02000000
#define PCANFD_ERRCNT		0x10000000
#define PCANFD_BUSLOAD		0x20000000

/* CAN-FD */
#define PCANFD_MSG_BRS		0x00100000
#define PCANFD_MSG_ESI		0x00200000

/* [PCANFD_TYPE_STATUS]
 *
 * flags bits definition: indicate the kind of error/status:
 */
#define PCANFD_ERROR_BUS	0x00000080	/* Bus status */
#define PCANFD_ERROR_PROTOCOL	0x00000100	/* Protocol error */
#define PCANFD_ERROR_CTRLR	0x00000200	/* Controller error */
#define PCANFD_ERROR_INTERNAL	0x00000400	/* Internal error */

/* [PCANFD_TYPE_STATUS]
 *
 * id field values:
 */
enum pcanfd_status {

	PCANFD_UNKNOWN,

	/* flags & PCANFD_ERROR_BUS.
	 * event id. is the state of the Bus */
	PCANFD_ERROR_ACTIVE,
	PCANFD_ERROR_WARNING,
	PCANFD_ERROR_PASSIVE,		/* receive only state */
	PCANFD_ERROR_BUSOFF,		/* switched off from the bus */

	/* flags & PCANFD_ERROR_CTRLR|PCANFD_ERROR_INTERNAL.
	 * event id. is one of the following error: */
	PCANFD_RX_EMPTY,
	PCANFD_RX_OVERFLOW,
	PCANFD_TX_EMPTY,
	PCANFD_TX_OVERFLOW,

	PCANFD_BUS_LOAD,

	PCANFD_STATUS_COUNT
};

#define PCAN_MAXDATALEN		8
#define PCANFD_MAXDATALEN	64

/* indexes describing content of ctrlr_data array
 * (see PCANFD_*/
enum pcanfd_ctrlr_data {
	PCANFD_RXERRCNT,
	PCANFD_TXERRCNT,
	PCANFD_BUSLOAD_UNIT,
	PCANFD_BUSLOAD_DEC,

	PCANFD_MAXCTRLRDATALEN
};

/* define new API with CAN-FD support */
struct pcanfd_msg {
	__u16		type;		/* PCANFD_TYPE_xxx */
	__u16		data_len;	/* true length (not the DLC) */
	__u32		id;		/* CAN / STATUS Id. */
	__u32		flags;		/* PCANFD_xxx definitions */
	struct timeval	timestamp;	/* timestamp of the event */
	__u8		ctrlr_data[PCANFD_MAXCTRLRDATALEN];
	__u8		data[PCANFD_MAXDATALEN] __attribute__((aligned(8)));
};

/* messages list base type (0 item list) */
struct __array_of_struct(pcanfd_msg, 0);

#define pcanfd_msgs		pcanfd_msgs_0

/* rule: 
 * if "bitrate" is not 0, then it is used,
 * if "bitrate" is 0, then all other 4 fields are used instead if all are not 0
 */
struct pcan_bittiming {
	__u32	brp;
	__u32	tseg1;
	__u32	tseg2;
	__u32	sjw;
	__u32	tsam;		/* triple sampling */

	__u32	bitrate;	/* bps */
	__u32	sample_point;	/* in 1/100 th of % (7500 = 75.00%) */
	__u32	tq;		/* Time quantum in ns. */
	__u32	bitrate_real;	/* info only */
};

/* PCANFD_XXX_INIT arg */

/* flags */
#define PCANFD_INIT_LISTEN_ONLY		0x00000001
#define PCANFD_INIT_STD_MSG_ONLY	0x00000002 /* backward compatibility */
#define PCANFD_INIT_FD			0x00000004 /* setup data bitrate too */
#define PCANFD_INIT_FD_NON_ISO		0x00000008 /* CAN-FD non ISO mode */

/* defines how raw timestamps should be processed by the driver in the messages
 * it gives to the application */
#define PCANFD_INIT_TS_DRV_REL		0x00000000 /* rel. to driver init time*/
#define PCANFD_INIT_TS_DEV_REL		0x00000010 /* rel. to device init time*/
#define PCANFD_INIT_TS_HOST_REL		0x00000020 /* rel. to host init time */
#define PCANFD_INIT_TS_FMT_MASK		0x00000030

/* (time is relative) */
#define PCANFD_INIT_TS_ABS		PCANFD_INIT_TS_HOST_REL

/* ask for being notified with PCANFD_TYPE_STATUS[PCANFD_BUS_LOAD]
 * (if the corresponding hardware is able to) */
#define PCANFD_INIT_BUS_LOAD_INFO	0x00000100

struct pcanfd_init {
	__u32 flags;
	__u32 clock_Hz;
	struct pcan_bittiming	nominal;
	struct pcan_bittiming	data;
};

/* PCANFD_GET_STATE arg */

struct pcanfd_state {
	__u16	ver_major, ver_minor, ver_subminor;

	struct timeval	tv_init;	/* time the device was initialized */

	enum pcanfd_status	bus_state;	/* CAN bus state */

	__u32	device_id;		/* device id., ffffffff is unused */

	__u32	open_counter;		/* open() counter */
	__u32	filters_counter;	/* count of message filters */

	__u16	hw_type;		/* pcan device type */
	__u16	channel_number;		/* channel number for the device */

	__u16	can_status;		/* same as wCANStatus but NOT CLEARED */
	__u16	bus_load;		/* bus load value, ffff if not given */

	__u32	tx_max_msgs;		/* Tx fifo size in count of msgs */
	__u32	tx_pending_msgs;	/* msgs waiting to be sent */
	__u32	rx_max_msgs;		/* Rx fifo size in count of msgs */
	__u32	rx_pending_msgs;	/* msgs waiting to be read */
	__u32	tx_frames_counter;	/* Tx frames written on device */
	__u32	rx_frames_counter;	/* Rx frames read on device */
	__u32	tx_error_counter;	/* CAN Tx errors counter */
	__u32	rx_error_counter;	/* CAN Rx errors counter */

	__u64	host_time_ns;		/* host time in nanoseconds as it was */
	__u64	hw_time_ns;		/* when hw_time_ns has been received */
};

/* PCANFD_xxx_FILTERS arg */

struct pcanfd_msg_filter {
	__u32	id_from;		/* msgs ID in range [id_from..id_to] */
	__u32	id_to;			/* and flags == msg_flags */
	__u32	msg_flags;		/* will be passed to applications */
};

/* filters list base type (0 item list) */
struct __array_of_struct(pcanfd_msg_filter, 0);

#define pcanfd_msg_filters		pcanfd_msg_filters_0

/* ioctls codes */
#define PCANFD_SEQ_START	0x90

enum {
	PCANFD_SEQ_SET_INIT = PCANFD_SEQ_START,
	PCANFD_SEQ_GET_INIT,
	PCANFD_SEQ_GET_STATE,
	PCANFD_SEQ_ADD_FILTERS,
	PCANFD_SEQ_GET_FILTERS,
	PCANFD_SEQ_SEND_MSG,
	PCANFD_SEQ_RECV_MSG,
	PCANFD_SEQ_SEND_MSGS,
	PCANFD_SEQ_RECV_MSGS
};

#define PCANFD_SET_INIT		_IOW(PCAN_MAGIC_NUMBER, PCANFD_SEQ_SET_INIT,\
					struct pcanfd_init)

#define PCANFD_GET_INIT		_IOR(PCAN_MAGIC_NUMBER, PCANFD_SEQ_GET_INIT,\
					struct pcanfd_init)

#define PCANFD_GET_STATE	_IOR(PCAN_MAGIC_NUMBER, PCANFD_SEQ_GET_STATE,\
					struct pcanfd_state)

#define PCANFD_ADD_FILTERS	_IOW(PCAN_MAGIC_NUMBER,			       \
				     PCANFD_SEQ_ADD_FILTERS,		       \
				     struct pcanfd_msg_filters)

#define PCANFD_GET_FILTERS	_IOWR(PCAN_MAGIC_NUMBER,		       \
				      PCANFD_SEQ_GET_FILTERS,		       \
				      struct pcanfd_msg_filters)

#define PCANFD_SEND_MSG		_IOW(PCAN_MAGIC_NUMBER, PCANFD_SEQ_SEND_MSG,\
					struct pcanfd_msg)

#define PCANFD_RECV_MSG		_IOR(PCAN_MAGIC_NUMBER, PCANFD_SEQ_RECV_MSG,\
					struct pcanfd_msg)

#define PCANFD_SEND_MSGS	_IOWR(PCAN_MAGIC_NUMBER, PCANFD_SEQ_SEND_MSGS,\
					struct pcanfd_msgs)

#define PCANFD_RECV_MSGS	_IOWR(PCAN_MAGIC_NUMBER, PCANFD_SEQ_RECV_MSGS,\
					struct pcanfd_msgs)

#endif
