/*
==========================未经授权，转载需保留此信息============================
Function : Operation for cc1101
Taobao website:http://zeyaotech.taobao.com/
Official website:http://www.ashining.com/
Written by:Lijian
TEL:028-64891123(Sales),028-64891129(Technology),e-mail: service@ashining.com
================================================================================
*/
/*

Description : This module contains the low level operations for CC1101

*/
#include "CC1101.H"

//10, 7, 5, 0, -5, -10, -15, -20, dbm output power, 0x12 == -30dbm
const INT8U PaTabel[] = { 0xc0, 0xC8, 0x84, 0x60, 0x68, 0x34, 0x1D, 0x0E};

// Sync word qualifier mode = 30/32 sync word bits detected 
// CRC autoflush = false 
// Channel spacing = 199.951172 
// Data format = Normal mode 
// Data rate = 2.00224 
// RX filter BW = 58.035714 
// PA ramping = false 
// Preamble count = 4 
// Whitening = false 
// Address config = No address check 
// Carrier frequency = 400.199890 
// Device address = 0 
// TX power = 10 
// Manchester enable = false 
// CRC enable = true 
// Deviation = 5.157471 
// Packet length mode = Variable packet length mode. Packet length configured by the first byte after sync word 
// Packet length = 255 
// Modulation format = GFSK 
// Base frequency = 399.999939 
// Modulated = true 
// Channel number = 1 
// PA table 
#define PA_TABLE {0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}

static const INT8U CC1101InitData[22][2]= 
{
  {CC1101_IOCFG0,      0x06},
  {CC1101_FIFOTHR,     0x47},
  {CC1101_PKTCTRL0,    0x05},
  {CC1101_CHANNR,      0x96},///430M
  {CC1101_FSCTRL1,     0x06},
  {CC1101_FREQ2,       0x0F},
  {CC1101_FREQ1,       0x62},
  {CC1101_FREQ0,       0x76},
  {CC1101_MDMCFG4,     0xF6},
  {CC1101_MDMCFG3,     0x43},
  {CC1101_MDMCFG2,     0x13},
  {CC1101_DEVIATN,     0x15},
  {CC1101_MCSM0,       0x18},
  {CC1101_FOCCFG,      0x16},
  {CC1101_WORCTRL,     0xFB},
  {CC1101_FSCAL3,      0xE9},
  {CC1101_FSCAL2,      0x2A},
  {CC1101_FSCAL1,      0x00},
  {CC1101_FSCAL0,      0x1F},
  {CC1101_TEST2,       0x81},
  {CC1101_TEST1,       0x35},
  {CC1101_MCSM1,       0x3B},
};


/*read a byte from the specified register*/
INT8U GS_CC1101ReadReg( INT8U addr );

/*Read some bytes from the rigisters continously*/
void GS_CC1101ReadMultiReg( INT8U addr, INT8U *buff, INT8U size );

/*Write a byte to the specified register*/
void GS_CC1101WriteReg( INT8U addr, INT8U value );

/*Flush the TX buffer of CC1101*/
void GS_CC1101ClrTXBuff( void );

/*Flush the RX buffer of CC1101*/
void GS_CC1101ClrRXBuff( void );

/*Get received count of CC1101*/
INT8U GS_CC1101GetRXCnt( void );

/*Reset the CC1101 device*/
void GS_CC1101Reset( void );

/*Write some bytes to the specified register*/
void GS_CC1101WriteMultiReg( INT8U addr, INT8U *buff, INT8U size );


/** 
 * @brief Initialize the WOR function of CC1101
 * @param None
 * @retval None
 */
void  GS_CC1101WORInit( void )
{

    GS_CC1101WriteReg(CC1101_MCSM0,0x18);
    GS_CC1101WriteReg(CC1101_WORCTRL,0x78); //Wake On Radio Control
    GS_CC1101WriteReg(CC1101_MCSM2,0x00);
    GS_CC1101WriteReg(CC1101_WOREVT1,0x8C);
    GS_CC1101WriteReg(CC1101_WOREVT0,0xA0);
	
	GS_CC1101WriteCmd( CC1101_SWORRST );
}

/**
 * @brief read a byte from the specified register
 * @param addr, The address of the register
 * @retval the byte read from the rigister
 */
INT8U GS_CC1101ReadReg( INT8U addr )
{
    INT8U i;
    CC_CSN_LOW( );
    SPI_ExchangeByte( addr | READ_SINGLE);
    i = SPI_ExchangeByte( 0xFF );
    CC_CSN_HIGH( );
    return i;
}

