/*
 * radio.c
 *
 *  Created on: 3 Jul 2018
 *      Author: nats
 */

#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "periph.h"
#include "datafifo.h"
#include "radio.h"

uint8_t beaconbuffer[48] = { 	0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xDC, 0x0F, 0xFE, 0xBA, 0xDF, 0x00, 0xD0,
								0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xDC, 0x0F, 0xFE, 0xBA, 0xDF, 0x00, 0xD0,
								0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xDC, 0x0F, 0xFE, 0xBA, 0xDF, 0x00, 0xD0,
								0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xDC, 0x0F, 0xFE, 0xBA, 0xDF, 0x00, 0xD0 };

TIM_TimeBaseInitTypeDef radTimConf;

void send_packet() {
	uint8_t * p = 0;
	//if(read_packet(&p) == FIFOERROR) {
		// Nothing to send in the FIFO
		// We send the Toxic beacon
		dmaSPISend(beaconbuffer);
	//} else {
		//dmaSPISend(p);
	//}
}

uint8_t si44_getcts() {
	while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
	SPI_I2S_SendData(SPI1, READ_CMD_BUFF);
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
	SPI_I2S_ReceiveData(SPI1);
	while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
	SPI_I2S_SendData(SPI1, 0);
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));
	return SPI_I2S_ReceiveData(SPI1);
}

void si44_spisend(uint8_t data) {
	while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
	SPI_I2S_SendData(SPI1, data);
	while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));
	SPI_I2S_ReceiveData(SPI1);
}

void si44_spiread(uint8_t *data, uint8_t size) {
	while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
	SPI_I2S_SendData(SPI1, READ_CMD_BUFF);
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
	SPI_I2S_ReceiveData(SPI1);
	for(uint8_t i = 0; i<size;i++) {
		while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
		SPI_I2S_SendData(SPI1, 0);
		while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
		while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));
		data[i] = SPI_I2S_ReceiveData(SPI1);
	}
}

void set_property(unsigned short property, unsigned char length) {
    si44_spisend(SET_PROPERTY);
    si44_spisend(property >> 8);
    si44_spisend(length);
    si44_spisend(property & 0xFF);
}

void initSiTimer() {
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	TIM_Cmd(TIM1, ENABLE);

	TIM_TimeBaseInitTypeDef radTimConf;
	TIM_TimeBaseStructInit(&radTimConf);

	radTimConf.TIM_ClockDivision = TIM_CKD_DIV1;
	radTimConf.TIM_Prescaler = 64;
	radTimConf.TIM_CounterMode = TIM_CounterMode_Up;
	radTimConf.TIM_Period = 0xFFFF;
	radTimConf.TIM_RepetitionCounter = 0;

	TIM_TimeBaseInit(TIM1, &radTimConf);
}

void tim1Wait(uint16_t us) {
	TIM1->SR = 0; // Clear All Flag !
	TIM1->CNT = 0;
	while(1) {
		uint16_t read_val = TIM1->CNT;
		if(read_val >= us) break;
	}
}

void spi_CS(uint8_t enable) {
	if(enable)
		GPIO_ResetBits(GPIOA, SI_CS);
	else {
		GPIO_SetBits(GPIOA, SI_CS);
		tim1Wait(10);
	}
}

void initSi446x() {
	initSiTimer();

	GPIO_ResetBits(GPIOB, SI_SHDN);
	tim1Wait(60000);
	GPIO_SetBits(GPIOB, SI_SHDN);
	tim1Wait(60000);
	GPIO_ResetBits(GPIOB, SI_SHDN);
	tim1Wait(60000);

	check_part_info();
	
	spi_CS(1);
	si44_spisend(POWER_UP);
	si44_spisend(1);
	si44_spisend(1);
	si44_spisend(0x01);
	si44_spisend(0x8C);
	si44_spisend(0xBA);
	si44_spisend(0x80);
	spi_CS(0);
	tim1Wait(60000);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
	set_property(GLOBAL_XO_TUNE, 1);
    si44_spisend(0);
	spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
	set_property(GLOBAL_CONFIG, 1);
    si44_spisend(0xC0);
	spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
	set_property(MODEM_MOD_TYPE,3);
    si44_spisend(1<<7);
    si44_spisend(0<<7);
    si44_spisend(0x03);
	spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
	set_property(MODEM_CLKGEN_BAND,1);
    si44_spisend(1<<3 | BAND << 0);
	spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
	set_property(0x4000, 8);
    si44_spisend(0x41);
    si44_spisend(0x0C);
    si44_spisend(0xEC);
    si44_spisend(0x4E);
    si44_spisend(0x4E);
    si44_spisend(0xC5);
    si44_spisend(0x20);
    si44_spisend(0xFE);
	spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
    set_property(PREAMBLE_TX_LENGTH, 1);
    si44_spisend(0);
    spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
    set_property(PREAMBLE_CONFIG, 1);
    si44_spisend(0);
    spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
    set_property(0x1005, 4);
    si44_spisend(0);
    si44_spisend(0);
    si44_spisend(0);
    si44_spisend(0);
    spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
    set_property(SYNC_CONFIG, 1);
    si44_spisend(1<<7);
    spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
    set_property(PA_MODE, 4);
    si44_spisend(7<<2);
    si44_spisend(POWER_LEVEL);
    si44_spisend(CLK_DUTY_LOW);
    si44_spisend(31);
    si44_spisend(0);
    si44_spisend(40);
    spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	spi_CS(1);
    set_property(0x2003, 10);
    si44_spisend(((1000000)>> 16) & 0xFF);
    si44_spisend(((1000000)>>  8) & 0xFF);
    si44_spisend(((1000000)     ) & 0xFF);
    si44_spisend(0<<2| ((Fxtal >>  24) & 0xFF));
    si44_spisend((Fxtal >>  16) & 0xFF);
    si44_spisend((Fxtal >>   8) & 0xFF);
    si44_spisend((Fxtal       ) & 0xFF);
    si44_spisend(0x00);
    spi_CS(0);
	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	
}

void check_part_info() {
	spi_CS(1);
	si44_spisend(PART_INFO);
	spi_CS(0);

	while(!GPIO_ReadInputDataBit(GPIOA, SI_CTS));
	
	uint8_t part_info[9];
	spi_CS(1);
	si44_spiread(part_info, 9);
	spi_CS(0);

	// To be changed for SI4463
	if(part_info[2] != 0x44 || part_info[3] != 0x61) {
		while(1) {
			GPIO_SetBits(GPIOA, LED);
			tim1Wait(60000);
			tim1Wait(60000);
			tim1Wait(60000);
			GPIO_ResetBits(GPIOA, LED);
			tim1Wait(60000);
			tim1Wait(60000);
			tim1Wait(60000);
		}
	}
}
