#include "a5130.h"
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

#define SPI_CS SPI_CS_Pin
#define SPI_CS_PORT SPI_CS_GPIO_Port
extern SPI_HandleTypeDef hspi1;

volatile HAL_LockTypeDef txLock;
volatile HAL_LockTypeDef rxLock;

extern volatile HAL_LockTypeDef spiLock;
extern osSemaphoreId rxSemHandle;

uint8_t	trimCBG, trimCTR, trimBDC, trimSTM;

static const uint8_t PageTab[8]={0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70};

static uint8_t ID_Tab[8]={0x34,0x75,0xC5,0x2A,0xC7,0x33,0x45,0xEA};

static uint8_t PN9_Tab[]=
{   0xFF,0x83,0xDF,0x17,0x32,0x09,0x4E,0xD1,
    0xE7,0xCD,0x8A,0x91,0xC6,0xD5,0xC4,0xC4,
    0x40,0x21,0x18,0x4E,0x55,0x86,0xF4,0xDC,
    0x8A,0x15,0xA7,0xEC,0x92,0xDF,0x93,0x53,
    0x30,0x18,0xCA,0x34,0xBF,0xA2,0xC7,0x59,
    0x67,0x8F,0xBA,0x0D,0x6D,0xD8,0x2D,0x7D,
    0x54,0x0A,0x57,0x97,0x70,0x39,0xD2,0x7A,
    0xEA,0x24,0x33,0x85,0xED,0x9A,0x1D,0xE0
};

#define DR_5800MHz_2Mbps

#ifdef DR_5800MHz_4Mbps
const uint8_t A5130Config[] =
{
	0x00, //RESET register,			
	0x62, //MODE register, 
	0x00, //CALIBRATION register,	
	0x3F, //FIFO1 register,
	0x00, //FIFO2 register,
	0x00, //FIFO register,		
	0x00, //IDDATA register,	
	0x00, //RCOSC1 register,
	0x00, //RCOSC2 register,
	0x0C, //RCOSC3 register,
	0x10, //CKO register,
	0x19, //GPIO1 register
	0x01, //GPIO2 register,
	0x1F, //DATARATECLOCK register,
	0x41, //PLL1 register,
	0x1E, //PLL2 register, 				
	0x59, //PLL3 register,
	0x74, //PLL4 register,
	0x01, //PLL5 register,
	0x32, //ChannelGroup1 register,
	0x64, //ChannelGroup1 register,
	0x2D, //TX1 register, 				
	0x40, //TX2 register,
	0x19, //DELAY1 register,
	0x40, //DELAY2 register,
	0x70, //RX register,
	0x7B, //RXGAIN1 register,
	0xC0, //RXGAIN2 register,				
	0x7C, //RXGAIN3 register,
	0xCA, //RXGAIN4 register,
	0x00, //RSSI register,
	0xC9, //ADC register,
	0x0C, //CODE1 register,
	0x0F, //CODE2 register, 				
	0x2A, //CODE3 register,
	0xE4, //IFCAL1 register,
	0x01, //IFCAL2 register,    			
	0x4F, //VCOCCAL register,
	0xC0, //VCOCAL1 register,
	0x80, //VCOCAL2 register,
	0x70, //VCO deviation 1 register,
	0x40, //VCO deviation 2 register,
	0x00, //DSA register,
	0x7F, //VCO Modulation delay register,	
	0x60, //BATTERY register,
	0x7B, //TXTEST register,
	0x57, //RXDEM1 register,
	0x74, //RXDEM2 register,
	0xF3, //CPC1 register,
	0x33, //CPC2 register,
	0x4D, //CRYSTAL register,
	0x15, //PLLTEST register,
	0x0F, //VCOTEST register,
	0x00, //RF Analog register,
	0x00, //Key data register,
	0x37, //Channel select register,
	0x00, //ROM register,
	0x00, //DataRate register,
	0x00, //FCR register,
	0x00, //ARD register,
	0x00, //AFEP register,
	0x00, //FCB register,
	0x00, //KEYC register,
	0x00  //USID register,
};