/**
 * @brief  Read some bytes from the rigisters continously
 * @param  addr, The address of the register
 * @param  buff, The buffer stores the data
 * @param  size, How many bytes should be read
 * @retval None
*/
void GS_CC1101ReadMultiReg( INT8U addr, INT8U *buff, INT8U size )
{
    INT8U i, j;
    CC_CSN_LOW( );
    SPI_ExchangeByte( addr | READ_BURST);
    for( i = 0; i < size; i ++ )
    {
        for( j = 0; j < 20; j ++ );
        *( buff + i ) = SPI_ExchangeByte( 0xFF );
    }
    CC_CSN_HIGH( );
}


/**
 * @brief Read a status register
 * @param addr, The address of the register
 * @retval the value read from the status register
 */
INT8U GS_CC1101ReadStatus( INT8U addr )
{
    INT8U i;
    CC_CSN_LOW( );
    SPI_ExchangeByte( addr | READ_BURST);
    i = SPI_ExchangeByte( 0xFF );
    CC_CSN_HIGH( );
    return i;
}


/**
 * @brief Set the device as TX mode or RX mode
 * @param mode selection
 * @retval None
 */
void GS_CC1101SetTRMode( TRMODE mode )
{
    if( mode == TX_MODE )
    {
        GS_CC1101WriteReg(CC1101_IOCFG0,0x46);
        GS_CC1101WriteCmd( CC1101_STX );
    }
    else if( mode == RX_MODE )
    {
        GS_CC1101WriteReg(CC1101_IOCFG0,0x46);
        GS_CC1101WriteCmd( CC1101_SRX );
    }
}


/**
 * @brief Write a byte to the specified register
 * @param addr, The address of the register
 * @param value, the byte you want to write
 * @retval None
 */
void GS_CC1101WriteReg( INT8U addr, INT8U value )
{
    CC_CSN_LOW( );
    SPI_ExchangeByte( addr );
    SPI_ExchangeByte( value );
    CC_CSN_HIGH( );
}


/**
 * @brief Write some bytes to the specified register
 * @param addr, The address of the register
 * @param buff, a buffer stores the values
 * @param size, How many byte should be written
 * @retval None
 */
void GS_CC1101WriteMultiReg( INT8U addr, INT8U *buff, INT8U size )
{
    INT8U i;
    CC_CSN_LOW( );
    SPI_ExchangeByte( addr | WRITE_BURST );
    for( i = 0; i < size; i ++ )
    {
        SPI_ExchangeByte( *( buff + i ) );
    }
    CC_CSN_HIGH( );
}


/**
 * @brief Write a command byte to the device
 * @param command, the byte you want to write
 * @retval None
 */
void GS_CC1101WriteCmd( INT8U command )
{
    CC_CSN_LOW( );
    SPI_ExchangeByte( command );
    CC_CSN_HIGH( );
}


/**
 * @brief Reset the CC1101 device
 * @param None
 * @retval None
 */ 
void GS_CC1101Reset( void )
{
    INT8U x;

    CC_CSN_HIGH( );
    CC_CSN_LOW( );
    CC_CSN_HIGH( );
    for( x = 0; x < 100; x ++ );
    GS_CC1101WriteCmd( CC1101_SRES );
}


/*
 * @brief Set the CC1101 into IDLE mode
 * @param None
 * @retval None
 */ 
void GS_CC1101SetIdle( void )
{
    GS_CC1101WriteCmd(CC1101_SIDLE);
}


/*
 * @brief Flush the TX buffer of CC1101
 * @param None
 * @retval None
 */ 
void GS_CC1101ClrTXBuff( void )
{
    GS_CC1101SetIdle();//MUST BE IDLE MODE
    GS_CC1101WriteCmd( CC1101_SFTX );
}
/**
 * @brief Flush the RX buffer of CC1101
 * @param None
 * @retval None
 */ 
void GS_CC1101ClrRXBuff( void )
{
    GS_CC1101SetIdle();//MUST BE IDLE MODE
    GS_CC1101WriteCmd( CC1101_SFRX );
}


/**
 * @brief Send a packet
 * @param txbuffer, The buffer stores data to be sent
 * @param size, How many bytes should be sent
 * @param mode, Broadcast or address check packet
 * @retval None
 */ 
