//----------------------------------------------------
/**	
	\file		ctk/hw/can_mcp2515.h
	\ingroup	can
	\ingroup	all

	\brief		Ovladac standalone CAN obvodu MCP2515 pripojeneho na SPI
				<<< ALL >>>
	
	\author		ConTeK s.r.o., Petr Cermak, Stanek Jan
	\version	01.10
	\date		12.04.2013
		
*/
//----------------------------------------------------


#ifndef CAN_MCP2515_H_
#define CAN_MCP2515_H_

#include <cancomm.h>
#include <spi.h>
#include <stmachine.h>
#include <timeticks.h>
#include <sync.h>

//----------------------------------------------------
//!	Konstanty pro rychlost CANu

typedef enum _CAN_MCP_SPD
{
	CAN_MCP_SPD_50,
	CAN_MCP_SPD_125,
	CAN_MCP_SPD_250,
	CAN_MCP_SPD_500,
	CAN_MCP_SPD_1000
} CAN_MCP_SPD;

//----------------------------------------------------
//!	Adresy registru

#define 	MCP2515_RXF0SIDH			0x00
#define 	MCP2515_RXF0SIDL			0x01
#define 	MCP2515_RXF0EID8			0x02
#define 	MCP2515_RXF0EID0			0x03
#define 	MCP2515_RXF1SIDH			0x04
#define 	MCP2515_RXF1SIDL			0x05
#define 	MCP2515_RXF1EID8			0x06
#define 	MCP2515_RXF1EID0			0x07
#define 	MCP2515_RXF2SIDH			0x08
#define 	MCP2515_RXF2SIDL			0x09
#define 	MCP2515_RXF2EID8			0x0A
#define 	MCP2515_RXF2EID0			0x0B

#define 	MCP2515_BFPCTRL				0x0C
#define 	MCP2515_TXRTSCTRL			0x0D
#define 	MCP2515_CANSTAT				0x0E
#define		MCP2515_CANCTRL				0x0F

//------------------------------------------
#define 	MCP2515_RXF3SIDH			0x10
#define 	MCP2515_RXF3SIDL			0x11
#define 	MCP2515_RXF3EID8			0x12
#define 	MCP2515_RXF3EID0			0x13
#define 	MCP2515_RXF4SIDH			0x14
#define 	MCP2515_RXF4SIDL			0x15
#define 	MCP2515_RXF4EID8			0x16
#define 	MCP2515_RXF4EID0			0x17
#define 	MCP2515_RXF5SIDH			0x18
#define 	MCP2515_RXF5SIDL			0x19
#define 	MCP2515_RXF5EID8			0x1A
#define 	MCP2515_RXF5EID0			0x1B

#define 	MCP2515_TEC					0x1C
#define 	MCP2515_REC					0x1D

//------------------------------------------
#define 	MCP2515_RXM0SIDH			0x20
#define 	MCP2515_RXM0SIDL			0x21
#define 	MCP2515_RXM0EID8			0x22
#define 	MCP2515_RXM0EID0			0x23
#define 	MCP2515_RXM1SIDH			0x24
#define 	MCP2515_RXM1SIDL			0x25
#define 	MCP2515_RXM1EID8			0x26
#define 	MCP2515_RXM1EID0			0x27
#define 	MCP2515_CNF3				0x28
#define 	MCP2515_CNF2				0x29
#define 	MCP2515_CNF1				0x2A
#define 	MCP2515_CANINTE				0x2B
#define 	MCP2515_CANINTF				0x2C
#define 	MCP2515_EFLG				0x2D

//------------------------------------------
#define 	MCP2515_TXB0CTRL			0x30
#define 	MCP2515_TXB0SIDH			0x31
#define 	MCP2515_TXB0SIDL			0x32
#define 	MCP2515_TXB0EID8			0x33
#define 	MCP2515_TXB0EID0			0x34
#define 	MCP2515_TXB0DLC				0x35
#define 	MCP2515_TXB0D0				0x36
#define 	MCP2515_TXB0D1				0x37
#define 	MCP2515_TXB0D2				0x38
#define 	MCP2515_TXB0D3				0x39
#define 	MCP2515_TXB0D4				0x3A
#define 	MCP2515_TXB0D5				0x3B
#define 	MCP2515_TXB0D6				0x3C
#define 	MCP2515_TXB0D7				0x3D

