// 外部中断模块
// 杭州秒寻科技有限公司
// 周涛
// 2023-11-14

#include "includes.h"
#include "time.h"

static uint8 gExti_byRxSyncLedFlag = 1;   // 接收同步点灯标识符
static uint8 gExti_byTxSyncFlag = 0;      // 发射同步中继信号标识符(本设备是否需要中继同步信号，1：不需要，2：需要)
static uint8 gExti_byDelayTimes = 0;      // 音频信号延迟次数
static uint8 gExti_byRxSyncWordIndex = 0; // 接收同步字

// 外部中断模块初始化
void exti_init()
{
    // 延时1秒，等到同步模块稳定
    driver_delay_1s();

    exti_init_rx_sync(); // 初始化接收完成同步信号的外部中断线
    exti_init_tx_sync(); // 初始化发射完成同步信号的外部中断线
}

/*****************************************下面是处理同步信号接收与发送**************************************************/
// 初始化同步模块接收完成外部中断线(SYNC_PASS)
void exti_init_rx_sync()
{
    GPIO_InitTypeDef stGpio = {0};
    EXTI_InitTypeDef stExti = {0};
    NVIC_InitTypeDef stNvic = {0};

    // 初始化GPIO管脚
    RCC_AHB1PeriphClockCmd(EXTI_SYNCRX_GPIO_CLK, ENABLE);
    stGpio.GPIO_Mode = GPIO_Mode_IN; // 输入模式
    stGpio.GPIO_PuPd = GPIO_PuPd_DOWN;
    stGpio.GPIO_Speed = GPIO_Speed_50MHz;
    stGpio.GPIO_Pin = EXTI_SYNCRX_GPIO_PIN;
    GPIO_Init(EXTI_SYNCRX_GPIO_PORT, &stGpio);

    // 使能系统配置时钟(SYSCOFG)，以便配置外部中断
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    // 配置外部中断参数
    SYSCFG_EXTILineConfig(EXTI_SYNCRX_GPIO_SOURCE_PORT, EXTI_SYNCRX_GPIO_SOURCE_PIN); // 配置GPIO管脚与exti线间的映射关系
    stExti.EXTI_Line = EXTI_SYNCRX_GPIO_SOURCE_LINE;
    stExti.EXTI_Mode = EXTI_Mode_Interrupt;
    stExti.EXTI_Trigger = EXTI_Trigger_Rising;
    stExti.EXTI_LineCmd = ENABLE;
    EXTI_Init(&stExti);

    // 配置中断
    stNvic.NVIC_IRQChannel = EXTI_SYNCRX_GPIO_IRQ_CHAN;
    stNvic.NVIC_IRQChannelPreemptionPriority = 0;
    stNvic.NVIC_IRQChannelSubPriority = 0;
    stNvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&stNvic);

    EXTI_ClearITPendingBit(EXTI_SYNCRX_GPIO_SOURCE_LINE); // 清除中断标识符
    sync_rxtx_update_rx_cplt_flag(1);                     // 更新同步信号接收完成标识，以便做后向处理
}

// EXTI0中断服务程序(同步信号的中断服务程序)
// 收到同步中断信号后，发送同步中继信号(需要的话)和定位信号
void EXTI0_IRQHandler(void)
{
    uint8 byGpioLevel = 0;
    uint16 wCounter = 500;

    if (EXTI_GetITStatus(EXTI_SYNCRX_GPIO_SOURCE_LINE) != RESET)
    {
        // 中断脉宽有效
        byGpioLevel = GPIO_ReadInputDataBit(EXTI_SYNCRX_GPIO_PORT, EXTI_SYNCRX_GPIO_PIN);
        if (byGpioLevel)
        {
            // 需要转发同步信号，同时不是最后一级(最后一级不再转发同步信号)
            if (gExti_byTxSyncFlag == 2 && gExti_byDelayTimes != 0)
            {
                // 转发同步信号
                exti_forward_sync_signal();
            }

            // 启动定时器延时N个周期再发送音频信号
            driver_timer_start_timer_delay_send_audio_signal(gExti_byTxSyncFlag, gExti_byDelayTimes, (void *)ssm_start_send_audito_signal);

            // 点灯
            driver_led_switch(gExti_byRxSyncLedFlag);
            gExti_byRxSyncLedFlag = ~gExti_byRxSyncLedFlag;
            gExti_byRxSyncLedFlag &= 0x01;
        }

        EXTI_ClearITPendingBit(EXTI_SYNCRX_GPIO_SOURCE_LINE); // 清除外部中断标识符
        sync_rxtx_update_rx_cplt_flag(1);                     // 更新同步信号接收完成标识，以便做后向处理（清缓存、清中断，状态切换）
    }
}

/*********************************上面是接收同步信号处理逻辑******************************************** */
/**************************************************************************************************** */
/*********************************下面是发射同步信号处理逻辑******************************************** */

