// 同步模块，配置载波频率(发射和接受同频，半双工)
// 杭州秒寻科技有限公司
// 周涛
// 2023-11-18
// 注意：这部分代码为厂家提供，没做修改，仅需要修改三个宏定义
// #define SYNC_FREQ_DEVIATION 10    // 载波偏移
// #define SYNC_FREQ_SYMBOL_RATE 9.6 // 符号率
// #define SYNC_FREQ_XTAL_PPM 5      // 晶振抖动

#include "includes.h"

static uint8 gFreq_byCarrierid = 0; // 载波频率id

static FREQ_CFG g_freq_cfg = {0};
unsigned char g_div_value = 0;
unsigned char g_iqdiv_value = 0;

// 配置载波频率(中心频率)
// dwFreq:频率，单位kHz
void sync_freq_config_center_freq(uint32 dwFreq)
{
    FREQ_CFG stFreqConfig = {0};
    stFreqConfig.FREQUENCRY = dwFreq * 1000; // 单位hz
    stFreqConfig.DEVIATION = SYNC_FREQ_DEVIATION;
    stFreqConfig.SYMBOL_RATE = SYNC_FREQ_SYMBOL_RATE;
    stFreqConfig.XTAL_PPM = SYNC_FREQ_XTAL_PPM;

    sync_freq_config(&stFreqConfig);
}

