/*--------------------------------------------------------------------------*/
/**@file     bk1080.c
   @brief    BK1080收音底层驱动
   @details
   @author
   @date   2011-3-30
   @note
*/
/*----------------------------------------------------------------------------*/

#include "app_config.h"

#include "system/includes.h"
#include "fm/fm_manage.h"
#include "BK1080.h"

#if(TCFG_FM_BK1080_ENABLE && TCHFG_SOFT_I2C_ENABLE)


extern void delay_2ms(int cnt);

#define delay_n10ms(x)      \
	delay_2ms(x*5)

static struct _fm_dev_info *fm_dev_info;

/**
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 必看 @@@@@@@@@@@@@@@@@@@@@@@@@@@
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 必看 @@@@@@@@@@@@@@@@@@@@@@@@@@@
*
*BK1080H可以使用外部晶振
*
*BK1080E不能使用外部晶振，因此主控需要提供一个时钟
*BK1080E需要的时钟范围是：32.768kHz~38.4MHz
*可以通过以下bk1080e_set_clk函数让主控在PA0输出一个24MHz的时钟
*该函数使用时加到int fm_dev_init(void *_data)函数的第一行
*该时钟及输出的IO口可配置，如需要可联系原厂提供帮助
*
*/
/* void bk1080e_set_clk(void){ */
/* JL_PORTA->DIR &= ~BIT(0); */
/* JL_CLOCK->CLK_CON0 &=~ BIT(12); */

/* JL_CLOCK->CLK_CON0 &=~ BIT(11); */
/* JL_CLOCK->CLK_CON0 |= BIT(10); */
/* } */


/*------------BK1080 Initialization Table-----------------*/
/*
const u16 HW_Reg[]=
{
    0x0008,
    0x1080,
#if XTAL_CLOCK	//reg2
    0x1201,	//for internal crystal clock
#else
    0x0201,	//for extern clock
#endif
    0x0000,
    0x40C0,
    0x0A1F,	  //reg5	RSSI[15:8] BAND[7:6] SPACE[5:4],Europe standar
    0x002E,
    0x02FF,
    0x5B11,
    0x0000,
    0x411E,
    0x0000,
    0xCE00,
    0x0000,
    0x0000,
    0x1000,		//reg15
    0x0010,
    0x0000,
    0x13FF,
    0x9852,
    0x0000,
    0x0000,
    0x0008,
    0x0000,
    0x51E1,
    0x28DC,
    0x2645,
    0x00E4,
    0x1CD8,
    0x3A50,
    0xEAF0,
    0x3000,	//reg31
    0x0200,
    0x0000,
};
*/

const u16 HW_Reg[] = {
    0x0800,
    0x8010,
#if XTAL_CLOCK	//reg2
    0x0112,	//for internal crystal clock
#else
    0x0142,	//for extern clock, system mute
#endif
    0x0000,
    0xC040,
    0x1F0A,	  //reg5	RSSI[15:8] BAND[7:6] SPACE[5:4],Europe standar
    0x2E00,
    0xFF02,
    0x115B,
    0x0000,
    0x1E41,
    0x0000,
    0x00CE,
    0x0000,
    0x0000,
    0x0010,		//reg15
    0x1000,
    0x0000,
    0xFF13,
    0x5298,
    0x0000,
    0x0000,
    0x0800,
    0x0000,
    0xE151,
    0xDC38,
    0x4526,
    0xE400,
    0xD81C,
    0x503A,
    0xF0EA,
    0x0030,	//reg31
    0x0002,
    0x0000,
};


u8 bk1080_iic_write(u8 w_chip_id, u8 register_address, u8 *buf, u32 data_len)
{
    u8 ret = 1;
    iic_start(fm_dev_info->iic_hdl);
    if (0 == iic_tx_byte(fm_dev_info->iic_hdl, w_chip_id)) {
        ret = 0;
        log_e("\n fm iic wr err 0\n");
        goto __gcend;
    }

    delay(fm_dev_info->iic_delay);

    if (0 == iic_tx_byte(fm_dev_info->iic_hdl, register_address)) {
        ret = 0;
        log_e("\n fm iic wr err 1\n");
        goto __gcend;
    }
    u8 *pbuf = buf;

    while (data_len--) {
        delay(fm_dev_info->iic_delay);

        if (0 == iic_tx_byte(fm_dev_info->iic_hdl, *pbuf++)) {
            ret = 0;
            log_e("\n fm iic wr err 2\n");
            goto __gcend;
        }
    }

__gcend:
    iic_stop(fm_dev_info->iic_hdl);

    return ret;
}