const uint8_t A5130_Addr2A_Config[]=
{
	0x2A, //page0, //49US, CL=18pF, CSXTL=42
	0x81, //page1,
	0xF0, //Page2,
	0x80, //page3,
	0x80, //page4,
	0x48, //page5,
	0x00, //page6,
	0xC0, //page7,
	0x3A, //page8,
	0x3E, //page9,
	0xE8, //page10,
	0x80, //page11,
	0x00  //page12,
};

const uint8_t A5130_Addr38_Config[]=
{
	0x74, //page0,
	0x50, //page1,
	0x0D, //page2,
	0x24, //page3,
	0x06, //page4,
	0x40, //page5,
	0x60, //page6,
	0x04, //page7,
	0x00, //page8,
	0x00, //page9,
	0x00  //page10,
};
#endif

#ifdef DR_5800MHz_2Mbps
const uint8_t A5130Config[]=
{
	0x00, //RESET register,			
	0x62, //MODE register, 
	0x00, //CALIBRATION register,	
	0x3F, //FIFO1 register,
	0x00, //FIFO2 register,
	0x00, //FIFO register,		
	0x00, //IDDATA register,	
	0x00, //RCOSC1 register,
	0x00, //RCOSC2 register,
	0x0C, //RCOSC3 register,
	0x10, //CKO register,
	0x19, //GPIO1 register
	0x01, //GPIO2 register,
	0x1F, //DATARATECLOCK register,
	0x41, //PLL1 register,
	0x1E, //PLL2 register, 				
	0x59, //PLL3 register,
	0x74, //PLL4 register,
	0x01, //PLL5 register,
	0x32, //ChannelGroup1 register,
	0x64, //ChannelGroup1 register,
	0x2C, //TX1 register, 				
	0x40, //TX2 register,
	0x19, //DELAY1 register,
	0x40, //DELAY2 register,
	0x70, //RX register,
	0x7B, //RXGAIN1 register,
	0xC0, //RXGAIN2 register,				
	0x5C, //RXGAIN3 register,
	0xCA, //RXGAIN4 register,
	0x00, //RSSI register,
	0xC9, //ADC register,
	0x0C, //CODE1 register,
	0x0F, //CODE2 register, 				
	0x2A, //CODE3 register,
	0xA4, //IFCAL1 register,
	0x01, //IFCAL2 register,    			
	0x4F, //VCOCCAL register,
	0xC0, //VCOCAL1 register,
	0x80, //VCOCAL2 register,
	0x70, //VCO deviation 1 register,
	0x40, //VCO deviation 2 register,
	0x00, //DSA register,
	0x40, //VCO Modulation delay register,	
	0x60, //BATTERY register,
	0x7B, //TXTEST register,
	0x57, //RXDEM1 register,
	0x74, //RXDEM2 register,
	0xF3, //CPC1 register,
	0x33, //CPC2 register,
	0x4D, //CRYSTAL register,
	0x15, //PLLTEST register,
	0x0F, //VCOTEST register,
	0x00, //RF Analog register,
	0x00, //Key data register,
	0x17, //Channel select register,
	0x00, //ROM register,
	0x00, //DataRate register,
	0x00, //FCR register,
	0x00, //ARD register,
	0x00, //AFEP register,
	0x00, //FCB register,
	0x00, //KEYC register,
	0x00  //USID register,
};

const uint8_t A5130_Addr2A_Config[]=
{
	0x2A, //page0, //49US, CL=18pF, CSXTL=42
	0x81, //page1,
	0xF0, //Page2,
	0x80, //page3,
	0x80, //page4,
	0x48, //page5,
	0x00, //page6,
	0x40, //page7,
	0x3A, //page8,
	0x3E, //page9,
	0xE8, //page10,
	0x80, //page11,
	0x00  //page12,
};

const uint8_t A5130_Addr38_Config[]=
{
	0x74, //page0,
	0x50, //page1,
	0x0D, //page2,
	0x24, //page3,
	0x06, //page4,
	0x40, //page5,
	0x60, //page6,
	0x04, //page7,
	0x00, //page8,
	0x00, //page9,
	0x00  //page10,
};
#endif