// 初始化同步发射模块发射完成中断管脚((TX_DONE))
void exti_init_tx_sync()
{
    GPIO_InitTypeDef stGpio = {0};
    EXTI_InitTypeDef stExti = {0};
    NVIC_InitTypeDef stNvic = {0};

    // 初始化GPIO管脚
    RCC_AHB1PeriphClockCmd(EXTI_SYNCTX_GPIO_CLK, ENABLE);
    stGpio.GPIO_Mode = GPIO_Mode_IN;   // 管脚模式，输入模式
    stGpio.GPIO_PuPd = GPIO_PuPd_DOWN; // 下拉，平时保持低电平
    stGpio.GPIO_Speed = GPIO_Speed_50MHz;
    stGpio.GPIO_Pin = EXTI_SYNCTX_GPIO_PIN;
    GPIO_Init(EXTI_SYNCTX_GPIO_PORT, &stGpio);

    // 配置GPIO管脚与exti线间的映射关系
    SYSCFG_EXTILineConfig(EXTI_SYNCTX_GPIO_SOURCE_PORT, EXTI_SYNCTX_GPIO_SOURCE_PIN);

    // 配置外部中断参数
    stExti.EXTI_Line = EXTI_SYNCTX_GPIO_SOURCE_LINE;
    stExti.EXTI_Mode = EXTI_Mode_Interrupt;
    stExti.EXTI_Trigger = EXTI_Trigger_Rising;
    stExti.EXTI_LineCmd = DISABLE;
    EXTI_Init(&stExti);

    // 配置中断
    stNvic.NVIC_IRQChannel = EXTI_SYNCTX_GPIO_IRQ_CHAN;
    stNvic.NVIC_IRQChannelPreemptionPriority = 0;
    stNvic.NVIC_IRQChannelSubPriority = 1;
    stNvic.NVIC_IRQChannelCmd = DISABLE;
    NVIC_Init(&stNvic);
}

// EXTI3中断服务程序(转发同步信号完成的中断服务程序，负责转发完成的后续处理)
void EXTI3_IRQHandler(void)
{
    uint8 byLevel = 0;

    if (EXTI_GetITStatus(EXTI_SYNCTX_GPIO_SOURCE_LINE) != RESET)
    {
        // 中断脉宽有效
        byLevel = GPIO_ReadInputDataBit(EXTI_SYNCTX_GPIO_PORT, EXTI_SYNCTX_GPIO_PIN);
        if (byLevel) // 中断脉宽有效
        {
            // 信号发送已完成，更新转发完成标识符为“已完成”
            synctx_rxtx_update_tx_cplt_flag(2);

            // 关闭同步信号转发中断
            exti_disable_sync_signal_forward_int();
        }

        // 清除外部中断标识符
        EXTI_ClearITPendingBit(EXTI_SYNCTX_GPIO_SOURCE_LINE);
    }
}

// 使能同步信号转发中断
void exti_enable_sync_signal_forward_int()
{
    EXTI_InitTypeDef stExti = {0};
    NVIC_InitTypeDef stNvic = {0};

    // 配置外部中断参数
    SYSCFG_EXTILineConfig(EXTI_SYNCTX_GPIO_SOURCE_PORT, EXTI_SYNCTX_GPIO_SOURCE_PIN); // 配置GPIO管脚与exti线间的映射关系
    stExti.EXTI_Line = EXTI_SYNCTX_GPIO_SOURCE_LINE;
    stExti.EXTI_Mode = EXTI_Mode_Interrupt;
    stExti.EXTI_Trigger = EXTI_Trigger_Rising;
    stExti.EXTI_LineCmd = ENABLE;
    EXTI_Init(&stExti);

    stNvic.NVIC_IRQChannel = EXTI_SYNCTX_GPIO_IRQ_CHAN;
    stNvic.NVIC_IRQChannelPreemptionPriority = 0;
    stNvic.NVIC_IRQChannelSubPriority = 1;
    stNvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&stNvic);

    return;
}

// 关闭同步信号转发中断
void exti_disable_sync_signal_forward_int()
{
    EXTI_InitTypeDef stExti = {0};
    NVIC_InitTypeDef stNvic = {0};

    // 配置外部中断参数
    stExti.EXTI_Line = EXTI_SYNCTX_GPIO_SOURCE_LINE;
    stExti.EXTI_Mode = EXTI_Mode_Interrupt;
    stExti.EXTI_Trigger = EXTI_Trigger_Rising;
    stExti.EXTI_LineCmd = DISABLE;
    EXTI_Init(&stExti);

    stNvic.NVIC_IRQChannel = EXTI_SYNCTX_GPIO_IRQ_CHAN;
    stNvic.NVIC_IRQChannelPreemptionPriority = 0;
    stNvic.NVIC_IRQChannelSubPriority = 1;
    stNvic.NVIC_IRQChannelCmd = DISABLE;
    NVIC_Init(&stNvic);

    return;
}

// 转发同步信号
void exti_forward_sync_signal()
{
    uint8 byTxCpltFlag = 0;

    // 查询发送标识符，0：空闲可发送；1：发送进行中；2：发送已完成
    byTxCpltFlag = synctx_rxtx_query_tx_cplt_flag();

    // 模块空闲，可发送
    if (!byTxCpltFlag)
    {
        //// 发送同步信号
        synctx_wirte_reg(0x01, SYNC_STATUS_GO_TX); // 切换直GO_TX状态
        synctx_rxtx_update_tx_cplt_flag(1);        // 修改发送标识符，发送进行中
        exti_enable_sync_signal_forward_int();     // 使能同步信号发送中断
    }

    return;
}

// 保存同步信号转发标识符
// bySyncTxFlag:同步信号转发标识符
void exti_save_sync_signal_forward_flag(uint8 bySyncTxFlag)
{
    gExti_byTxSyncFlag = bySyncTxFlag;
    return;
}

// 根据接收同步字，计算音频信号延迟次数
// byRxSyncWordIndex，接收同步字编号（共有4个同步字，编号从1到4）
void exti_cal_audio_signal_send_delay_times(uint8 byRxSyncWordIndex)
{
    // 接收同步字非法
    if (byRxSyncWordIndex <= 0 || byRxSyncWordIndex > SYS_SYNC_WORD_MAX_ID)
    {
        gExti_byDelayTimes = 0; // 不延迟
    }
    else
    {
        // 延迟次数（最大延迟5次）
        gExti_byDelayTimes = SYS_SYNC_WORD_MAX_ID - byRxSyncWordIndex;
    }

    return;
}