/*
 * CAN.c

 *
 *  Created on: Dec 04, 2018
 *      Author: v0stap
 */

#include "main.h"
#include "CAN.h"

can_msg_typedef CAN_TX_Msg;					// CAN message for transmit
can_msg_typedef CAN_RX_Msg;					// CAN received message
uint8_t CAN_TX_Rdy = 0;				// CAN hardware ready to transmit a message
uint8_t CAN_RX_Rdy = 0;				// CAN hardware message received
uint32_t CAN_Speed = CAN_500KBS;		// CAN Speed / CAN BTR register
can_buffer_typedef CAN_TX_Buffer, CAN_RX_Buffer;
uint8_t CAN_Filter_Idx = 0;			// CAN filter index

void CAN_Init(void) {
	CAN_TX_Buffer.todo = 0;
	CAN_TX_Buffer.corent = 0;
	CAN_TX_Buffer.done = 0;
	CAN_RX_Buffer.todo = 0;
	CAN_RX_Buffer.corent = 0;
	CAN_RX_Buffer.done = 0;
	CAN_Setup(CAN_500KBS);
	CAN_Write_Filter(0x212, STD_FORMAT);
	CAN_Write_Filter(0x643, STD_FORMAT);
	//CAN_Write_Filter(0x620, STD_FORMAT);
	//CAN_Write_Filter(0x630, STD_FORMAT);
	//CAN_Write_Filter(0x240, STD_FORMAT);
	CAN_Start();
	CAN_Wait_Ready();
}
/*----------------------------------------------------------------------------
 setup CAN interface
 *----------------------------------------------------------------------------*/