#ifdef DR_5800MHz_1Mbps
const uint8_t A5130Config[]=
{
	0x00, //RESET register,			
	0x62, //MODE register, 
	0x00, //CALIBRATION register,	
	0x3F, //FIFO1 register,
	0x00, //FIFO2 register,
	0x00, //FIFO register,		
	0x00, //IDDATA register,	
	0x00, //RCOSC1 register,
	0x00, //RCOSC2 register,
	0x0C, //RCOSC3 register,
	0x10, //CKO register,
	0x19, //GPIO1 register
	0x01, //GPIO2 register,
	0x1F, //DATARATECLOCK register,
	0x41, //PLL1 register,
	0x1E, //PLL2 register, 				
	0x59, //PLL3 register,
	0x74, //PLL4 register,
	0x01, //PLL5 register,
	0x32, //ChannelGroup1 register,
	0x64, //ChannelGroup1 register,
	0x2C, //TX1 register, 				
	0x40, //TX2 register,
	0x19, //DELAY1 register,
	0x40, //DELAY2 register,
	0x70, //RX register,
	0x7B, //RXGAIN1 register,
	0xC0, //RXGAIN2 register,				
	0x5C, //RXGAIN3 register,
	0xCA, //RXGAIN4 register,
	0x00, //RSSI register,
	0xC9, //ADC register,
	0x0C, //CODE1 register,
	0x0F, //CODE2 register, 				
	0x2A, //CODE3 register,
	0xA4, //IFCAL1 register,
	0x01, //IFCAL2 register,    			
	0x4F, //VCOCCAL register,
	0xC0, //VCOCAL1 register,
	0x80, //VCOCAL2 register,
	0x70, //VCO deviation 1 register,
	0x40, //VCO deviation 2 register,
	0x00, //DSA register,
	0x40, //VCO Modulation delay register,	
	0x60, //BATTERY register,
	0x7B, //TXTEST register,
	0x57, //RXDEM1 register,
	0x74, //RXDEM2 register,
	0xF3, //CPC1 register,
	0x33, //CPC2 register,
	0x4D, //CRYSTAL register,
	0x15, //PLLTEST register,
	0x0F, //VCOTEST register,
	0x00, //RF Analog register,
	0x00, //Key data register,
	0x17, //Channel select register,
	0x00, //ROM register,
	0x01, //DataRate register,
	0x00, //FCR register,
	0x00, //ARD register,
	0x00, //AFEP register,
	0x00, //FCB register,
	0x00, //KEYC register,
	0x00  //USID register,
};

const uint8_t A5130_Addr2A_Config[]=
{
	0x2A, //page0, //49US, CL=18pF, CSXTL=42 
	0x81, //page1,
	0xF0, //Page2,
	0x80, //page3,
	0x80, //page4,
	0x48, //page5,
	0x00, //page6,
	0x40, //page7,
	0x3A, //page8,
	0x3E, //page9,
	0xE8, //page10,
	0x80, //page11,
	0x00  //page12,
};

const uint8_t A5130_Addr38_Config[]=
{
	0x74, //page0,
	0x50, //page1,
	0x0D, //page2,
	0x24, //page3,
	0x06, //page4,
	0x40, //page5,
	0x60, //page6,
	0x04, //page7,
	0x00, //page8,
	0x00, //page9,
	0x00  //page10,
};
#endif 

void Err_State(void)
{
    //A5130 error handler
    while(1){;}
}

void A5130_WriteReg2Byte(uint8_t addr, uint8_t dataByte1, uint8_t dataByte2)
{
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, &addr, 1, 100);
    HAL_SPI_Transmit(&hspi1, &dataByte1, 1, 100);
    HAL_SPI_Transmit(&hspi1, &dataByte2, 1, 100);
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_SET);
}

void A5130_WriteReg(uint8_t addr, uint8_t dataByte)
{
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, &addr, 1, 100);
    HAL_SPI_Transmit(&hspi1, &dataByte, 1, 100);
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_SET);
}

uint8_t A5130_ReadReg(uint8_t addr)
{
    uint8_t tmp;
    addr |= 0x40;
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, &addr, 1, 100);
    HAL_SPI_Receive(&hspi1, &tmp, 1, 100);
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_SET);
    return tmp;
}