u8 bk1080_iic_readn(u8 r_chip_id, u8 register_address, u8 *buf, u8 data_len)
{
    u8 read_len = 0;

    iic_start(fm_dev_info->iic_hdl);
    if (0 == iic_tx_byte(fm_dev_info->iic_hdl, (r_chip_id & 0x01) ? (r_chip_id - 1) : (r_chip_id))) {
        log_e("\n fm iic rd err 0\n");
        read_len = 0;
        goto __gdend;
    }


    delay(fm_dev_info->iic_delay);
    if (0 == iic_tx_byte(fm_dev_info->iic_hdl, register_address)) {
        log_e("\n fm iic rd err 1\n");
        read_len = 0;
        goto __gdend;
    }

    /* delay(fm_dev_info->iic_delay); */
    /* iic_start(fm_dev_info->iic_hdl); */
    /* if (0 == iic_tx_byte(fm_dev_info->iic_hdl, r_chip_id)) { */
    /* log_e("\n fm iic rd err 2\n"); */
    /* read_len = 0; */
    /* goto __gdend; */
    /* } */

    delay(fm_dev_info->iic_delay);

    for (; data_len > 1; data_len--) {
        *buf++ = iic_rx_byte(fm_dev_info->iic_hdl, 1);
        read_len ++;
    }

    *buf = iic_rx_byte(fm_dev_info->iic_hdl, 0);

__gdend:

    iic_stop(fm_dev_info->iic_hdl);
    delay(fm_dev_info->iic_delay);

    return read_len;
}

#define app_IIC_write bk1080_iic_write
#define app_IIC_readn bk1080_iic_readn

/*----------------------------------------------------------------------------*/
/**@brief    BK1080读寄存器函数
   @param    num 需要的数目
   @return   无
   @note     void BEKEN_I2c_Read(u8 reg,u8 *pBuf,u8 num)
*/
/*----------------------------------------------------------------------------*/
static void BEKEN_I2c_Read(u8 reg, u8 *pBuf, u8 num)
{
    reg = reg << 1;
    reg |= 0x01;
    app_IIC_readn(CHIP_DEV_ID, reg, pBuf, num);
}

/*----------------------------------------------------------------------------*/
/**@brief    BK1080读寄存器函数
   @param    num 需要的数目
   @return   无
   @note     void BEKEN_I2c_Write(u8 reg,u8 *pBuf,u8 num)
*/
/*----------------------------------------------------------------------------*/
static void BEKEN_I2c_Write(u8 reg, u8 *pBuf, u8 num)
{
    reg = reg << 1;
    app_IIC_write(CHIP_DEV_ID, reg, pBuf, num);
}

/*----------------------------------------------------------------------------*/
/**@brief    BK1080 初始化
   @param    无
   @return   无
   @note     void init_BK1080(void)
*/
/*----------------------------------------------------------------------------*/
void bk1080_init(void *priv)
{
    if (priv != NULL) {
        fm_dev_info = priv;
    }
    u8 temp[2];
    //delay_n10ms(100);	//delay 1s,please revise delay time according to your MCU

    BEKEN_I2c_Write(0, (u8 *)HW_Reg, 68);	//start from reg2,total 60 byte

    delay_n10ms(25);			//delay 250ms
    temp[0] = HW_Reg[25];
    temp[1] = HW_Reg[25] >> 8;
    temp[1] &= 0x7f;
    BEKEN_I2c_Write(25, temp, 2);

    temp[1] |= 0x80;
    BEKEN_I2c_Write(25, temp, 2);

    /* dac_channel_on(FM_IIC_CHANNEL, FADE_ON); */

    delay_n10ms(5);			//delay 50ms
}


/*----------------------------------------------------------------------------*/
/**@brief    设置一个频点 BK1080
   @param    curFreq：设置频点
   @return   无
   @note     void bk1080_setfreq(u16 curFreq)
*/
/*----------------------------------------------------------------------------*/
void bk1080_setfreq(u16 curFreq)
{
    u8 curChan;
    u16 temp;

    curChan = curFreq - (REAL_FREQ_MIN / 10);

    temp = curChan << 8;
    BEKEN_I2c_Write(0x03, (u8 *)&temp, 2); //write reg3,with 2 bytes

    temp |= 0x80;
    BEKEN_I2c_Write(0x03, (u8 *)&temp, 2);
}

