/** * @brief Function for turning on RX carrier. */ void radio_rx_carrier(uint8_t mode, uint8_t channel) { radio_disable(); NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk; NRF_RADIO->FREQUENCY = channel; NRF_RADIO->TASKS_RXEN = 1; }
/* * Start modulated TX carrier. This is done by repeatedly sending a packet with random address and * random payload. */ static void radio_modulated_tx_carrier(uint8_t txpower, uint8_t mode, uint8_t channel) { radio_disable(); generate_modulated_rf_packet(); NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_DISABLED_TXEN_Msk;; NRF_RADIO->TXPOWER = (txpower << RADIO_TXPOWER_TXPOWER_Pos); NRF_RADIO->MODE = (mode << RADIO_MODE_MODE_Pos); NRF_RADIO->FREQUENCY = channel; NRF_RADIO->TASKS_TXEN = 1; }
/** * @brief Function for turning on the TX carrier test mode. */ void radio_tx_carrier(uint8_t txpower, uint8_t mode, uint8_t channel) { radio_disable(); NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk; NRF_RADIO->TXPOWER = (txpower << RADIO_TXPOWER_TXPOWER_Pos); NRF_RADIO->MODE = (mode << RADIO_MODE_MODE_Pos); NRF_RADIO->FREQUENCY = channel; NRF_RADIO->TEST = (RADIO_TEST_CONST_CARRIER_Enabled << RADIO_TEST_CONST_CARRIER_Pos) \ | (RADIO_TEST_PLL_LOCK_Enabled << RADIO_TEST_PLL_LOCK_Pos); NRF_RADIO->TASKS_TXEN = 1; }
void ll_scan_timeout_cb (void) { switch (m_scanner.state) { case SCANNER_STATE_RECEIVE_SCAN_RSP: m_state_receive_scan_rsp_exit (); radio_disable (); m_state_receive_adv_entry (); break; default: break; } }
u8 mode_select_display_func(ui_mode_t mode, ui_display_event_t event) { if (event == CONFIG_SHORT_PRESS) { u16 m = 1; u8 i; for(i=0; i<3-mode_select_digit; i++) { m *= 10; } u8 p = (mode_select_current/m)%10; mode_select_current -= p*m; p = (p+1)%10; mode_select_current += p*m; } else if (event == CONFIG_LONG_PRESS) { ++mode_select_digit; if (mode_select_digit >= 4) { /* Save the new config word */ save_persist_data_16(PDATA_CONFIG_WORD_1L + mode_select_word*2, ~mode_select_current); ++mode_select_word; do_config_word(mode_select_word); } if (mode_select_word >= NUM_CONFIG_WORDS) { /* wait for button release */ while (!(LED_PIN & (1<<LED_BIT))); radio_disable(); /* reset */ void (*rstvec)() = (void (*)())0; (*rstvec)(); } } output_number(MODE_MODE_SELECT + mode_select_word + 1, mode_select_current, CENTER_NONE, DFLAGS_FLASH_PLACE_0<<mode_select_digit); return 1; }
void ll_scan_rx_cb (bool crc_valid) { /* Received invalid packet */ if (!crc_valid) { switch(m_scanner.state) { case SCANNER_STATE_RECEIVE_ADV: m_packets_invalid++; m_state_receive_adv_exit (); radio_disable (); m_state_receive_adv_entry (); break; case SCANNER_STATE_RECEIVE_SCAN_RSP: m_packets_invalid++; m_state_receive_scan_rsp_exit (); radio_disable (); m_state_receive_adv_entry (); break; default: break; } } switch (m_scanner.state) { /* Packet received */ case SCANNER_STATE_RECEIVE_ADV: m_packets_valid++; switch (m_rx_buf[0] & 0x0F) { /* If active scanning is enabled, these packets should be reponded to with * a SCAN_REQ, and we should wait for a SCAN_RSP. */ case PACKET_TYPE_ADV_IND: m_state_receive_adv_exit (); m_adv_report_generate (m_rx_buf); /* If we're doing active scanning, prepare to send SCAN REQ, otherwise * loop back around to receive a new advertisement. */ if (m_scanner.params.scan_type == BTLE_SCAN_TYPE_ACTIVE) { m_state_send_scan_req_entry (); } else { m_state_receive_adv_entry (); } break; case PACKET_TYPE_ADV_SCAN_IND: m_state_receive_adv_exit (); m_adv_report_generate (m_rx_buf); /* If we're doing active scanning, prepare to send SCAN REQ, otherwise * loop back around to receive a new advertisement. */ if (m_scanner.params.scan_type == BTLE_SCAN_TYPE_ACTIVE) { m_state_send_scan_req_entry (); } else { m_state_receive_adv_entry (); } break; /* These packets do not require response. */ case PACKET_TYPE_ADV_DIRECT_IND: m_state_receive_adv_exit (); radio_disable(); m_adv_report_generate (m_rx_buf); m_state_receive_adv_entry (); break; case PACKET_TYPE_ADV_NONCONN_IND: m_state_receive_adv_exit (); radio_disable(); m_adv_report_generate (m_rx_buf); m_state_receive_adv_entry (); break; /* This should not have happened */ default: m_state_receive_adv_exit (); radio_disable(); m_state_receive_adv_entry(); } break; case SCANNER_STATE_RECEIVE_SCAN_RSP: m_packets_valid++; m_state_receive_scan_rsp_exit (); m_adv_report_generate (m_rx_buf); m_state_receive_adv_entry (); break; default: break; } }
/** * @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 Function for stopping Timer 0. */ void radio_sweep_end(void) { NRF_TIMER0->TASKS_STOP = 1; radio_disable(); }
/** * @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; }