//需要使用的头文件
#include <stdint.h>
#include <stdbool.h>
#include "nrf.h"
#include "app_error.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "nrf_nvic.h"
#include "ble_comm.h"

// 定义一个timeSlot的变量，该变量用来设置 请求的timeSlot的特性。
static nrf_radio_request_t m_timeslot_request;
// 请求的timeSlot的时间间隙长度
static uint32_t m_slot_length;
// 信号处理函数的返回值。
static nrf_radio_signal_callback_return_param_t signal_callback_return_param;


//请求一个earliest possible 类型的timeSlot，第一次请求timeSLot的时候总是以该类型发起
// timeSlot时间长度为  5000 us
// timeSlot的请求优先级为正常优先级
// 这里设置了在timeSlot运行过程中会打开外部高频晶振时钟源，不过其实不是必须的。
// timeout_us表示请求timeSlot发出后，系统接收这个请求的最大延迟。
// timeSLot的时间长度为5000us
uint32_t request_next_event_earliest(void)
{
    m_slot_length = 5000;
    m_timeslot_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST;
    m_timeslot_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
    m_timeslot_request.params.earliest.priority = NRF_RADIO_PRIORITY_NORMAL;
    m_timeslot_request.params.earliest.length_us = m_slot_length;
    m_timeslot_request.params.earliest.timeout_us = 1000000;
    return sd_radio_request(&m_timeslot_request);
}

// 配置 earliest possible的类型的 timeSlot
void configure_next_event_earliest(void)
{
    m_slot_length = 5000;
    m_timeslot_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST;
    m_timeslot_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
    m_timeslot_request.params.earliest.priority = NRF_RADIO_PRIORITY_NORMAL;
    m_timeslot_request.params.earliest.length_us = m_slot_length;
    m_timeslot_request.params.earliest.timeout_us = 1000000;
}

// 配置normal类型的timeSlot
void configure_next_event_normal(void)
{
    m_slot_length = 5000;
    m_timeslot_request.request_type = NRF_RADIO_REQ_TYPE_NORMAL;
    m_timeslot_request.params.normal.hfclk = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
		m_timeslot_request.params.normal.priority = NRF_RADIO_PRIORITY_HIGH;
// norma类型的timeSlot 的开始时间为距离上一个 timeSlot的开始时间 distance_us后
    m_timeslot_request.params.normal.distance_us = 100000;
    m_timeslot_request.params.normal.length_us = m_slot_length;
}


// timeSlot 会话相关的 一些事件的处理
// 这里的主要处理是，在收到 IDLE事件，即申请的这段会话中没有 timeSlot需要处理后会
// 产生这个事件，那么就可以 通过sd_radio_session_close 函数关闭这个 会话了
// 另外请求的timeSlot可能因为和协议栈运行产生冲突，那么就可以被阻塞或去掉，所以
// NRF_EVT_RADIO_BLOCKED 和 NRF_EVT_RADIO_CANCELED 事件的处理都是重新发起请求
void nrf_evt_signal_handler(uint32_t evt_id)
{
    uint32_t err_code;
    switch (evt_id)
    {
        case NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN:
            BLE_PRINT("NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN\r\n");
            break;
        case NRF_EVT_RADIO_SESSION_IDLE:
            BLE_PRINT("NRF_EVT_RADIO_SESSION_IDLE\r\n");
            sd_radio_session_close();
            break;
        case NRF_EVT_RADIO_SESSION_CLOSED:
            BLE_PRINT("NRF_EVT_RADIO_SESSION_CLOSED\r\n");
            break;
        case NRF_EVT_RADIO_BLOCKED:
            BLE_PRINT("NRF_EVT_RADIO_BLOCKED\r\n");
            //注意这里没有break,所以 这两个事件的处理都是重新发起请求
        case NRF_EVT_RADIO_CANCELED:
            BLE_PRINT("NRF_EVT_RADIO_CANCELED\r\n");
            err_code = request_next_event_earliest();
            APP_ERROR_CHECK(err_code);
            break;
        default:
            break;
    }
}


// timeSlot相关的信号处理函数。
// 当请求的timeSlot 被安排开始后，就会收到 START信号，在这个信号处理里面实现
// 实现翻转 LED灯同时设置 Timer0的超时时间，time0在timeSLot开始后会被自动重置为
// 1MH运行从0 计数，所以这里设置time0的超时时间比 timeSlot的时间长度短1000us，//这样在timeSLot
// 结束之前就可以收到 NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0信号，然后在这信号处
// 理里做一些收尾工作，在这里我们实现的是请求下一个timeSlot

// NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO信号不需要处理，因为我们没有在timeSLot
// 中使用Radio，所以不会有这个信号。

nrf_radio_signal_callback_return_param_t * radio_callback(uint8_t signal_type)
{
    static uint8_t start_count = 0;
    static uint8_t timer0_count = 0;

    switch(signal_type)
    {
        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
            signal_callback_return_param.params.request.p_next = NULL;
						signal_callback_return_param.callback_action    = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;

            NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
            NRF_TIMER0->CC[0] = m_slot_length - 1000;
            NVIC_EnableIRQ(TIMER0_IRQn);

            nrf_gpio_pin_toggle(16);
            //避免打印太快
            if(start_count++ >10 ){            
                BLE_PRINT("NRF_RADIO_CALLBACK_SIGNAL_TYPE_START\r\n");
                start_count = 0;
            }
            break;

        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO:
            signal_callback_return_param.params.request.p_next = NULL;
            signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
            break;

        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0:
            configure_next_event_normal();
            signal_callback_return_param.params.request.p_next = &m_timeslot_request;
            signal_callback_return_param.callback_action    = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
            if(timer0_count++ >10 ){            
                BLE_PRINT("NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0\r\n");
                timer0_count = 0;
            }
            break;
        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED:
            BLE_PRINT("NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED\r\n");
            break;
        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED:
            BLE_PRINT("NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED\r\n");
            configure_next_event_earliest();
            signal_callback_return_param.params.request.p_next = &m_timeslot_request;
						signal_callback_return_param.callback_action    = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
            break;
        default:
            //No implementation needed
            break;
    }
    return (&signal_callback_return_param);
}

// timeSlot初始化函数。
uint32_t timeslot_sd_init(void)
{
    uint32_t err_code;

    err_code = sd_radio_session_open(radio_callback);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    err_code = request_next_event_earliest();
    if (err_code != NRF_SUCCESS)
    {
        (void)sd_radio_session_close();
        return err_code;
    }
    nrf_gpio_cfg_output(16);
    return NRF_SUCCESS;
}