/*----------------------------------------------------------------------------*/
/**@brief    设置一个频点BK1080
   @param    fre 频点  875~1080
   @return   1：当前频点有台，0：当前频点无台
   @note     bool bk1080_set_fre(u16 freq)
*/
/*----------------------------------------------------------------------------*/
bool bk1080_set_fre(void *priv, u16 freq)
{
    static u16 last_tuned_freq;
    static u16 g_last_freq_deviation_value;
    u8 temp[4];
    u16 cur_freq_deviation;

    bk1080_setfreq(freq);
    delay_n10ms(4);		//延时时间>=30ms

///////////////////////////////////////////////////////////////////
//new added 2009-05-30

    BEKEN_I2c_Read(0x07, temp, 2);	//start from reg 0x7,with 2bytes

    cur_freq_deviation = (temp[0] << 8) | temp[1];
    cur_freq_deviation = cur_freq_deviation >> 4;

    BEKEN_I2c_Read(0x0a, &temp[2], 2);

/////////////////////////////////////////////////////////////////////
    if (temp[2] & 0x10) {  			//check AFCRL bit12
        last_tuned_freq = freq;			//save last tuned freqency
        g_last_freq_deviation_value = cur_freq_deviation;
        return 0;
    }

    if (temp[3] < 8) { //RSSI<10   //搜台较少可减少该值，假台较多可增大该值    //8
        last_tuned_freq = freq;			//save last tuned freqency
        g_last_freq_deviation_value = cur_freq_deviation;
        return 0;
    }

    if ((temp[1] & 0x0f) < 2) { //SNR<2 //搜台较少可减少该值，假台较多可增大该值
        last_tuned_freq = freq;			//save last tuned freqency
        g_last_freq_deviation_value = cur_freq_deviation;
        return 0;
    }
/////////////////////////////////////////////////////////////////////////
//add frequency devation check
    if ((cur_freq_deviation >= 192) && (cur_freq_deviation <= (0xfff - 192))) { //0x64 //搜台较少可减少该值，假台较多可增大该值
        last_tuned_freq = freq;			//save last tuned freqency
        g_last_freq_deviation_value = cur_freq_deviation;

        return 0;
    }

///////////////////////////////////////////////////////////////////////////
//new added 2009-05-30
    if ((freq > 875) && ((freq - last_tuned_freq) == 1)) { //start_freq)&&( (freq-last_tuned_freq)==1) )
        if (g_last_freq_deviation_value & 0x800) {
            last_tuned_freq = freq;		//save last tuned freqency
            g_last_freq_deviation_value = cur_freq_deviation;
            return 0;
        }

        if (g_last_freq_deviation_value < 150) { //搜台较少可减少该值，假台较多可增大该值
            last_tuned_freq = freq;		//save last tuned freqency
            g_last_freq_deviation_value = cur_freq_deviation;
            return 0;
        }
    }

    if ((freq >= 875) && ((last_tuned_freq - freq) == 1)) { //start_freq)&&( (last_tuned_freq - freq)==1) )
        if ((g_last_freq_deviation_value & 0x800) == 0) {
            last_tuned_freq = freq;		//save last tuned freqency
            g_last_freq_deviation_value = cur_freq_deviation;
            return 0;
        }

        if (g_last_freq_deviation_value > (0xfff - 150)) { //搜台较少可减少该值，假台较多可增大该值
            last_tuned_freq = freq;		//save last tuned freqency
            g_last_freq_deviation_value = cur_freq_deviation;
            return 0;
        }
    }

    last_tuned_freq = freq;				//save last tuned freqency
    g_last_freq_deviation_value = cur_freq_deviation;

    return 1;
}


/*----------------------------------------------------------------------------*/
/**@brief    关闭 BK1080的电源
   @param    无
   @return   无
   @note     void BK1080_PowerDown(void)
*/
/*----------------------------------------------------------------------------*/
void bk1080_powerdown(void *priv)
{
    u16 temp = 0x4102;
    //temp[0] = 0x02;			  //write 0x0241 into reg2
    //temp[1] = 0x41;
    BEKEN_I2c_Write(0x02, (u8 *)&temp, 2);

    /* dac_channel_off(FM_IIC_CHANNEL, FADE_ON); */
    delay_n10ms(5);				  //delay 50ms
}

/*----------------------------------------------------------------------------*/
/**@brief    FM 模块静音控制
   @param    dir：1-mute 0-unmute
   @return   无
   @note     void BK1080_mute(dir)
*/
/*----------------------------------------------------------------------------*/
void bk1080_mute(void *priv, u8 flag)
{
    u8 TmpData8[2];

    BEKEN_I2c_Read(2, TmpData8, 2);
    if (flag) {
        TmpData8[0] |= 0x40;    //mute
    } else {
        TmpData8[0] &= 0xbf;
    }

    BEKEN_I2c_Write(2, TmpData8, 2);
}

/*----------------------------------------------------------------------------*/
/**@brief   FM模块检测，获取BK1080 模块ID
   @param   无
   @return  检测到BK1080模块返回1，否则返回0
   @note    bool BK1080_Read_ID(void)
*/
/*----------------------------------------------------------------------------*/
bool bk1080_read_id(void *priv)
{
    u16 bk_id;

    if (fm_dev_info == NULL) {
        fm_dev_info = (struct _fm_dev_info *)priv;
    }

    BEKEN_I2c_Read(0x01, (u8 *)&bk_id, 2); 	//read reg3,with 2 bytes

    printf("bk1080_read_id %x", bk_id);
    if (0x8010 == bk_id) {
        return TRUE;
    }
    return FALSE;
}

void bk1080_test(void)
{
    printf("bk1080 test\n");
}

REGISTER_FM(bk1080) = {
    .logo    = "bk1080",
    .init    = bk1080_init,
    .close   = bk1080_powerdown,
    .set_fre = bk1080_set_fre,
    .mute    = bk1080_mute,
    .read_id = bk1080_read_id,
};


#endif
