//需要使用的头文件 #include #include #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; }