/**@brief Function for setting payload for ANT message and sending it. */ void ant_message_send() { uint32_t err_code; uint8_t message_payload[ANT_STANDARD_DATA_PAYLOAD_SIZE]; memset(message_payload, 0, ANT_STANDARD_DATA_PAYLOAD_SIZE); // Assign a new value to the broadcast data. message_payload[ANT_STANDARD_DATA_PAYLOAD_SIZE - 1] = m_counter; // Broadcast the data. err_code = sd_ant_broadcast_message_tx(ANT_BROADCAST_CHANNEL_NUMBER, ANT_STANDARD_DATA_PAYLOAD_SIZE, message_payload); APP_ERROR_CHECK(err_code); // Increment the counter. m_counter++; }
ret_code_t ant_sdm_sens_open(ant_sdm_profile_t * p_profile) { ASSERT(p_profile != NULL); // Fill tx buffer for the first frame uint32_t err_code; uint8_t p_message_payload[ANT_STANDARD_DATA_PAYLOAD_SIZE]; sens_message_encode(p_profile, p_message_payload); err_code = sd_ant_broadcast_message_tx(p_profile->channel_number, sizeof (p_message_payload), p_message_payload); APP_ERROR_CHECK(err_code); LOG_SDM("ANT SDM channel %u open\n\r", p_profile->channel_number); return sd_ant_channel_open(p_profile->channel_number); }
/**@brief Function for creating and sending main * relay data page. * * @param[in] channel ANT channel on which to send this message. */ void ant_relay_main_message(uint8_t channel) { uint8_t status; uint32_t err_code = sd_ant_channel_status_get(ANT_RELAY_SLAVE_CHANNEL, &status); APP_ERROR_CHECK(err_code); m_broadcast_data[0] = ANT_RELAY_MAIN_PAGE; m_broadcast_data[1] = ( LED_IS_ON(BSP_LED_0_MASK) )? 1 : 0; m_broadcast_data[2] = (uint8_t)(m_led_change_counter >> 0); m_broadcast_data[3] = (uint8_t)(m_led_change_counter >> 8); m_broadcast_data[4] = (uint8_t)(m_led_change_counter >> 16); m_broadcast_data[5] = (uint8_t)(m_led_change_counter >> 24); m_broadcast_data[6] = 0xFF; m_broadcast_data[7] = status & STATUS_CHANNEL_STATE_MASK; err_code = sd_ant_broadcast_message_tx(channel, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_broadcast_data); APP_ERROR_CHECK(err_code); }
/**@brief Formats page with current button state and sends data * Byte 0 = Page number (Digital I/O Data) * Byte 1-6 = Reserved * Byte 7 = State of digital inputs */ static void handle_transmit() { uint32_t err_code; encode_button_state(); m_broadcast_data[0] = DIGITALIO_DATA_PID; m_broadcast_data[1] = 0xFF; m_broadcast_data[2] = 0xFF; m_broadcast_data[3] = 0xFF; m_broadcast_data[4] = 0xFF; m_broadcast_data[5] = 0xFF; m_broadcast_data[6] = 0xFF; m_broadcast_data[7] = m_tx_input_pin_state; err_code = sd_ant_broadcast_message_tx(ANT_CHANNEL_NUMBER, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_broadcast_data); APP_ERROR_CHECK(err_code); }
void ant_hrm_tx_evt_handle(ant_hrm_profile_t * p_profile, ant_evt_t * p_ant_event) { if (p_ant_event->channel == p_profile->channel_number) { uint8_t p_message_payload[8]; uint32_t err_code; switch (p_ant_event->event) { case EVENT_TX: encode_tx_message(p_profile, p_message_payload); err_code = sd_ant_broadcast_message_tx(p_profile->channel_number, sizeof(p_message_payload), p_message_payload); APP_ERROR_CHECK(err_code); break; default: break; } } }
/**@brief Processes a ANT messages while in the assigned state. * * @param[in] Pointer to the raw ant message received. */ static void ascs_process_message_assigned(uint8_t event, uint8_t * p_event_message_buffer) { uint32_t err_code; switch (event) { case EVENT_RX: { m_timeout_counter = 0; switch(p_event_message_buffer[DECODE_PAGE_ID_BYTE]) { case REQUEST_DATA_PID: { err_code = asc_decode_request_data_page(&m_last_received_request, p_event_message_buffer); APP_ERROR_CHECK(err_code); //if the request is for the update data page, handle it automatically. //Otherwise, notify the application that the request came in if(m_last_received_request.page_id_requested == UPDATE_DATA_PID) { asc_update_data_t update = { .shared_address = m_shared_address, .state = m_light_state }; asc_encode_update_data_page(update, m_response_buffer); err_code = sd_ant_broadcast_message_tx(m_channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_response_buffer); APP_ERROR_CHECK(err_code); } else { asc_event_set(&m_asc_event_flags, EVENT_ASC_REQUEST_RECEIVED); } break; } case COMMAND_PID: { ascs_process_command(p_event_message_buffer); break; } } break; }
/**@brief Processes a ANT messages while in the connected state. * * @param[in] Pointer to the raw ant message received. */ static void process_message_connected(uint8_t * p_ant_message) { uint32_t err_code; switch (p_ant_message[ANT_MESSAGE_ID_OFFSET]) { case MESG_RESPONSE_EVENT_ID: { if(p_ant_message[ANT_MESSAGE_DATA0_OFFSET] == MESG_EVENT_ID) //Channel event { switch(p_ant_message[ANT_MESSAGE_DATA1_OFFSET]) { case EVENT_TX: { //If this is a slave channel, we will need to controll the reverse-direction communication. //Otherwise, the last message loaded into the tx buffer will continue to be transmitted anyway if( m_retries-- > 0) { err_code = sd_ant_broadcast_message_tx(m_ant_connected_parameters.channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); } else if (m_ant_connected_parameters.channel_type == CHANNEL_TYPE_MASTER) { memcpy(m_tx_buffer, ascmm_idle_page, ANT_STANDARD_DATA_PAYLOAD_SIZE); err_code = sd_ant_broadcast_message_tx(m_ant_connected_parameters.channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); } break; } default: break; } } break; } case MESG_BROADCAST_DATA_ID: //fall-through case MESG_ACKNOWLEDGED_DATA_ID: { //process by page switch (p_ant_message[DECODE_PAGE_ID_BYTE_PHONE_FORMAT]) { case PHONE_COMMAND_PID: { //lint --e{534} asc_decode_phone_command_page(&m_last_received_command, p_ant_message); asc_event_set(&m_asc_event_flags, EVENT_ASC_COMMAND_RECEIVED); break; } case UPDATE_DATA_PID: { //lint --e{534} asc_decode_phone_update_data_page(&m_last_received_update, p_ant_message); asc_event_set(&m_asc_event_flags, EVENT_ASC_UPDATE_RECEIVED); break; } default: { break; } } break; } default: break; } }
/**@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 Processes an ANT messages while in the sending command state. * * @param[in] Pointer to the raw ant message received. */ static void process_message_sending_command(uint8_t* p_ant_message) { uint32_t err_code; switch (p_ant_message[ANT_MESSAGE_ID_OFFSET]) { case MESG_RESPONSE_EVENT_ID: { if (p_ant_message[ANT_MESSAGE_DATA0_OFFSET] == MESG_EVENT_ID) //Channel event { switch (p_ant_message[ANT_MESSAGE_DATA1_OFFSET]) { case EVENT_TX: { //This event will be received if broadcast messages were used //Automatically retry to increase the chances of a successful transmission asc_encode_command_page(m_current_command_data, m_tx_buffer); if (m_send_command_as_ack) { err_code = sd_ant_acknowledge_message_tx(m_channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); } else { err_code = sd_ant_broadcast_message_tx(m_channel_number, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx_buffer); } APP_ERROR_CHECK(err_code); if (++m_msg_counter_sending_command > m_retries) { m_is_command_pending = false; ascm_set_state(m_previous_state); } break; } case EVENT_TRANSFER_TX_COMPLETED: { //The message was successfully received. No need to resend m_is_command_pending = false; ascm_set_state(m_previous_state); break; } case EVENT_TRANSFER_TX_FAILED: { asc_encode_command_page(m_current_command_data, 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); //retry untitl success, or until too many retries have occured if (++m_msg_counter_sending_command > m_retries) { m_is_command_pending = false; ascm_set_state(m_previous_state); } break; } default: { break; } } } break; } case MESG_ACKNOWLEDGED_DATA_ID: //fall-through case MESG_BROADCAST_DATA_ID: { //Process by page switch (p_ant_message[DECODE_PAGE_ID_BYTE]) { case UPDATE_DATA_PID: { process_device_update(p_ant_message); break; } default: { break; } } break; } default: { break; } } }
/**@brief Process ANT message on ANT mobile interface channel * * @details This function handles all events on the mobile interface channel. * On EVENT_TX an ANT_MOBILE_MAIN_PAGE message is queue. The format is: * byte[0] = page (1 = ANT_MOBILE_MAIN_PAGE) * byte[1] = led state (1 = 0N, 0 = OFF) * byte[2-6] = reserved (0xFF) * byte[7] = relay slave channel status (0 = unnassigned, 1 = assigned, 2 = searching, 3 = tracking) * * On EVENT_RX the function will decode an ANT_MOBILE_COMMAND_PAGE. The format is: * byte[0] = page (2 = ANT_MOBILE_COMMAND_PAGE) * byte[1] = reserved (Set to 0xFF) * byte[2] = command (1 = pairing, 2 = led on, 3 = led off) * byte[3-7] = reserved (Set to 0xFF) * * @param[in] p_ant_event ANT message content. */ void ant_process_mobile(ant_evt_t* p_ant_event) { ANT_MESSAGE* p_ant_message = (ANT_MESSAGE*)p_ant_event->evt_buffer; switch(p_ant_event->event) { case EVENT_RX: { switch(p_ant_message->ANT_MESSAGE_aucPayload[0]) { case ANT_MOBILE_COMMAND_PAGE: { switch(p_ant_message->ANT_MESSAGE_aucPayload[2]) { case ANT_COMMAND_ON: { LEDS_ON(BSP_LED_0_MASK); m_led_change_counter++; break; } case ANT_COMMAND_OFF: { LEDS_OFF(BSP_LED_0_MASK); m_led_change_counter++; break; } case ANT_COMMAND_PAIRING: { uint8_t channel_status; uint32_t err_code = sd_ant_channel_status_get (ANT_RELAY_SLAVE_CHANNEL, &channel_status); APP_ERROR_CHECK(err_code); if((channel_status & STATUS_CHANNEL_STATE_MASK) == STATUS_ASSIGNED_CHANNEL) { err_code = sd_ant_channel_open(ANT_RELAY_SLAVE_CHANNEL); APP_ERROR_CHECK(err_code); } break; } } break; } default: { break; } } break; } case EVENT_TX: { uint8_t status; uint32_t err_code = sd_ant_channel_status_get(ANT_RELAY_SLAVE_CHANNEL, &status); APP_ERROR_CHECK(err_code); m_broadcast_data[0] = ANT_MOBILE_MAIN_PAGE; m_broadcast_data[1] = ( LED_IS_ON(BSP_LED_0_MASK) )? 1 : 0; m_broadcast_data[2] = 0xFF; m_broadcast_data[3] = 0xFF; m_broadcast_data[4] = 0xFF; m_broadcast_data[5] = 0xFF; m_broadcast_data[6] = 0xFF; m_broadcast_data[7] = status & STATUS_CHANNEL_STATE_MASK; err_code = sd_ant_broadcast_message_tx(ANT_MOBILE_CHANNEL, ANT_STANDARD_DATA_PAYLOAD_SIZE, m_broadcast_data); APP_ERROR_CHECK(err_code); break; } default: { break; } } }
/**@brief Function for transmitting a broadcast message. * * @retval NRF_SUCCESS Operation success. * @retval NRF_ERROR_INVALID_PARAM Operation failure. Invalid Parameter. * @retval NRF_ANT_ERROR_MESSAGE_SIZE_EXCEEDS_LIMIT Operation failure. Data message provided is too * large. * @retval NRF_ANT_ERROR_INVALID_SCAN_TX_CHANNEL Operation failure. Attempt to transmit on * channel 0 while in scan mode. * @retval NRF_ANT_ERROR_CHANNEL_IN_WRONG_STATE Operation failure. Attempt to perform an action * in a wrong channel state. * @retval NRF_ANT_ERROR_TRANSFER_IN_PROGRESS Operation failure. Attempt to communicate on a * channel with a TX transfer in progress. * @retval NRF_ANT_ERROR_TRANSFER_IN_ERROR Operation failure. Transfer error has occured on * supplied burst message or burst data segment. */ static __INLINE uint32_t broadcast_message_transmit(void) { return sd_ant_broadcast_message_tx(CBSC_TX_ANT_CHANNEL, TX_BUFFER_SIZE, m_tx_buffer); }
void ant_message_types_master_setup(void) { uint32_t err_code; ant_channel_config_t channel_config = { .channel_number = ANT_CHANNEL_NUMBER, .channel_type = CHANNEL_TYPE_MASTER, .ext_assign = EXT_ASSIGN, .rf_freq = RF_FREQUENCY, .transmission_type = CHAN_ID_TRANS_TYPE, .device_type = CHAN_ID_DEV_TYPE, .device_number = (uint16_t) (NRF_FICR->DEVICEID[0]), .channel_period = CHANNEL_PERIOD, .network_number = ANT_CHANNEL_DEFAULT_NETWORK, }; err_code = ant_channel_init(&channel_config); APP_ERROR_CHECK(err_code); //Set Tx Power err_code = sd_ant_channel_radio_tx_power_set(ANT_CHANNEL_NUMBER, RADIO_TX_POWER_LVL_3, ANT_CUSTOM_TRANSMIT_POWER); APP_ERROR_CHECK(err_code); // Open channel. err_code = sd_ant_channel_open(ANT_CHANNEL_NUMBER); APP_ERROR_CHECK(err_code); // Write counter value to last byte of the broadcast data. // The last byte is chosen to get the data more visible in the end of an printout // on the recieving end. memset(m_tx_buffer, 0, BROADCAST_DATA_BUFFER_SIZE); m_tx_buffer[BROADCAST_DATA_BUFFER_SIZE - 1] = m_counter; // Configure the initial payload of the broadcast data err_code = sd_ant_broadcast_message_tx(ANT_CHANNEL_NUMBER, BROADCAST_DATA_BUFFER_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); //Set state to broadcasting state_message_types = BROADCAST; } void ant_message_types_master_bsp_evt_handler(bsp_event_t evt) { switch (evt) { case BSP_EVENT_KEY_0: state_message_types = BROADCAST; break; case BSP_EVENT_KEY_1: state_message_types = ACKNOWLEDGED; break; case BSP_EVENT_KEY_2: state_message_types = BURST; break; default: break; // no implementation needed } } void ant_message_types_master_event_handler(ant_evt_t * p_ant_evt) { uint32_t err_code; uint32_t led_output = LED_BROADCAST; switch (p_ant_evt->event) { // ANT broadcast/Acknowledged/Burst Success // Send the next message according to the current state and increment the counter. case EVENT_TX: // Intentional fall through case EVENT_TRANSFER_TX_COMPLETED: // Intentional fall through case EVENT_TRANSFER_TX_FAILED: LEDS_OFF(LEDS_MASK); m_tx_buffer[BROADCAST_DATA_BUFFER_SIZE - 1] = m_counter; if(state_message_types == BROADCAST) { // Send as broadcast err_code = sd_ant_broadcast_message_tx(ANT_CHANNEL_NUMBER, BROADCAST_DATA_BUFFER_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); led_output = LED_BROADCAST; } else if(state_message_types == ACKNOWLEDGED) { // Send as acknowledged err_code = sd_ant_acknowledge_message_tx(ANT_CHANNEL_NUMBER, BROADCAST_DATA_BUFFER_SIZE, m_tx_buffer); APP_ERROR_CHECK(err_code); led_output = LED_ACKNOWLEDGED; } else if(state_message_types == BURST) { // If this is a new message, populate the burst buffer // with new dummy data. Otherwise, will retry sending the // same content. if(p_ant_evt->event != EVENT_TRANSFER_TX_FAILED) { for(uint32_t i = 0; i < BURST_BLOCK_SIZE; i++) { m_burst_data[i] = m_counter; m_counter++; } } // Queue a Burst Transfer. Since this is a small burst, queue entire burst. err_code = sd_ant_burst_handler_request(ANT_CHANNEL_NUMBER, BURST_BLOCK_SIZE, m_burst_data, (BURST_SEGMENT_START | BURST_SEGMENT_END)); APP_ERROR_CHECK(err_code); led_output = LED_BURST; } // Activate LED for 20ms LEDS_ON(led_output); nrf_delay_ms(20); LEDS_OFF(led_output); m_counter++; break; case TRANSFER_IN_PROGRESS: //Intentional fall through case TRANSFER_SEQUENCE_NUMBER_ERROR: //Intentional fall through case TRANSFER_IN_ERROR: //Intentional fall through case TRANSFER_BUSY: // Ignore these events; will retry burst transfer when we get the EVENT_TRANSFER_TX_FAILED event. break; default: break; } }