void A5130_WriteReg_Page(uint8_t addr, uint8_t wbyte, uint8_t page)
{
  	A5130_WriteReg(RFANALOG_REG, (A5130Config[0x35]& 0x0F) | (page<<4));
  	A5130_WriteReg(addr, wbyte);
}

void A5130_Reset(void)
{
    A5130_WriteReg(MODE_REG, 0x00);
}

void A5130_WriteID(void)
{
    int i;
    uint8_t addr = IDCODE_REG;
    
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, &addr, 1, 100);
    for (i=0; i < 8; i++)
        HAL_SPI_Transmit(&hspi1, &ID_Tab[i], 1, 100);
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_SET);
}

void A5130_Config(void)
{
    int i;

  	for (i=MODECTRL_REG; i<=FIFO2_REG; i++)
	    A5130_WriteReg(i, A5130Config[i]);

  	for (i=RCOSC1_REG; i<=VCODEVCAL2_REG; i++)
  		A5130_WriteReg(i, A5130Config[i]);

  	for (i=0; i<=12; i++)
  		A5130_WriteReg_Page(DASP_REG, A5130_Addr2A_Config[i], i);

  	for (i=VCOMODDELAY_REG; i<=RFANALOG_REG; i++)
  		A5130_WriteReg(i, A5130Config[i]);

  	A5130_WriteReg(CHSELECT_REG, A5130Config[CHSELECT_REG]);

  	for (i=0; i<=10; i++)
  		A5130_WriteReg_Page(ROMP_REG, A5130_Addr38_Config[i], i);

  	for (i=DATARATECLOCK; i<=AFEP_REG; i++)
  		A5130_WriteReg(i, A5130Config[i]);

  	A5130_WriteReg(KEYC_REG, A5130Config[KEYC_REG]);
}

void A5130_Trimming_read(void)
{
    uint8_t addr;

    A5130_WriteReg_Page(ROMP_REG, 0xA0, 9);	

    HAL_Delay(10);

    addr = USID_REG | 0x40;

    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, &addr, 1, 100);
    HAL_SPI_Receive(&hspi1, &trimCBG, 1, 100);
    HAL_SPI_Receive(&hspi1, &trimCTR, 1, 100);
    HAL_SPI_Receive(&hspi1, &trimBDC, 1, 100);
    HAL_SPI_Receive(&hspi1, &trimSTM, 1, 100);
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_SET);

    A5130_WriteReg_Page(ROMP_REG, 0x20, 9);	

    HAL_Delay(5);
}

void A5130_Trimming_write(void)
{
  	uint8_t tmp;

  	tmp=(uint8_t)0x40+trimCBG;

  	A5130_WriteReg_Page(ROMP_REG, tmp, 1);	//BPBG
  	A5130_WriteReg_Page(ROMP_REG, trimCTR, 2);	//ADC trimming
  	A5130_WriteReg_Page(ROMP_REG, trimBDC << 2, 0);	//Battery detect
  	A5130_WriteReg_Page(ROMP_REG, trimSTM, 4);	//V-temp trimming
}

void StrobeCmd(uint8_t src)
{
    uint8_t cmd;
    if (cmd == 0x80)  //Sleep mode
    	A5130_WriteReg(BATTERY_REG, A5130Config[BATTERY_REG] & ~0x20);
    else
    	A5130_WriteReg(BATTERY_REG, A5130Config[BATTERY_REG]);

    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, &src, 1, 100);
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_SET);
}

static void CHGroupCal(uint8_t ch)
{
    uint8_t i;
    uint8_t tmp;
    uint8_t vb,vbcf,vc,vccf;
    uint8_t deva,adev;

    A5130_WriteReg(PLL1_REG, ch);
    A5130_WriteReg(VCOCCAL_REG, A5130Config[0x25]);	//for test mode

    for(i=0;i<5;i++)
    {

    	A5130_WriteReg(CALIBRATION_REG, 0x1C);
    	do
    	{
    		tmp = A5130_ReadReg(CALIBRATION_REG);
    		tmp &= 0x1C;
    	}
    	while (tmp);

    }
    //for check
    tmp = A5130_ReadReg(VCOCAL1_REG);
    vb = tmp & 0x0F;
    vbcf = (tmp >>4) & 0x01;

    tmp = A5130_ReadReg(VCOCCAL_REG);
    vc = tmp & 0x0F;
    vccf = (tmp >>4) & 0x01;

    tmp = A5130_ReadReg(VCODEVCAL1_REG);
    deva = tmp;

    tmp = A5130_ReadReg(VCODEVCAL2_REG);
    adev = tmp;

    if (vbcf || vccf)
       Err_State();
}