// 配置载波频率
// freq:载波频率参数
// 配置完成后，芯片在ready状态，配置完频率，要复位设备以便生效
void sync_freq_config(FREQ_CFG *freq)
{
    double tmp;
    unsigned int freq_temp;
    unsigned char afc_reg;

    signed int n_value;
    signed int harm_value;
    signed int delta_left;
    signed int delta_right;

    unsigned int freq_offset;
    unsigned int freq_if;

    unsigned char pll_rx_n;
    unsigned int pll_rx_k;
    unsigned char pll_tx_n;
    unsigned int pll_tx_k;
    unsigned char pll_ircal_n;
    unsigned int pll_ircal_k;
    unsigned char tone_div_sel;
    unsigned int dev_value;

    // 切换芯片状态
    sync_switch_work_status(SYNC_STATUS_GO_SLEEP, SYNC_STATUS_SLEEP);
    sync_switch_work_status(SYNC_STATUS_GO_READY, SYNC_STATUS_READY);

    if (((*freq).FREQUENCRY < 112500000) || ((*freq).FREQUENCRY > 960000000)) // just return, when out of range
        return;

    // get freq_offset，晶振引起的频偏
    tmp = (((double)(*freq).FREQUENCRY) / 1000000.0) * ((double)((*freq).XTAL_PPM + (*freq).XTAL_PPM));
    freq_offset = (unsigned int)tmp;

    // get baseband，载波基带频率
    tmp = (double)(*freq).DEVIATION + ((double)(*freq).SYMBOL_RATE / 2.0);
    freq_temp = (unsigned int)tmp; // baseband

    // get freq_if
    sync_select_reg_page(1);
    sync_read_reg(CMT2310A_RX_AFC_REG_00, &afc_reg);
    if ((afc_reg & 0x01) == 0x01) // afc on
        freq_temp += (freq_offset >> 1);
    else
        freq_temp += freq_offset;
    freq_temp <<= 1; // double band
    if (freq_temp <= 125000)
        freq_if = 125000;
    else if (freq_temp <= 250000)
        freq_if = 250000;
    else if (freq_temp <= 500000)
        freq_if = 500000;
    else
        freq_if = 800000;

    // calc. freq_lo, & get div & get iq_div
    freq_temp = (*freq).FREQUENCRY + freq_if; // freq_lo
    sync_freq_set_div_value(freq_temp);

    // calc. deviation
    tmp = (double)(*freq).DEVIATION * g_div_value * 1.333 * 1048576.0 / 32000000.0;
    dev_value = (unsigned int)tmp;

    // calc. RX N_K value
    freq_temp *= g_div_value;
    pll_rx_n = freq_temp / 32000000;
    tmp = ((double)freq_temp / 32000000.0 - (double)pll_rx_n);
    tmp *= 1048576.0;
    pll_rx_k = (unsigned int)tmp;

    // calc. TX N_K value
    freq_temp = (*freq).FREQUENCRY;
    freq_temp *= g_div_value;
    pll_tx_n = freq_temp / 32000000;
    tmp = ((double)freq_temp / 32000000.0 - (double)pll_tx_n) * 1048576.0;
    pll_tx_k = (unsigned int)tmp;

    // calc. IR cal N_K value
    if ((*freq).FREQUENCRY > 500000000)
    {
        tone_div_sel = 0;
        freq_offset = 32000000;
    }
    else
    {
        tone_div_sel = 1;
        freq_offset = 16000000;
    }
    tmp = ((double)(*freq).FREQUENCRY) / ((double)freq_offset);
    n_value = (signed int)((tmp - 1) / 2.0);
    delta_left = (signed int)(tmp - (double)(2 * n_value + 1));
    delta_right = (signed int)((double)(2 * n_value + 3) - tmp);

    if (delta_left <= delta_right)
        harm_value = 2 * n_value + 1;
    else
        harm_value = 2 * n_value + 3;
    freq_temp = (freq_offset * harm_value - freq_if); // freq_lo_ircal

    if (freq_temp < 112500000)
        harm_value += 2;
    else if (freq_temp > 960000000)
        harm_value -= 2;
    else
        harm_value = harm_value;

    freq_temp = freq_offset * harm_value;
    freq_temp -= freq_if;
    freq_temp *= g_div_value;
    pll_ircal_n = freq_temp / 32000000;
    tmp = ((double)freq_temp / 32000000.0 - (double)pll_ircal_n) * 1048576.0;
    pll_ircal_k = (unsigned int)tmp;

    // set frequencry's register
    sync_rewrite_reg(CMT2310A_RX_FREQ_REG_00, ((tone_div_sel << 3) | (g_iqdiv_value & 0x07)), 0x3F);

    if ((*freq).SYMBOL_RATE <= 125000)
    {
        sync_wirte_reg(CMT2310A_TX_DR_REG_03, 32);
        sync_wirte_reg(CMT2310A_TX_DR_REG_04, ((0 << 6) + 8));
        sync_rewrite_reg(CMT2310A_RX_DR_REG_07, (1 << 6), (1 << 6));
        sync_rewrite_reg(CMT2310A_CMT_REG_06, (0 << 6), (1 << 6));
    }
    else if ((*freq).SYMBOL_RATE <= 250000)
    {
        sync_wirte_reg(CMT2310A_TX_DR_REG_03, 64);
        sync_wirte_reg(CMT2310A_TX_DR_REG_04, ((1 << 6) + 16));
        sync_rewrite_reg(CMT2310A_RX_DR_REG_07, (1 << 6), (1 << 6));
        sync_rewrite_reg(CMT2310A_CMT_REG_06, (1 << 6), (1 << 6));
    }
    else if ((*freq).SYMBOL_RATE <= 375000)
    {
        sync_wirte_reg(CMT2310A_TX_DR_REG_03, 128);
        sync_wirte_reg(CMT2310A_TX_DR_REG_04, ((2 << 6) + 32));
        sync_rewrite_reg(CMT2310A_RX_DR_REG_07, (1 << 6), (1 << 6));
        sync_rewrite_reg(CMT2310A_CMT_REG_06, (1 << 6), (1 << 6));
    }
    else
    {
        sync_wirte_reg(CMT2310A_TX_DR_REG_03, 128);
        sync_wirte_reg(CMT2310A_TX_DR_REG_04, ((3 << 6) + 32));
        sync_rewrite_reg(CMT2310A_RX_DR_REG_07, (1 << 6), (1 << 6));
        sync_rewrite_reg(CMT2310A_CMT_REG_06, (1 << 6), (1 << 6));
    }
    sync_wirte_reg(CMT2310A_TX_FREQ_REG_00, pll_tx_n);
    sync_wirte_reg(CMT2310A_TX_FREQ_REG_01, (unsigned char)pll_tx_k);
    sync_wirte_reg(CMT2310A_TX_FREQ_REG_02, (unsigned char)(pll_tx_k >> 8));
    sync_rewrite_reg(CMT2310A_TX_FREQ_REG_03, (unsigned char)((pll_tx_k >> 16) & 0x0F), 0x0F);

    sync_wirte_reg(CMT2310A_RX_FREQ_REG_01, pll_rx_n);
    sync_wirte_reg(CMT2310A_RX_FREQ_REG_02, (unsigned char)pll_rx_k);
    sync_wirte_reg(CMT2310A_RX_FREQ_REG_03, (unsigned char)(pll_rx_k >> 8));
    sync_rewrite_reg(CMT2310A_RX_FREQ_REG_04, (unsigned char)((pll_rx_k >> 16) & 0x0F), 0x0F);

    sync_wirte_reg(CMT2310A_RX_IRF_REG_00, pll_ircal_n);
    sync_wirte_reg(CMT2310A_RX_IRF_REG_01, (unsigned char)pll_ircal_k);
    sync_wirte_reg(CMT2310A_RX_IRF_REG_02, (unsigned char)(pll_ircal_k >> 8));
    sync_rewrite_reg(CMT2310A_RX_IRF_REG_03, (unsigned char)((pll_ircal_k >> 16) & 0x0F), 0x0F);

    sync_wirte_reg(CMT2310A_TX_DEV_REG_00, (unsigned char)dev_value);
    sync_wirte_reg(CMT2310A_TX_DEV_REG_01, (unsigned char)(dev_value >> 8));
    sync_rewrite_reg(CMT2310A_TX_DEV_REG_02, (unsigned char)((dev_value >> 16) & 0x0F), 0x0F);

    sync_select_reg_page(0);
}