//------------------------------------------
#define 	MCP2515_TXB1CTRL			0x40
#define 	MCP2515_TXB1SIDH			0x41
#define 	MCP2515_TXB1SIDL			0x42
#define 	MCP2515_TXB1EID8			0x43
#define 	MCP2515_TXB1EID0			0x44
#define 	MCP2515_TXB1DLC				0x45
#define 	MCP2515_TXB1D0				0x46
#define 	MCP2515_TXB1D1				0x47
#define 	MCP2515_TXB1D2				0x48
#define 	MCP2515_TXB1D3				0x49
#define 	MCP2515_TXB1D4				0x4A
#define 	MCP2515_TXB1D5				0x4B
#define 	MCP2515_TXB1D6				0x4C
#define 	MCP2515_TXB1D7				0x4D

//------------------------------------------
#define 	MCP2515_TXB2CTRL			0x50
#define 	MCP2515_TXB2SIDH			0x51
#define 	MCP2515_TXB2SIDL			0x52
#define 	MCP2515_TXB2EID8			0x53
#define 	MCP2515_TXB2EID0			0x54
#define 	MCP2515_TXB2DLC				0x55
#define 	MCP2515_TXB2D0				0x56
#define 	MCP2515_TXB2D1				0x57
#define 	MCP2515_TXB2D2				0x58
#define 	MCP2515_TXB2D3				0x59
#define 	MCP2515_TXB2D4				0x5A
#define 	MCP2515_TXB2D5				0x5B
#define 	MCP2515_TXB2D6				0x5C
#define 	MCP2515_TXB2D7				0x5D

//------------------------------------------
#define 	MCP2515_RXB0CTRL			0x60
#define 	MCP2515_RXB0SIDH			0x61
#define 	MCP2515_RXB0SIDL			0x62
#define 	MCP2515_RXB0EID8			0x63
#define 	MCP2515_RXB0EID0			0x64
#define 	MCP2515_RXB0DLC				0x65
#define 	MCP2515_RXB0D0				0x66
#define 	MCP2515_RXB0D1				0x67
#define 	MCP2515_RXB0D2				0x68
#define 	MCP2515_RXB0D3				0x69
#define 	MCP2515_RXB0D4				0x6A
#define 	MCP2515_RXB0D5				0x6B
#define 	MCP2515_RXB0D6				0x6C
#define 	MCP2515_RXB0D7				0x6D

//------------------------------------------
#define 	MCP2515_RXB1CTRL			0x70
#define 	MCP2515_RXB1SIDH			0x71
#define 	MCP2515_RXB1SIDL			0x72
#define 	MCP2515_RXB1EID8			0x73
#define 	MCP2515_RXB1EID0			0x74
#define 	MCP2515_RXB1DLC				0x75
#define 	MCP2515_RXB1D0				0x76
#define 	MCP2515_RXB1D1				0x77
#define 	MCP2515_RXB1D2				0x78
#define 	MCP2515_RXB1D3				0x79
#define 	MCP2515_RXB1D4				0x7A
#define 	MCP2515_RXB1D5				0x7B
#define 	MCP2515_RXB1D6				0x7C
#define 	MCP2515_RXB1D7				0x7D

//MCP2515 Command Bytes
#define   MCP2515_CMD_RESET           0xC0
#define   MCP2515_CMD_READ            0x03
#define   MCP2515_CMD_READ_RX_BUFFER  0x90
#define   MCP2515_CMD_WRITE           0x02
#define   MCP2515_CMD_LOAD_TX_BUFFER  0x40
#define   MCP2515_CMD_RTS             0x80
#define   MCP2515_CMD_READ_STATUS     0xA0
#define   MCP2515_CMD_RX_STATUS       0xB0
#define   MCP2515_CMD_BIT_MODIFY      0x05

//MCP2515 Status Mask
#define   MCP2515_STATUS_RX0IF		0x01
#define   MCP2515_STATUS_RX1IF		0x02
#define   MCP2515_STATUS_TX0REQ		0x04
#define   MCP2515_STATUS_TX0IF		0x08
#define   MCP2515_STATUS_TX1REQ		0x10
#define   MCP2515_STATUS_TX1IF		0x20
#define   MCP2515_STATUS_TX2REQ		0x40
#define   MCP2515_STATUS_TX2IF		0x80

//MCP2515 RX Status Mask
#define   MCP2515_RX_STATUS_MESSAGE		0xC0
#define   MCP2515_RX_STATUS_TYPE		0x18
#define   MCP2515_RX_STATUS_FILTER		0x07