void A5130_Cal(void)
{
    uint8_t tmp;
    uint8_t fb, fbcf, fcd, rhc, rlc;

    StrobeCmd(CMD_PLL); //calibration @PLL state

    //calibration IF procedure
    A5130_WriteReg(CALIBRATION_REG, 0x63);
    do
    {
    	tmp = A5130_ReadReg(CALIBRATION_REG);
    	tmp &= 0x63;
    }
    while(tmp);

    //calibration VBC,VDC procedure
    CHGroupCal(25);		//calibrate channel group Bank I
    CHGroupCal(75);		//calibrate channel group Bank II
    CHGroupCal(125);	//calibrate channel group Bank III
    StrobeCmd(CMD_STBY); //return to STBY state

    //for check
    tmp = A5130_ReadReg(IFCAL1_REG);
    fb = tmp & 0x0F;
    fbcf = (tmp >>4) & 0x01;

    tmp = A5130_ReadReg(IFCAL2_REG);
    fcd = tmp & 0x1F;

    rhc = A5130_ReadReg(RXGAIN2_REG);
    rlc = A5130_ReadReg(RXGAIN3_REG);

    if (fbcf)
       Err_State();
}

void WriteFIFO(uint8_t length)
{
    uint8_t i, cmd;

    A5130_WriteReg( FIFO1_REG, length-1);
    StrobeCmd(CMD_TFR);
    
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_RESET);
    cmd = FIFO_REG;
    HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);
    HAL_SPI_Transmit_DMA(&hspi1, PN9_Tab, 8);
    HAL_Delay(1);
    HAL_GPIO_WritePin(SPI_CS_PORT,SPI_CS,GPIO_PIN_SET);
}

void WriteFIFOData(uint8_t length, uint8_t *pData)
{
    uint8_t cmd;

    A5130_WriteReg( FIFO1_REG, length-1);
    
    SPI_CS_PORT->BRR = SPI_CS;
    cmd = FIFO_REG;
    HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);
    txLock=HAL_LOCKED;
    HAL_SPI_Transmit_DMA(&hspi1, pData, length);
    while(txLock==HAL_LOCKED){}
    SPI_CS_PORT->BSRR = SPI_CS;
}

void ReadFIFOData(uint8_t length, uint8_t *pData)
{
    uint8_t i, cmd, recv[100];

    SPI_CS_GPIO_Port->BRR = SPI_CS_Pin;
    cmd = FIFO_REG | 0x40;

    HAL_SPI_Transmit(&hspi1, &cmd, 1, 10);
    HAL_SPI_Receive_DMA(&hspi1, pData, length);

    rxLock = HAL_LOCKED;
    osSemaphoreWait(rxSemHandle,1);
    SPI_CS_GPIO_Port->BSRR = SPI_CS_Pin;
}

void A5130_init(void)
{
    A5130_Reset();
    A5130_WriteID();
    A5130_Config();
    A5130_Trimming_read();
    A5130_Trimming_write();
    A5130_Cal();

    StrobeCmd(CMD_STBY);

    A5130_WriteReg(CKO_REG, 0x02);		//DCK
    A5130_WriteReg(GIO1_REG, 0x19);		//TRXD
    A5130_WriteReg(GIO2_REG, 0x01);		//WTR

    A5130_WriteReg(MODECTRL_REG, 0x62);	//FIFO mode
    A5130_WriteReg(PLL1_REG, 65); 							//5790.001MHz
}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    txLock=HAL_UNLOCKED;
}

void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
    rxLock = HAL_UNLOCKED;
    osSemaphoreRelease(rxSemHandle); 
}

void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
}