void GS_CC1101SendPacket( INT8U *txbuffer, INT8U size, TX_DATA_MODE mode )
{
    INT8U address;
    if( mode == BROADCAST )             { address = 0; }
    else if( mode == ADDRESS_CHECK )    { address = GS_CC1101ReadReg( CC1101_ADDR ); }

    GS_CC1101ClrTXBuff( );
    
    if( ( GS_CC1101ReadReg( CC1101_PKTCTRL1 ) & ~0x03 ) != 0 )
    {
        GS_CC1101WriteReg( CC1101_TXFIFO, size + 1 );
        GS_CC1101WriteReg( CC1101_TXFIFO, address );
    }
    else
    {
        GS_CC1101WriteReg( CC1101_TXFIFO, size );
    }

    GS_CC1101WriteMultiReg( CC1101_TXFIFO, txbuffer, size );
    GS_CC1101SetTRMode( TX_MODE );
    while( GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_2 ) != 0 );
    while( GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_2 ) == 0 );

    GS_CC1101ClrTXBuff( );
}


/**
 * @brief Get received count of CC1101
 * @param None
 * @retval How many bytes hae been received
 */
INT8U GS_CC1101GetRXCnt( void )
{
    return ( GS_CC1101ReadStatus( CC1101_RXBYTES )  & BYTES_IN_RXFIFO );
}


/**
 * @brief Set the address and address mode of the CC1101
 * @param address, The address byte
 * @param AddressMode, the address check mode
 * @retval None
 */
void GS_CC1101SetAddress( INT8U address, ADDR_MODE AddressMode)
{
    INT8U btmp = GS_CC1101ReadReg( CC1101_PKTCTRL1 ) & ~0x03;
    GS_CC1101WriteReg(CC1101_ADDR, address);
    if     ( AddressMode == BROAD_ALL )     {}
    else if( AddressMode == BROAD_NO  )     { btmp |= 0x01; }
    else if( AddressMode == BROAD_0   )     { btmp |= 0x02; }
    else if( AddressMode == BROAD_0AND255 ) { btmp |= 0x03; }   
}


/**
 * @brief Set the SYNC bytes of the CC1101
 * @param sync, 16bit sync 
 * @retval None
 */
void GS_CC1101SetSYNC( INT16U sync )
{
    GS_CC1101WriteReg(CC1101_SYNC1, 0xFF & ( sync>>8 ) );
    GS_CC1101WriteReg(CC1101_SYNC0, 0xFF & sync ); 
}


/**
 * @brief Receive a packet
 * @param rxBuffer, A buffer store the received data
 * @retval 1:received count, 0:no data
 */
INT8U GS_CC1101RecPacket( INT8U *rxBuffer )
{
    INT8U status[2];
    INT8U pktLen;
    INT16U x , j = 0;

    if ( GS_CC1101GetRXCnt( ) != 0 )
    {
        pktLen = GS_CC1101ReadReg(CC1101_RXFIFO);           // Read length byte
        if( ( GS_CC1101ReadReg( CC1101_PKTCTRL1 ) & ~0x03 ) != 0 )
        {
            x = GS_CC1101ReadReg(CC1101_RXFIFO);
        }
        if( pktLen == 0 )           { return 0; }
        else                        { pktLen --; }
        GS_CC1101ReadMultiReg(CC1101_RXFIFO, rxBuffer, pktLen); // Pull data
        GS_CC1101ReadMultiReg(CC1101_RXFIFO, status, 2);   // Read  status bytes

        GS_CC1101ClrRXBuff( );

        if( status[1] & CRC_OK ) {   return pktLen; }
        else                     {   return 0; }
    }
    else   {  return 0; }                               // Error
}


/**
 * @brief Initialize the CC1101, User can modify it
 * @param None
 * @retval None
 */ 
void GS_CC1101Init( void )
{
    volatile INT8U i, j;

    GS_CC1101Reset( );    
    
    for( i = 0; i < 22; i++ )
    {
        GS_CC1101WriteReg( CC1101InitData[i][0], CC1101InitData[i][1] );
    }
    GS_CC1101SetAddress( 0x05, BROAD_0AND255 );
    GS_CC1101SetSYNC( 0x8799 );
    GS_CC1101WriteReg(CC1101_MDMCFG1,   0x72); //Modem Configuration

    GS_CC1101WriteMultiReg(CC1101_PATABLE, PaTabel, 8 );

    i = GS_CC1101ReadStatus( CC1101_PARTNUM );//for test, must be 0x80
    i = GS_CC1101ReadStatus( CC1101_VERSION );//for test, refer to the datasheet
}


/*

------------------------------------THE END-------------------------------------

*/