//MCP2515 Interrupt Config
#define	  MCP2515_INTE_MERRE			0x80	//!< Message Error Interrupt Enable bit
#define   MCP2515_INTE_WAKIE			0x40	//!< Wakeup Interrupt Enable bit
#define   MCP2515_INTE_ERRIE			0x20	//!< Error Interrupt Enable bit (multiple sources in EFLG register)
#define   MCP2515_INTE_TX2IE			0x10	//!< Transmit Buffer 2 Empty Interrupt Enable bit
#define   MCP2515_INTE_TX1IE			0x08	//!< Transmit Buffer 1 Empty Interrupt Enable bit
#define   MCP2515_INTE_TX0IE			0x04	//!< Transmit Buffer 0 Empty Interrupt Enable bit
#define   MCP2515_INTE_RX1IE			0x02	//!< Receive Buffer 1 Full Interrupt Enable bit
#define   MCP2515_INTE_RX0IE			0x01	//!< Receive Buffer 0 Full Interrupt Enable bit
#define   MCP2515_INTE_ALL_TX			MCP2515_INTE_TX2IE | MCP2515_INTE_TX1IE | MCP2515_INTE_TX0IE
#define   MCP2515_INTE_ALL_RX			MCP2515_INTE_RX1IE | MCP2515_INTE_RX0IE
#define   MCP2515_INTE_ALL				MCP2515_INTE_ALL_TX | MCP2515_INTE_ALL_RX | MCP2515_INTE_MERRE | MCP2515_INTE_WAKIE | MCP2515_INTE_ERRIE

#ifdef MSVC
	#pragma pack(push,1)
#endif // MSVC

//----------------------------------------------------
//!	Konstanty pro pocet odesilacich a vysilacich slotu
#define  MCP2515_TX_COUNT		3
#define  MCP2515_RX_COUNT		2

//----------------------------------------------------
//!	Konstanta pro periodu vycitani status registru
#define MCP2515_PERIOD_STATUS	1

//----------------------------------------------------
//!	Datove struktury pro komunikaci s radicem

typedef struct _CAN_MCP2515_SPI_DESC_CTX
{
	uint8_t					operation;
	uint8_t					address;
	uint8_t					registerData[2];
}__attribute__((packed))CAN_MCP2515_SPI_DESC_CTX;

typedef struct _CAN_MCP2515_STATUS_CTX
{
	uint8_t		Rx0IF	:1;
	uint8_t		Rx1IF	:1;
	uint8_t		Tx0Req	:1;
	uint8_t		Tx0IF	:1;
	uint8_t		Tx1Req	:1;
	uint8_t		Tx1IF	:1;
	uint8_t		Tx2Req	:1;
	uint8_t		Tx2IF	:1;
} __attribute__((packed)) CAN_MCP2515_STATUS_CTX;

typedef struct _CAN_MCP2515_TXCTRL_CTX
{
	uint8_t		TXP		:2;				//!< 	Transmit Buffer Priority
	uint8_t				:1;				//!<	Unimplemented
	uint8_t		TxReq	:1;				//!<	Message Transmit Request bit
	uint8_t		TxErr	:1;				//!<	Transmission Error Detected bit
	uint8_t		MLOA	:1;				//!<	Message Lost Arbitration bit
	uint8_t		ABTF	:1;				//!< 	Message Aborted Flag bit
	uint8_t 			:1;				//!<	Unimplemented
} __attribute__((packed)) CAN_MCP2515_TXCTRL_CTX;


typedef struct _CAN_MCP2515_RXCTRL_CTX
{
	uint8_t				:1;				//!<	Unimplemented
	uint8_t		RXM		:2;				//!<	Receive Buffer Operating Mode bits
	uint8_t				:1;				//!<	Unimplemented
	uint8_t		RxRTR	:1;				//!<	Received Remote Transfer Request bit
	uint8_t		BUKT	:1;				//!<	Rollover Enable bit
	uint8_t		BUKT1	:1;				//!<	Read-only Copy of BUKT bit (used internally by the MCP2515)
	uint8_t		FILHIT	:1;				//!<	Filter Hit bit - indicates which acceptance filter enabled reception of message
} __attribute__((packed)) CAN_MCP2515_RXCTRL_CTX;