void CAN_Setup(uint32_t speed) {

	RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
	RCC->APB1ENR |= RCC_APB1ENR_CANEN;
	GPIOB->MODER &= ~((3 << (8 * 2)) | (3 << (9 * 2)));
	GPIOB->MODER |= ((2 << (8 * 2)) | (2 << (9 * 2)));
	GPIOB->OTYPER &= ~((1 << 8) | (1 << 9));
	GPIOB->OSPEEDR &= ~((3 << (8 * 2)) | (3 << (9 * 2)));
	GPIOB->PUPDR &= ~((3 << (8 * 2)) | (3 << (9 * 2)));
	GPIOB->AFR[1] &= ~((15 << (0 * 4)) | (15 << (1 * 4)));
	GPIOB->AFR[1] |= ((4 << 0) | (4 << (1 * 4)));
	CAN->MCR |= CAN_MCR_INRQ;
	while ((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) {
		//some code
	}
	CAN->MCR &= ~ CAN_MCR_SLEEP;
	CAN->BTR &= ~(((0x03) << 24) | ((0x07) << 20) | ((0x0F) << 16) | (0x1FF));
	CAN->BTR |= speed;
	NVIC_EnableIRQ(CEC_CAN_IRQn);
	CAN->IER |= CAN_IER_FMPIE0;
}

/*----------------------------------------------------------------------------
 leave initialisation mode
 *----------------------------------------------------------------------------*/
void CAN_Start(void) {
	CAN->MCR &= ~CAN_MCR_INRQ;
	while ((CAN->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) {

	}

}

/*----------------------------------------------------------------------------
 check if transmit mailbox is empty
 *----------------------------------------------------------------------------*/
void CAN_Wait_Ready(void) {
	while ((CAN->TSR & CAN_TSR_TME0) == 0) {      // Transmit mailbox 0 is empty

	}
	CAN_TX_Rdy = 1;
}

// CAN send data
void CAN_Send_Msg(can_msg_typedef *msg) {
	CAN_TX_Rdy = 0;
	CAN->sTxMailBox[0].TIR = (uint32_t) 0;
	if (msg->format == STD_FORMAT) {
		CAN->sTxMailBox[0].TIR |= (uint32_t) (msg->id << 21) | CAN_ID_STD;
	} else {
		CAN->sTxMailBox[0].TIR |= (uint32_t) (msg->id << 3) | CAN_ID_EXT;
	}
	if (msg->frame == DATA_FRAME) {
		CAN->sTxMailBox[0].TIR |= CAN_RTR_DATA;
	} else {
		CAN->sTxMailBox[0].TIR |= CAN_RTR_REMOTE;
	}
	CAN->sTxMailBox[0].TDLR = (((uint32_t) msg->data[3] << 24)
			| ((uint32_t) msg->data[2] << 16) | ((uint32_t) msg->data[1] << 8)
			| ((uint32_t) msg->data[0]));
	CAN->sTxMailBox[0].TDHR = (((uint32_t) msg->data[7] << 24)
			| ((uint32_t) msg->data[6] << 16) | ((uint32_t) msg->data[5] << 8)
			| ((uint32_t) msg->data[4]));
	CAN->sTxMailBox[0].TDTR &= ~CAN_TDT0R_DLC;
	CAN->sTxMailBox[0].TDTR |= (msg->lenght & CAN_TDT0R_DLC);
	CAN->IER |= CAN_IER_TMEIE;
	CAN->sTxMailBox[0].TIR |= CAN_TI0R_TXRQ;
}
// Read CAN message
void CAN_Recive_Msg(can_msg_typedef *msg) {
	if ((CAN->sFIFOMailBox[0].RIR & CAN_ID_EXT) == 0) {
		msg->format = STD_FORMAT;
		msg->id = (uint32_t) 0x000007FF & (CAN->sFIFOMailBox[0].RIR >> 21);
	} else {
		msg->format = EXTD_FORMAT;
		msg->id = (uint32_t) 0x0003FFFF & (CAN->sFIFOMailBox[0].RIR >> 3);
	}
	if ((CAN->sFIFOMailBox[0].RIR & CAN_RTR_REMOTE) == 0) {
		msg->frame = DATA_FRAME;
	} else {
		msg->frame = REMOTE_FRAME;
	}
	msg->lenght = (uint8_t) 0x0000000F & CAN->sFIFOMailBox[0].RDTR;
	msg->data[0] = (uint32_t) 0x000000FF & (CAN->sFIFOMailBox[0].RDLR);
	msg->data[1] = (uint32_t) 0x000000FF & (CAN->sFIFOMailBox[0].RDLR >> 8);
	msg->data[2] = (uint32_t) 0x000000FF & (CAN->sFIFOMailBox[0].RDLR >> 16);
	msg->data[3] = (uint32_t) 0x000000FF & (CAN->sFIFOMailBox[0].RDLR >> 24);
	msg->data[4] = (uint32_t) 0x000000FF & (CAN->sFIFOMailBox[0].RDHR);
	msg->data[5] = (uint32_t) 0x000000FF & (CAN->sFIFOMailBox[0].RDHR >> 8);
	msg->data[6] = (uint32_t) 0x000000FF & (CAN->sFIFOMailBox[0].RDHR >> 16);
	msg->data[7] = (uint32_t) 0x000000FF & (CAN->sFIFOMailBox[0].RDHR >> 24);
	CAN->RF0R |= CAN_RF0R_RFOM0;

	CAN_RX_Rdy = 0;
//	if (msg->id == 0x643)
//		printf(
//				"CAN ID: 0x%X%X Data: 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X \n",
//				(uint16_t) (msg->id >> 16), (uint16_t) msg->id, msg->data[0],
//				msg->data[1], msg->data[2], msg->data[3], msg->data[4],
//				msg->data[5], msg->data[6], msg->data[7]);
//	//(&canRxMsg); //TO DO not realy working
}
//Write CAN Filter
void CAN_Write_Filter(uint32_t id, uint8_t format) {
	uint32_t CAN_msg_typedefId = 0;
	if (CAN_Filter_Idx > 13) {
		return;
	}
	if (format == STD_FORMAT) {
		CAN_msg_typedefId |= (uint32_t) (id << 21) | CAN_ID_STD;
	} else {
		CAN_msg_typedefId |= (uint32_t) (id << 3) | CAN_ID_EXT;
	}
	CAN->FMR |= CAN_FMR_FINIT;
	CAN->FA1R &= ~(uint32_t) (1 << CAN_Filter_Idx);
	CAN->FS1R |= (uint32_t) (1 << CAN_Filter_Idx);
	CAN->FM1R |= (uint32_t) (1 << CAN_Filter_Idx);
	//Comment next to lines for no filter
	if (id != 0) {
		CAN->sFilterRegister[CAN_Filter_Idx].FR1 = CAN_msg_typedefId;
		CAN->sFilterRegister[CAN_Filter_Idx].FR2 = CAN_msg_typedefId;
		//Uncomment next to line for no filter
	} else {
		CAN->sFilterRegister[CAN_Filter_Idx].FR1 = 0; //  32-bit identifier
		CAN->sFilterRegister[CAN_Filter_Idx].FR2 = 0; //  32-bit identifier
	}
	CAN->FFA1R &= ~(uint32_t) (1 << CAN_Filter_Idx);
	CAN->FA1R |= (uint32_t) (1 << CAN_Filter_Idx);
	CAN->FMR &= ~CAN_FMR_FINIT;
	CAN_Filter_Idx++;
}
//CAN recive/transmit irq handler
void CEC_CAN_IRQHandler(void) {
	if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) {
		CAN->TSR |= CAN_TSR_RQCP0;
		CAN->IER &= ~CAN_IER_TMEIE;
		CAN_TX_Rdy = 1;
	}
	if ((CAN->RF0R & CAN_RF0R_FMP0) != 0) {
		CAN_Add_RX_Buffer();
		// TO DO
		CAN->RF0R |= CAN_RF0R_RFOM0;
		CAN_RX_Rdy = 1;
	}
}
void CAN_Send_TX_Buffer(void) {

	if (CAN_TX_Rdy) {
		//HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
		if (CAN_TX_Buffer.todo > 0) {
			CAN_TX_Buffer.todo--;
			//HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
			CAN_Send_Msg(&CAN_TX_Buffer.data[CAN_TX_Buffer.done]);
			if ((CAN_TX_Buffer.done++) > 14) {
				CAN_TX_Buffer.done = 0;
			}
		}
	}
}
void CAN_Add_TX_Buffer(can_msg_typedef *data) {
	if ((CAN_TX_Buffer.todo++) < 15) {
		if ((CAN_TX_Buffer.corent++) > 14) {
			CAN_TX_Buffer.corent = 0;
		}
		//memcpy((void*) &canTX_buffer.data[canTX_buffer.corent], (void*) &data, sizeof(CAN_msg_typedef));
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].id = data->id;
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].format = data->format;
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].frame = data->frame;
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].lenght = data->lenght;
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].data[0] = data->data[0];
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].data[1] = data->data[1];
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].data[2] = data->data[2];
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].data[3] = data->data[3];
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].data[4] = data->data[4];
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].data[5] = data->data[5];
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].data[6] = data->data[6];
		CAN_TX_Buffer.data[CAN_TX_Buffer.corent].data[7] = data->data[7];
	}
}
void CAN_Add_RX_Buffer(void) {
	if ((CAN_RX_Buffer.todo) < 16) {
		CAN_RX_Buffer.todo++;
		if ((CAN->sFIFOMailBox[0].RIR & CAN_ID_EXT) == 0) {
			CAN_RX_Buffer.data[CAN_RX_Buffer.corent].format = STD_FORMAT;
			CAN_RX_Buffer.data[CAN_RX_Buffer.corent].id = (uint32_t) 0x000007FF
					& (CAN->sFIFOMailBox[0].RIR >> 21);
		} else {
			CAN_RX_Buffer.data[CAN_RX_Buffer.corent].format = EXTD_FORMAT;
			CAN_RX_Buffer.data[CAN_RX_Buffer.corent].id = (uint32_t) 0x0003FFFF
					& (CAN->sFIFOMailBox[0].RIR >> 3);
		}
		if ((CAN->sFIFOMailBox[0].RIR & CAN_RTR_REMOTE) == 0) {
			CAN_RX_Buffer.data[CAN_RX_Buffer.corent].frame = DATA_FRAME;
		} else {
			CAN_RX_Buffer.data[CAN_RX_Buffer.corent].frame = REMOTE_FRAME;
		}
		CAN_RX_Buffer.data[CAN_RX_Buffer.corent].lenght = (uint8_t) 0x0000000F
				& CAN->sFIFOMailBox[0].RDTR;
		CAN_RX_Buffer.data[CAN_RX_Buffer.corent].data[0] = (uint32_t) 0x000000FF
				& (CAN->sFIFOMailBox[0].RDLR);
		CAN_RX_Buffer.data[CAN_RX_Buffer.corent].data[1] = (uint32_t) 0x000000FF
				& (CAN->sFIFOMailBox[0].RDLR >> 8);
		CAN_RX_Buffer.data[CAN_RX_Buffer.corent].data[2] = (uint32_t) 0x000000FF
				& (CAN->sFIFOMailBox[0].RDLR >> 16);
		CAN_RX_Buffer.data[CAN_RX_Buffer.corent].data[3] = (uint32_t) 0x000000FF
				& (CAN->sFIFOMailBox[0].RDLR >> 24);
		CAN_RX_Buffer.data[CAN_RX_Buffer.corent].data[4] = (uint32_t) 0x000000FF
				& (CAN->sFIFOMailBox[0].RDHR);
		CAN_RX_Buffer.data[CAN_RX_Buffer.corent].data[5] = (uint32_t) 0x000000FF
				& (CAN->sFIFOMailBox[0].RDHR >> 8);
		CAN_RX_Buffer.data[CAN_RX_Buffer.corent].data[6] = (uint32_t) 0x000000FF
				& (CAN->sFIFOMailBox[0].RDHR >> 16);
		CAN_RX_Buffer.data[CAN_RX_Buffer.corent].data[7] = (uint32_t) 0x000000FF
				& (CAN->sFIFOMailBox[0].RDHR >> 24);
		if ((CAN_RX_Buffer.corent++) > 15) {
			CAN_RX_Buffer.corent = 0;
		}

		//canAddRXBuffer(&canRxMsg); //TO DO not realy working
	}
	CAN->RF0R |= CAN_RF0R_RFOM0;
}
void CAN_Read_RX_Buffer(can_msg_typedef *data) {
	if (CAN_RX_Buffer.todo > 0) {
		//memcpy((void*) &data, (void*) &canRX_buffer.data[canRX_buffer.done], sizeof(CAN_msg_typedef));
		data->id = CAN_RX_Buffer.data[CAN_RX_Buffer.done].id;
		data->format = CAN_RX_Buffer.data[CAN_RX_Buffer.done].format;
		data->frame = CAN_RX_Buffer.data[CAN_RX_Buffer.done].frame;
		data->lenght = CAN_RX_Buffer.data[CAN_RX_Buffer.done].lenght;
		data->data[0] = CAN_RX_Buffer.data[CAN_RX_Buffer.done].data[0];
		data->data[1] = CAN_RX_Buffer.data[CAN_RX_Buffer.done].data[1];
		data->data[2] = CAN_RX_Buffer.data[CAN_RX_Buffer.done].data[2];
		data->data[3] = CAN_RX_Buffer.data[CAN_RX_Buffer.done].data[3];
		data->data[4] = CAN_RX_Buffer.data[CAN_RX_Buffer.done].data[4];
		data->data[5] = CAN_RX_Buffer.data[CAN_RX_Buffer.done].data[5];
		data->data[6] = CAN_RX_Buffer.data[CAN_RX_Buffer.done].data[6];
		data->data[7] = CAN_RX_Buffer.data[CAN_RX_Buffer.done].data[7];
		if ((CAN_RX_Buffer.done++) > 15) {
			CAN_RX_Buffer.done = 0;
		}
		CAN_RX_Buffer.todo--;
	}
}
