void transport_control_step(void) { uint64_t next_time; uint64_t time_now = timer_get_timestamp() + global_time; trickle_time_update(time_now); uint32_t error_code = mesh_srv_get_next_processing_time(&next_time); if (error_code != NRF_SUCCESS) { return; } if (next_time < time_now) { async_event_t async_evt; async_evt.callback.generic = trickle_step_callback; async_evt.type = EVENT_TYPE_GENERIC; event_handler_push(&async_evt); } else { if (next_time < global_time + timeslot_get_end_time()) { timer_abort(step_timer_index); step_timer_index = timer_order_cb(next_time - global_time, trickle_step_callback); } } }
int timer_testTearDown(void) { unsigned i; for (i = 0; i < countof(test_timers); ++i) timer_abort(&test_timers[i]); return 0; }
/** * Sleep until any of the signals in \a sigs or \a timeout ticks elapse. * If the timeout elapse a SIG_TIMEOUT is added to the received signal(s). * \return the signal(s) that have awoken the process. * \note Caller must check return value to check which signal awoke the process. */ sigmask_t sig_waitTimeout(sigmask_t sigs, ticks_t timeout) { Timer t; sigmask_t res; cpu_flags_t flags; ASSERT(!sig_check(SIG_TIMEOUT)); ASSERT(!(sigs & SIG_TIMEOUT)); /* IRQ are needed to run timer */ ASSERT(IRQ_ENABLED()); timer_set_event_signal(&t, proc_current(), SIG_TIMEOUT); timer_setDelay(&t, timeout); timer_add(&t); res = sig_wait(SIG_TIMEOUT | sigs); IRQ_SAVE_DISABLE(flags); /* Remove timer if sigs occur before timer signal */ if (!(res & SIG_TIMEOUT) && !sig_check(SIG_TIMEOUT)) timer_abort(&t); IRQ_RESTORE(flags); return res; }
/** * @brief Handle trickle timing events */ static void trickle_step_callback(void) { TICK_PIN(6); /* check if timeslot is about to end */ if (timeslot_get_remaining_time() < RADIO_SAFETY_TIMING_US) return; uint64_t time_now = global_time + timer_get_timestamp(); trickle_time_update(time_now); packet_t packet; bool has_anything_to_send = false; mesh_srv_packet_assemble(&packet, PACKET_DATA_MAX_LEN * PACKET_MAX_CHAIN_LEN, &has_anything_to_send); if (has_anything_to_send) { TICK_PIN(PIN_MESH_TX); radio_disable(); uint8_t packet_and_addr_type = PACKET_TYPE_ADV_NONCONN | ((packet.sender.addr_type == BLE_GAP_ADDR_TYPE_PUBLIC)? 0 : PACKET_ADDR_TYPE_MASK); uint8_t* temp_data_ptr = &packet.data[0]; uint8_t* tx_data_ptr = &tx_data[0]; tx_data_ptr[PACKET_TYPE_POS] = packet_and_addr_type; /* Code structured for packet chaining, although this is yet to be implemented. */ do { uint8_t min_len = ((packet.length > PACKET_DATA_MAX_LEN)? PACKET_DATA_MAX_LEN : packet.length); tx_data_ptr[PACKET_PADDING_POS] = 0; tx_data_ptr[PACKET_LENGTH_POS] = (min_len + PACKET_ADDR_LEN); tx_data_ptr[PACKET_TYPE_POS] = packet_and_addr_type; memcpy(&tx_data_ptr[PACKET_ADDR_POS], packet.sender.addr, PACKET_ADDR_LEN); memcpy(&tx_data_ptr[PACKET_DATA_POS], &temp_data_ptr[0], min_len); radio_event_t tx_event; tx_event.access_address = 0; rbc_mesh_channel_get(&tx_event.channel); tx_event.event_type = RADIO_EVENT_TYPE_TX; tx_event.packet_ptr = &tx_data_ptr[0]; tx_event.start_time = 0; tx_event.callback.tx = NULL; radio_order(&tx_event); TICK_PIN(0); } while (0); order_search(); /* search for the rest of the timeslot */ } /* order next processing */ uint64_t next_time; uint64_t end_time = timeslot_get_end_time(); uint32_t error_code = mesh_srv_get_next_processing_time(&next_time); if (error_code == NRF_SUCCESS && next_time < global_time + end_time) { timer_abort(step_timer_index); step_timer_index = timer_order_cb(next_time - global_time, trickle_step_callback); } }
/** * @brief Radio signal callback handler taking care of all signals in searching * mode */ static nrf_radio_signal_callback_return_param_t* radio_signal_callback(uint8_t sig) { g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE; g_is_in_callback = true; static uint32_t requested_extend_time = 0; static uint32_t successful_extensions = 0; static uint64_t last_rtc_value = 0; //static uint8_t noise_val = 0x5F; SET_PIN(PIN_SYNC_TIME); static uint64_t time_now = 0; switch (sig) { case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START: { NVIC_ClearPendingIRQ(SWI0_IRQn); g_is_in_timeslot = true; event_fifo_flush(); timer_init(); SET_PIN(2); successful_extensions = 0; g_negotiate_timeslot_length = g_timeslot_length; g_timeslot_length = g_next_timeslot_length; g_timeslot_end_timer = timer_order_cb_sync_exec(g_timeslot_length - TIMESLOT_END_SAFETY_MARGIN_US, end_timer_handler); /* attempt to extend our time right away */ timeslot_extend(g_negotiate_timeslot_length); #if USE_SWI_FOR_PROCESSING NVIC_EnableIRQ(SWI0_IRQn); NVIC_SetPriority(SWI0_IRQn, 3); #endif /* sample RTC timer for trickle timing */ uint32_t rtc_time = NRF_RTC0->COUNTER; /*First time the offset should be added*/ if(last_rtc_value == 0) { last_rtc_value = g_start_time_ref; } /* Calculate delta rtc time */ uint64_t delta_rtc_time; if(last_rtc_value > rtc_time) { delta_rtc_time = 0xFFFFFF - last_rtc_value + rtc_time; } else { delta_rtc_time = rtc_time - last_rtc_value; } /* Store last rtc time */ last_rtc_value = rtc_time; /* scale to become us */ time_now += ((delta_rtc_time << 15) / 1000); transport_control_timeslot_begin(time_now); break; } case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO: /* send to radio control module */ TICK_PIN(PIN_RADIO_SIGNAL); radio_event_handler(); break; case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0: /* send to timer control module */ TICK_PIN(PIN_TIMER_SIGNAL); timer_event_handler(); break; case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED: g_timeslot_length += requested_extend_time; requested_extend_time = 0; ++successful_extensions; g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE; timer_abort(g_timeslot_end_timer); g_timeslot_end_timer = timer_order_cb_sync_exec(g_timeslot_length - TIMESLOT_END_SAFETY_MARGIN_US, end_timer_handler); TICK_PIN(1); if (g_timeslot_length + g_negotiate_timeslot_length < TIMESLOT_MAX_LENGTH) { timeslot_extend(g_negotiate_timeslot_length); } else { /* done extending, check for new trickle event */ transport_control_step(); } break; case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED: g_negotiate_timeslot_length >>= 2; TICK_PIN(1); if (g_negotiate_timeslot_length > 1000) { timeslot_extend(g_negotiate_timeslot_length); } else { /* done extending, check for new trickle event */ transport_control_step(); } break; default: APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE); } g_is_in_callback = false; if (g_ret_param.callback_action == NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND) { requested_extend_time = g_ret_param.params.extend.length_us; } else if (g_ret_param.callback_action == NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END) { CLEAR_PIN(2); g_is_in_timeslot = false; event_fifo_flush(); } else { requested_extend_time = 0; } CLEAR_PIN(PIN_SYNC_TIME); return &g_ret_param; }
/** * @brief Radio signal callback handler taking care of all signals in searching * mode */ static nrf_radio_signal_callback_return_param_t* radio_signal_callback(uint8_t sig) { static uint32_t requested_extend_time = 0; static uint32_t successful_extensions = 0; static uint32_t timeslot_count = 0; if (sig == NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) { g_timeslot_forced_command = TS_FORCED_COMMAND_NONE; } else /* on forced command */ { switch (g_timeslot_forced_command) { case TS_FORCED_COMMAND_STOP: g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_END; g_is_in_timeslot = false; g_end_timer_triggered = false; CLEAR_PIN(PIN_IN_TS); event_handler_on_ts_end(); timeslot_count = 0; return &g_ret_param; case TS_FORCED_COMMAND_RESTART: timeslot_order_earliest(TIMESLOT_SLOT_LENGTH, true); g_is_in_timeslot = false; g_end_timer_triggered = false; CLEAR_PIN(PIN_IN_TS); event_handler_on_ts_end(); radio_disable(); return &g_ret_param; default: break; } } g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE; g_is_in_callback = true; SET_PIN(PIN_IN_CB); switch (sig) { case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START: { SET_PIN(PIN_IN_TS); g_is_in_timeslot = true; g_end_timer_triggered = false; successful_extensions = 0; if (timeslot_count > 0) { global_time_update(); } mesh_packet_on_ts_begin(); event_handler_on_ts_begin(); timer_on_ts_begin(); tc_on_ts_begin(); g_negotiate_timeslot_length = TIMESLOT_SLOT_EXTEND_LENGTH; g_timeslot_length = g_next_timeslot_length; timer_order_cb_sync_exec(TIMER_INDEX_TS_END, g_timeslot_length - end_timer_margin(), end_timer_handler); /* attempt to extend our time right away */ timeslot_extend(g_negotiate_timeslot_length); /* increase timeslot-count, but skip =0 on rollover */ if (!++timeslot_count) { timeslot_count++; } break; } case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO: /* send to radio control module */ SET_PIN(PIN_RADIO_SIGNAL); radio_event_handler(); CLEAR_PIN(PIN_RADIO_SIGNAL); break; case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0: /* send to timer control module */ SET_PIN(PIN_TIMER_SIGNAL); timer_event_handler(); CLEAR_PIN(PIN_TIMER_SIGNAL); break; case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED: g_timeslot_length += requested_extend_time; requested_extend_time = 0; ++successful_extensions; timer_abort(TIMER_INDEX_TS_END); timer_order_cb_sync_exec(TIMER_INDEX_TS_END, g_timeslot_length - end_timer_margin(), end_timer_handler); g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE; TICK_PIN(PIN_EXTENSION_OK); if (g_timeslot_length + g_negotiate_timeslot_length < TIMESLOT_MAX_LENGTH) { timeslot_extend(g_negotiate_timeslot_length); } else { /* done extending, check for new trickle event */ vh_on_timeslot_begin(); } break; case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED: g_negotiate_timeslot_length >>= 1; TICK_PIN(PIN_EXTENSION_FAIL); if (g_negotiate_timeslot_length > 1000) { timeslot_extend(g_negotiate_timeslot_length); } else { /* done extending, check for new trickle event */ vh_on_timeslot_begin(); } break; default: APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE); } if (g_end_timer_triggered) { timeslot_order_earliest(TIMESLOT_SLOT_LENGTH, true); g_is_in_timeslot = false; g_end_timer_triggered = false; CLEAR_PIN(PIN_IN_TS); event_handler_on_ts_end(); radio_disable(); timer_on_ts_end(); } else if (g_ret_param.callback_action == NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND) { requested_extend_time = g_ret_param.params.extend.length_us; } else { requested_extend_time = 0; } g_is_in_callback = false; CLEAR_PIN(PIN_IN_CB); return &g_ret_param; }