typedef struct _CAN_MCP2515_SIDH_CTX
{
	uint8_t		SID;					//!<	Standard Identifier bits <10:3>
} __attribute__((packed)) CAN_MCP2515_SIDH_CTX;

typedef struct _CAN_MCP2515_SIDL_CTX
{
	uint8_t		EID		:2;				//!<	Extended Identifier bits <17:16>
	uint8_t				:1;				//!<	Unimplemented
	uint8_t		EXIDE	:1;				//!<	Extended Identifier Enable bit
	uint8_t				:1;				//!<	Unimplemented
	uint8_t		SID		:3;				//!<	Standard Identifier bits <2:0>
} __attribute__((packed)) CAN_MCP2515_SIDL_CTX;

typedef uint8_t CAN_MCP2515_EID_CTX;	//!<	Extended Identifier bits

typedef struct _CAN_MCP2515_DLC_CTX
{
	uint8_t		DLC		:4;				//!<	Data Length Code
	uint8_t				:2;				//!<	Unimplemented
	uint8_t		RTR		:1;				//!<	Remote Transmission Request bit
	uint8_t 			:1;				//!<	Unimplemented
} __attribute__((packed)) CAN_MCP2515_DLC_CTX;

typedef uint8_t CAN_MCP2515_DATA_CTX;	//!<	Buffer Data Field Byte

typedef struct _CAN_MCP2515_TXMSG_CTX
{
	CAN_MCP2515_TXCTRL_CTX	ctrl;
	CAN_MCP2515_SIDH_CTX	sidh;
	CAN_MCP2515_SIDL_CTX	sidl;
	CAN_MCP2515_EID_CTX		eid[2];
	CAN_MCP2515_DLC_CTX		dlc;
	CAN_MCP2515_DATA_CTX	data[8];
} __attribute__((packed)) CAN_MCP2515_TXMSG_CTX;

typedef enum _CAN_MCP2515_TXMSG_STATUS
{
	MCP2515_TXMSG_STATUS_READY,
	MCP2515_TXMSG_STATUS_START_SENDING,
	MCP2515_TXMSG_STATUS_PENDING,
	MCP2515_TXMSG_STATUS_ERROR
}CAN_MCP2515_TXMSG_STATUS;

typedef struct _CAN_MCP2515_TXMSG_DESC_CTX
{
	CAN_MCP2515_TXMSG_STATUS		status;
	CAN_MCP2515_TXMSG_CTX			data;
}__attribute__((packed)) CAN_MCP2515_TXMSG_DESC_CTX;

typedef struct _CAN_MCP2515_RXMSG_CTX
{
	CAN_MCP2515_RXCTRL_CTX	ctrl;
	CAN_MCP2515_SIDH_CTX	sidh;
	CAN_MCP2515_SIDL_CTX	sidl;
	CAN_MCP2515_EID_CTX		eid[2];
	CAN_MCP2515_DLC_CTX		dlc;
	CAN_MCP2515_DATA_CTX	data[8];
} __attribute__((packed)) CAN_MCP2515_RXMSG_CTX;

typedef struct _CAN_MCP2515_RXMSG_BUFFER_CTX
{
	CAN_MCP2515_SPI_DESC_CTX	desc;
	CAN_MCP2515_RXMSG_CTX		data;
}__attribute__((packed)) CAN_MCP2515_RXMSG_BUFFER_CTX;


typedef struct _CAN_MCP2515_CANCTRL_CTX
{
	uint8_t		CLKPRE	:1;		//!< CLKOUT Pin Prescaler bits <1:0>
	uint8_t		CLKEN	:1;		//!< CLKOUT Pin Enable bit
	uint8_t		OSM		:1;		//!< One Shot Mode bit
	uint8_t		ABAT	:1;		//!< Abort All Pending Transmissions bit
	uint8_t		REQOP	:2;		//!< Request Operation Mode bits <2:0>
}__attribute__((packed))CAN_MCP2515_CANCTRL_CTX;;

typedef struct _CAN_MCP2515_CONFIG_CTX
{
	uint8_t		cnf3;			//!< CONFIGURATION 3
	uint8_t		cnf2;			//!< CONFIGURATION 2
	uint8_t		cnf1;			//!< CONFIGURATION 1
	uint8_t		caninte;		//!< INTERRUPT ENABLE
}__attribute__((packed))CAN_MCP2515_CONFIG_CTX;