/******************************
**Name:  sync_freq_set_div_value
**Func:  get div_code & iqdiv_code for calcuate
**Input: freq: traget tx frequencry, unit=Hz
*Output: None
**note:  Should be make sure is not out of frequencry range.
********************************/
void sync_freq_set_div_value(unsigned int freq)
{

    if (freq < 135000000) // 112.5 - 135 MHz
    {
        g_div_value = 24;
        g_iqdiv_value = 6;
    }
    else if (freq < 169000000) // 135 - 169 MHz
    {
        g_div_value = 20;
        g_iqdiv_value = 5;
    }
    else if (freq < 225000000) // 169 - 225 MHz
    {
        g_div_value = 16;
        g_iqdiv_value = 4;
    }
    else if (freq < 320000000) // 225 - 320 MHz
    {
        g_div_value = 12;
        g_iqdiv_value = 3;
    }
    else if (freq < 500000000) // 320 - 500 MHz (note: 320-337.5 is not recommended!)
    {
        g_div_value = 8;
        g_iqdiv_value = 2;
    }
    else if (freq < 640000000) // 500 - 640 MHz
    {
        g_div_value = 6;
        g_iqdiv_value = 1;
    }
    else // 640 - 960 MHz
    {
        g_div_value = 4;
        g_iqdiv_value = 0;
    }
}

/*
 * 计划选用的频段为409-410MHz，起始频点为：409.750，截止频率为：409.9875
 * 鉴于2310芯片频率最小间隔只能到K，所有只能使用奇数号频点，分别如下
 * 1：409.750，3：409.775，5：409.800，7：409.825，9：409.850，
 * 11：409.875，13：409.900，15：409.925，17：409.950，19：409.975
 */

// 配置载波中心频率
// 中心频率 = 基本频率（RFPDK工具导出的频率）+ 频点ID * 频点间隔
// byCarrierId:频点ID，0-250
// byFreqSpace:频点间隔，单位khz，，最小值50K，最大250，默认间隔选250kHz
// 返回值，0：失败，1：成功
uint8 sync_freq_config_carrier_freq(uint8 byCarrierId, uint8 byFreqSpace)
{
    uint8 byFlag = 0;

    // 默认参数
    if (byCarrierId == 0xFF)
    {
        byCarrierId = 0;
    }

    // 默认参数
    if (byFreqSpace == 0xFF)
    {
        byFreqSpace = 250;
    }

    // go sleep
    byFlag = sync_switch_work_status(SYNC_STATUS_GO_SLEEP, SYNC_STATUS_SLEEP);
    if (!byFlag)
    {
        return 0;
    }

    // 配置频率
    sync_freq_config_freq_space(byFreqSpace); // 配置频点间隔
    driver_delay_100us();                     // 延时100us
    sync_freq_config_channel_id(byCarrierId); // 配置频点号

    // go ready
    byFlag = sync_switch_work_status(SYNC_STATUS_GO_READY, SYNC_STATUS_READY);
    if (!byFlag)
    {
        return 0;
    }

    // go tfs
    byFlag = sync_switch_work_status(SYNC_STATUS_GO_TFS, SYNC_STATUS_TFS);
    if (!byFlag)
    {
        return 0;
    }

    // 保存载波频率
    sync_rxtx_set_payload(byCarrierId);

    return 1;
}

// 配置频点间隔，单位Kh
// byFreqSpace:频点间隔，单位khz，最大255，默认间隔选250kHz
void sync_freq_config_freq_space(uint8 byFreqSpace)
{
    sync_wirte_reg(0x0C, byFreqSpace); // 频点间隔
}

// 配置频点ID
// byChannelId:频点ID号，0至255有效
void sync_freq_config_channel_id(uint8 byCarrierId)
{
    sync_wirte_reg(0x03, byCarrierId); // 频点号
}

// 查询载波频率
uint8 sync_freq_get_carrier_id()
{
    return gFreq_byCarrierid;
}