/**@brief Process ANT message on ANT scanner * * @param[in] p_ant_event ANT message content. */ void continuous_scan_event_handler(ant_evt_t * p_ant_evt) { uint32_t err_code; uint8_t message_rssi; uint16_t message_device_number; ANT_MESSAGE * p_ant_message = (ANT_MESSAGE *) p_ant_evt->msg.evt_buffer; switch (p_ant_evt->event) { case EVENT_RX: if (p_ant_message->ANT_MESSAGE_aucPayload[0] == DEVICE_STATUS_PAGE) { LEDS_INVERT(BSP_LED_1_MASK); if (p_ant_message->ANT_MESSAGE_stExtMesgBF.bANTDeviceID && p_ant_message->ANT_MESSAGE_stExtMesgBF.bANTRssi) { message_device_number = (uint16_t)(p_ant_message->ANT_MESSAGE_aucExtData[0] | ((uint16_t)p_ant_message->ANT_MESSAGE_aucExtData[1] << 8)); message_rssi = p_ant_message->ANT_MESSAGE_aucExtData[5]; node_to_list_add(message_device_number, message_rssi); } } break; case EVENT_TRANSFER_TX_COMPLETED: LEDS_OFF(BSP_LED_0_MASK | BSP_LED_1_MASK); err_code = sd_ant_channel_close(ANT_SCAN_CHANNEL_NUMBER); APP_ERROR_CHECK(err_code); break; case EVENT_TRANSFER_TX_FAILED: if (m_retries > 0) { command_send(); m_retries--; } else { LEDS_OFF(BSP_LED_0_MASK | BSP_LED_1_MASK); err_code = sd_ant_channel_close(ANT_SCAN_CHANNEL_NUMBER); APP_ERROR_CHECK(err_code); } break; default: break; // No implementation needed } }
/**@brief Application's Stack BLE event handler. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code = NRF_SUCCESS; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: nrf_gpio_pin_set(CONNECTED_LED_PIN_NO); nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO); m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; break; case BLE_GAP_EVT_DISCONNECTED: nrf_gpio_pin_clear(CONNECTED_LED_PIN_NO); m_conn_handle = BLE_CONN_HANDLE_INVALID; // Need to close the ANT channel to make it safe to write bonding information to flash err_code = sd_ant_channel_close(ANT_HRMRX_ANT_CHANNEL); APP_ERROR_CHECK(err_code); // Note: Bonding information will be stored, advertising will be restarted and the // ANT channel will be reopened when ANT event CHANNEL_CLOSED is received. break; #ifndef BONDING_ENABLE case BLE_GAP_EVT_SEC_PARAMS_REQUEST: err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL); #endif // BONDING_ENABLE APP_ERROR_CHECK(err_code); break; case BLE_GAP_EVT_TIMEOUT: if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT) { nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO); // Go to system-off mode (this function will not return; wakeup will cause a reset) err_code = sd_power_system_off(); APP_ERROR_CHECK(err_code); } break; #ifndef BONDING_ENABLE case BLE_GATTS_EVT_SYS_ATTR_MISSING: err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0); APP_ERROR_CHECK(err_code); break; #endif // BONDING_ENABLE default: // No implementation needed. break; } }
/**@brief Sets the state machine to the specified state. */ static void ascmm_set_state(ascmm_states_t new_state) { uint32_t err_code; if(new_state != m_state) { switch (new_state) { case ASCMM_OFF: { //Close the channel err_code = sd_ant_channel_close(m_discovery_channel_number); APP_ERROR_CHECK(err_code); break; } case DISCOVERY: { if (m_state != ASCMM_OFF) { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } m_state = new_state; //Open the discovery channel err_code = sd_ant_channel_open(m_discovery_channel_number); break; } case CONNECTED: { if (m_state != DISCOVERY) { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } m_state = new_state; //Close the channel err_code = sd_ant_channel_close(m_discovery_channel_number); APP_ERROR_CHECK(err_code); //Assign the connection channel err_code = sd_ant_channel_assign(m_ant_connected_parameters.channel_number, m_ant_connected_parameters.channel_type, m_ant_connected_parameters.network_number, 0); APP_ERROR_CHECK(err_code); //Set channel id err_code = sd_ant_channel_id_set (m_ant_connected_parameters.channel_number, m_connection_device_number, m_ant_connected_parameters.device_type, m_ant_connected_parameters.tx_type); APP_ERROR_CHECK(err_code); //Set radio frequency err_code = sd_ant_channel_radio_freq_set (m_ant_connected_parameters.channel_number, m_ant_connected_parameters.rf_frequency); APP_ERROR_CHECK(err_code); if(m_ant_connected_parameters.channel_type == CHANNEL_TYPE_SLAVE) { //Configure search timeout for slave channel err_code = sd_ant_channel_rx_search_timeout_set(m_ant_connected_parameters.channel_number, ASCMM_SEARCH_TIMEOUT); APP_ERROR_CHECK(err_code); err_code = sd_ant_channel_low_priority_rx_search_timeout_set(m_ant_connected_parameters.channel_number, ASCMM_LP_SEARCH_TIMEOUT); APP_ERROR_CHECK(err_code); } else { // Configure Tx power for master chanel err_code = sd_ant_channel_radio_tx_power_set(m_ant_connected_parameters.channel_number, m_ant_connected_parameters.tx_power, 0); APP_ERROR_CHECK(err_code); } err_code = sd_ant_channel_open(m_ant_connected_parameters.channel_number); APP_ERROR_CHECK(err_code); break; } default: { //if the new state was not recognized, return to avoid setting the state changed event asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } } asc_event_set(&m_asc_event_flags, EVENT_ASC_STATE_CHANGED); } //lint --e{438} }
/**@brief Send command to node with highest RSSI. * If a global command was selected, send to all. */ static void send_command(void) { uint16_t device_number = 0; uint8_t max_rssi = 0; uint32_t err_code; // Loop through nodes and pick highest rssi node for(int node = 0; node < MAX_DEVICES; node++) { if(m_node_list[node].device_number != 0) { if(m_node_list[node].rssi > max_rssi) { max_rssi = m_node_list[node].rssi; device_number = m_node_list[node].device_number; } } } // Do not send the command if no device was found // Close scanning channel and return if( device_number == 0 ) { LEDS_ON(BSP_LED_2_MASK); LEDS_OFF(BSP_LED_0_MASK); err_code = sd_ant_channel_close(ANT_SCAN_CHANNEL_NUMBER); APP_ERROR_CHECK(err_code); return; } else { LEDS_OFF(BSP_LED_2_MASK); } err_code = sd_ant_channel_id_set(ANT_RESPONSE_CHANNEL_NUMBER, device_number, ANT_DEVICE_TYPE, ANT_TRANSMISSION_TYPE); APP_ERROR_CHECK(err_code); switch( m_command ) { case COMMAND_STATE_ON: m_command = COMMAND_LIGHT_ON; break; case COMMAND_STATE_OFF: m_command = COMMAND_LIGHT_OFF; break; case COMMAND_STATE_ALL_ON: device_number = ADDRESS_ALL_NODES; m_command = COMMAND_LIGHT_ON; break; case COMMAND_STATE_ALL_OFF: device_number = ADDRESS_ALL_NODES; m_command = COMMAND_LIGHT_OFF; break; default: break; } m_tx_buffer[0] = MOBILE_COMMAND_PAGE; m_tx_buffer[1] = 0xFF; m_tx_buffer[2] = device_number; m_tx_buffer[3] = 0xFF; m_tx_buffer[4] = 0xFF; m_tx_buffer[5] = 0xFF; m_tx_buffer[6] = 0xFF; m_tx_buffer[7] = m_command; err_code = sd_ant_acknowledge_message_tx(ANT_RESPONSE_CHANNEL_NUMBER, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); }
/**@brief Sets the state machine to the applicable state */ static void set_state(connection_states_t new_state) { uint32_t err_code; if(m_state != new_state) { switch(new_state) { case PHONE_OFF: { uint8_t channel_status; err_code = sd_ant_channel_status_get(m_channel_number, &channel_status); APP_ERROR_CHECK(err_code); m_state = new_state; switch(channel_status) { case STATUS_SEARCHING_CHANNEL: //Intentional fallthrough case STATUS_TRACKING_CHANNEL: { err_code = sd_ant_channel_close(m_channel_number); APP_ERROR_CHECK(err_code); } //Intentional fallthrough case STATUS_ASSIGNED_CHANNEL: { err_code = sd_ant_channel_unassign(m_channel_number); APP_ERROR_CHECK(err_code); break; } default: { return; } } break; } case PHONE_ON: { //uint32_t err_code; if(m_state == PHONE_OFF) { //Open the channel err_code = sd_ant_channel_open(m_channel_number); APP_ERROR_CHECK(err_code); } m_state = new_state; //Prepare the buffer asc_encode_device_availability_page(m_neighbor_id, m_tx_buffer); err_code = sd_ant_broadcast_message_tx (m_channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); break; } default: { return; } } } }
/**@brief Sets the state machine to the specified state. */ static void ascs_set_state(ascs_states_t new_state) { uint32_t err_code; if(m_state != new_state) { switch (new_state) { case OFF: { m_state = new_state; err_code = sd_ant_channel_close(m_channel_number); APP_ERROR_CHECK(err_code); break; } case SEARCHING: { //Check if we need to re-open the channel if (m_state == OFF) { //Open slave channel err_code = sd_ant_channel_open(m_channel_number); APP_ERROR_CHECK(err_code); } m_state = new_state; m_groups_assigned = NO_GROUPS; m_shared_address = SEARCH_ADDRESS; asc_encode_set_shared_address(m_shared_address, m_tx_buffer); err_code = sd_ant_broadcast_message_tx (m_channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); break; } case REQUESTING: { if(m_state != SEARCHING) { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } m_state = new_state; asc_encode_request_address_page(m_serial_number, m_tx_buffer); err_code = sd_ant_acknowledge_message_tx(m_channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); break; } case WAITING: { if(m_state != REQUESTING) { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } m_state = new_state; m_shared_address = REGISTER_ADDRESS; asc_encode_set_shared_address(m_shared_address, m_tx_buffer); err_code = sd_ant_broadcast_message_tx (m_channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); break; } case CONFIRMING: { if(m_state != WAITING) { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } m_state = new_state; m_timeout_counter = 0; asc_confirm_acquire_paramters_t params = { .serial_number = m_serial_number, .model_number = MODEL_NUMBER, .hw_revision = HW_REVISION, .sw_revision = SW_REVISION }; asc_encode_confirm_acquire_page(params, m_tx_buffer); err_code = sd_ant_acknowledge_message_tx(m_channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); break; } case ASSIGNED: { if(m_state != CONFIRMING) { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } ascs_states_t previous_state = m_state; m_state = new_state; m_timeout_counter = 0; if(previous_state == CONFIRMING) { asc_encode_set_shared_address(m_shared_address, m_tx_buffer); err_code = sd_ant_broadcast_message_tx (m_channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); } break; } default: { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } } asc_event_set(&m_asc_event_flags, EVENT_ASC_STATE_CHANGED); } }
/**@brief Sets the state machine to the specified state. */ static void ascm_set_state(ascm_states_t new_state) { uint32_t err_code; if (new_state != m_state) { switch (new_state) { case ASCM_OFF: { //Close the channel m_previous_state = m_state; m_state = new_state; err_code = sd_ant_channel_close(m_channel_number); APP_ERROR_CHECK(err_code); break; } case ADDRESS_AVAILABLE: { if (m_state == ASCM_OFF) { //Open the channel err_code = sd_ant_channel_open(m_channel_number); APP_ERROR_CHECK(err_code); } m_previous_state = m_state; m_state = new_state; m_is_address_available = !deviceregistry_is_full(pm_device_registry); ascm_send_address_available_page(); break; } case HANDSHAKING: { if (m_state != ADDRESS_AVAILABLE) { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } m_previous_state = m_state; m_state = new_state; //there is no need to check for validity of this shared address, as there must be a free address available //to be in the handshaking state at all. m_handshaking_device.shared_address = deviceregistry_get_next_free_shared_address(pm_device_registry); m_msg_counter_handshaking = 0; ascm_send_busy_acquiring_page(); break; } case POLLING: { if (m_state != ADDRESS_AVAILABLE && m_state != SENDING_COMMAND) { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } m_previous_state = m_state; m_state = new_state; //If the previous state was not SENDING_COMMAND, start from the beginning of the polling cycle. //Otherwise, allow the process_message handler to finish the cycle if (m_previous_state != SENDING_COMMAND) { m_current_shared_address_polling = deviceregistry_get_first_registered_shared_address(pm_device_registry); if (m_current_shared_address_polling != INVALID_SHARED_ADDRESS) { m_msg_counter_polling = 0; send_polling_message(); } else { //no devices are registered, go back to address available ascm_set_state(ADDRESS_AVAILABLE); } } break; } case SENDING_COMMAND: { //Only allow sending commands if the device is in the //Address available or polling states if (m_state != ADDRESS_AVAILABLE && m_state != POLLING) { asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } m_previous_state = m_state; m_state = new_state; m_msg_counter_sending_command = 0; break; } default: { //if the new state was not recognized, return to avoid setting the state changed event asc_event_set(&m_asc_event_flags, EVENT_ASC_DEVICE_IN_WRONG_STATE); return; } } asc_event_set(&m_asc_event_flags, EVENT_ASC_STATE_CHANGED); } }