typedef struct _CAN_MCP2515_INTERRUPT_FLAG
{
	uint8_t		Rx0IF	:1;		//!< Receive Buffer 0 Full Interrupt Flag bit
	uint8_t		Rx1IF	:1;		//!< Receive Buffer 1 Full Interrupt Flag bit
	uint8_t		Tx0IF	:1;		//!< Transmit Buffer 0 Empty Interrupt Flag bit
	uint8_t		Tx1IF	:1;		//!< Transmit Buffer 1 Empty Interrupt Flag bit
	uint8_t		Tx2IF	:1;		//!< Transmit Buffer 2 Empty Interrupt Flag bit
	uint8_t		ERRIF	:1;		//!< Error Interrupt Flag bit (multiple sources in EFLG register)
	uint8_t		WAKIF	:1;		//!< Wakeup Interrupt Flag bit
	uint8_t		MERRF	:1;		//!< Message Error Interrupt Flag bit
}__attribute__((packed))CAN_MCP2515_INTERRUPT_FLAG;;


typedef struct _CAN_MCP2515_EFLG
{
	uint8_t		EWARN	:1;		//!< Error Warning Flag bit
	uint8_t		RXWAR	:1;		//!< Receive Error Warning Flag bit
	uint8_t		TXWAR	:1;		//!< Transmit Error Warning Flag bit
	uint8_t		RXEP	:1;		//!< Receive Error-Passive Flag bit
	uint8_t		TXEP	:1;		//!< Transmit Error-Passive Flag bit
	uint8_t		TXBO	:1;		//!< Bus-Off Error Flag bit
	uint8_t		RX0OVR	:1;		//!< Receive Buffer 0 Overflow Flag bit
	uint8_t		RX1OVR	:1;		//!< Receive Buffer 1 Overflow Flag bit
}__attribute__((packed))CAN_MCP2515_EFLG;;


//----------------------------------------------------
//!	Kontext ovladace CAN

typedef struct _CAN_MCP2515_CTX {
	CANCOMMDESC Parent;			//!< Rodic

	CANMODE 	Mode;			//!< Rezim ID
	CAN_MCP_SPD	Speed;			//!< Baudrate
	
	ccmCANTick	Tick;			//!< Rodicovsky tick

	SPIDESC	*   Spi;			//!< Kontext pouzivaneho spi
	uint8_t		SpiChannel;		//!< Kanal pouzivaneho SPI
	volatile bool_t		SpiReady;		//!< Status pouzivaneho SPI (TRUE = muze se vysilat)

	STMACHINE	StmTick;		//!< Tick hlavniho automatu

	bool_t		flRunning;
	bool_t		flTickExec;

	CAN_MCP2515_CONFIG_CTX			config;			//!< Konfiguracni promene CAN controleru

	CAN_MCP2515_STATUS_CTX			status;						//!< Status CAN controleru
	CAN_MCP2515_TXMSG_DESC_CTX		txMsg[MCP2515_TX_COUNT];	//!< Odesilaci schranky
	CAN_MCP2515_RXMSG_CTX			rxMsg[MCP2515_RX_COUNT];	//!< Prijimaci schranky

	CAN_MCP2515_SPI_DESC_CTX		cmdSpi;					//!< Prikaz pro praci s CAN controlerem

} CAN_MCP2515_CTX;




//----------------------------------------------------
/**
	\brief	Inicializace CAN

	\param	ctx				Kontext CAN, ktery bude prirazen teto instanci
	\param	Mode			Rezim ID
	\param	Baudrate		Rychlost prenocu na CAN
	\param  spi				Kontex SPI
	\param  spiChanel		Index SPI kanalu
	
	\return	TRUE			pokud inicializace probehla v poradku
*/
//---------------------------------------------------
bool_t CanMcp2515Initialize(CAN_MCP2515_CTX *ctx, CANMODE Mode, CAN_MCP_SPD baudRate, const ticks_t Timeout, SPIDESC * const spi, const uint8_t spiChannel);

//----------------------------------------------------
/**
	\brief	Tick fyzicke vrstvy CAN komunikace 2515

	\param	cmm		Kontext nadrazene komunikace

*/
//---------------------------------------------------
void ccmiHW_CANTick( struct _CANCOMMDESC * const cmm );

//----------------------------------------------------
/**
	\brief	Finalizace CAN

	\param	ctx		Kontext CAN
*/
//----------------------------------------------------
void CanMcp2515Finalize(CAN_MCP2515_CTX * ctx);


#endif
