//
// This file is part of the GNU ARM Eclipse distribution.
// Copyright (c) 2014 Liviu Ionescu.
//

// ----------------------------------------------------------------------------
#include <stm32f10x_conf.h>

#include <stdio.h>

#include "diag/Trace.h"

// ----------------------------------------------------------------------------
//
// Standalone STM32F1 empty sample (trace via ITM).
//
// Trace support is enabled by adding the TRACE macro definition.
// By default the trace messages are forwarded to the ITM output,
// but can be rerouted to any device or completely suppressed, by
// changing the definitions required in system/src/diag/trace_impl.c
// (currently OS_USE_TRACE_ITM, OS_USE_TRACE_SEMIHOSTING_DEBUG/_STDOUT).
//

typedef int (*recv_func)(int message_id, char data[8]);

// recv function to handle receive interrupt
static recv_func __recv;

/**
 * initialize can bus
 */
int can_init(int filter_mask, int filter_id, recv_func _recv) {
	__recv = _recv;
	// initialize can bus with 125k
    GPIO_InitTypeDef GPIO_InitStructure;
    CAN_InitTypeDef CAN_InitStructure;


	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);


	//CAN RX
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	//CAN TX
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);


	GPIO_PinRemapConfig(GPIO_Remap1_CAN1 , ENABLE);

	CAN_DeInit(CAN1);
	CAN_StructInit(&CAN_InitStructure);

	CAN_InitStructure.CAN_Prescaler = 16;
	CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
	CAN_InitStructure.CAN_BS1 = CAN_BS1_12tq;
	CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq;
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
	CAN_InitStructure.CAN_TTCM = DISABLE;
	CAN_InitStructure.CAN_ABOM = DISABLE;
	CAN_InitStructure.CAN_AWUM = DISABLE;
	CAN_InitStructure.CAN_NART = DISABLE;
	CAN_InitStructure.CAN_RFLM = DISABLE;
	CAN_InitStructure.CAN_TXFP = DISABLE;
	CAN_Init(CAN1, &CAN_InitStructure);


	CAN_FilterInitTypeDef CAN_FilterInitStructure;
	CAN_FilterInitStructure.CAN_FilterNumber = 1;
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
	CAN_FilterInitStructure.CAN_FilterIdHigh = filter_id << 5 ;
	CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = filter_mask << 5;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);

	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
	return 0;
}

/**
 * de-initialize can bus
 */
void can_uninit(void) {
	// uninit can bus.. if neccessary
	CAN_DeInit(CAN1);
}

/**
 * send data via can bus
 */
int can_send(int message_id, char data[8]) {
	// send message via can
	CanTxMsg message;
	uint8_t mailbox;
	uint8_t status;

	int i;
	message.StdId = message_id;
	message.ExtId = 0;
	message.RTR = CAN_RTR_DATA;
	message.IDE = CAN_ID_STD;
	message.DLC = 8;

	for (i = 0; i < 8; i++) {
		message.Data[i] = data[i];
	}

	// transmit and hope to get a free mailbox
	mailbox = CAN_Transmit(CAN1, &message);
	if(mailbox == CAN_NO_MB) {

		return -1;
	}

	// wait until message is sent..
	do {
		status = CAN_TransmitStatus(CAN1,mailbox);
	}while(status == 2);

	return status;
}

// call recv function on receive interrupt
void USB_LP_CAN1_RX0_IRQHandler(void) {
CanRxMsg RxMessage;
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
	__recv(RxMessage.StdId, (char*)RxMessage.Data);

}
// ----- main() ---------------------------------------------------------------

// Sample pragmas to cope with warnings. Please note the related line at
// the end of this function, used to pop the compiler diagnostics status.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wmissing-declarations"
#pragma GCC diagnostic ignored "-Wreturn-type"

int recv_candata(int message_id, char data[8]) {
	data[1] = data[0];
	can_send(message_id, data);
	return 0;
}

int
main(int argc, char* argv[])
{
  // At this stage the system clock should have already been configured
  // at high speed.
	RCC_HSEConfig(RCC_HSE_ON);
	while (!RCC_WaitForHSEStartUp())
		;

	// Message-ID 0x110-0x11f

//	motor.id = read_configswitches();
	can_init(0x00, 0x00, recv_candata);

	char data[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
  // Infinite loop
  while (1)
    {
	  can_send(0x22,data);
       // Add your code here.
    }
}

#pragma GCC diagnostic pop

// ----------------------------------------------------------------------------
