void ble_achs_on_ble_evt(ble_achs_t * p_achs, ble_evt_t * p_ble_evt) { switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: p_achs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; // If we are connected start reporting, push a fake reporting mode on command m_last_received_command.command = REPORTING_MODE_ON; m_last_received_command.master_id = EVERY_MASTER_ID; m_last_received_command.group_number = NO_GROUPS; m_last_received_command.shared_address = EVERY_DEVICE_ADDRESS; asc_event_set(&m_event_flags, EVENT_ASC_COMMAND_RECEIVED); break; case BLE_GAP_EVT_DISCONNECTED: p_achs->conn_handle = BLE_CONN_HANDLE_INVALID; break; case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: on_rw_authorize_request(p_achs, &p_ble_evt->evt.gatts_evt); break; default: // No implementation needed. break; } }
/**@brief Processes a device update message and sets the update received event flag. * * @param[in] Pointer to the raw ant message received. */ static void process_device_update(uint8_t * p_ant_message) { uint32_t err_code; err_code = asc_decode_update_data_page(&m_last_received_udpate, p_ant_message); APP_ERROR_CHECK(err_code); asc_event_set(&m_asc_event_flags, EVENT_ASC_UPDATE_RECEIVED); }
/**@brief ANT message processor for the current <STATE> * * @param pucANTMessage - pointer to a buffer with an ANT event */ static void process_message_on(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 (m_is_update_available && ++m_retry_counter >= m_retries) { m_is_update_available = false; m_retry_counter = 0; 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; } } } break; } case MESG_BROADCAST_DATA_ID: //fall-through case MESG_ACKNOWLEDGED_DATA_ID: { //Process by page switch(p_ant_message[ANT_MESSAGE_DATA0_OFFSET]) { case PHONE_COMMAND_PID: { //Store command info //lint --e{534} asc_decode_phone_command_page(&m_last_command, p_ant_message); asc_event_set(&m_asc_events, EVENT_ASC_COMMAND_RECEIVED); break; } default: break; } 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 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 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 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 Function to decode and handle a command message. */ static void ascs_process_command(uint8_t * p_event_message_buffer) { uint32_t err_code; asc_command_data_t command_data; err_code = asc_decode_command_page(&command_data, p_event_message_buffer); APP_ERROR_CHECK(err_code); switch(command_data.command) { case TURN_OFF: { if(command_data.group_number == NO_GROUPS || (GROUP_SET << command_data.group_number) & m_groups_assigned) { m_light_state = SLAVE_STATE_OFF; } break; } case TURN_ON: { if(command_data.group_number == NO_GROUPS || (GROUP_SET << command_data.group_number) & m_groups_assigned) { m_light_state = SLAVE_STATE_ON; } break; } case ASSIGN_TO_GROUP: { m_groups_assigned = GROUP_SET << command_data.group_number; break; } case ASSIGN_TO_ADDITIONAL_GROUP: { m_groups_assigned |= GROUP_SET << command_data.group_number; break; } case ASSIGN_TO_ALL_GROUPS: { m_groups_assigned = ALL_GROUPS; break; } case CLEAR_FROM_GROUP: { //lint --e{502} m_groups_assigned &= ~(GROUP_SET << command_data.group_number); break; } case CLEAR_FROM_ALL_GROUPS: { m_groups_assigned = NO_GROUPS; break; } default: { break; } } asc_event_set(&m_asc_event_flags, EVENT_ASC_LIGHT_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); } }
static void on_ctrlpt_write(ble_achs_t * p_achs, ble_gatts_evt_write_t * p_evt_write) { ble_gatts_rw_authorize_reply_params_t auth_reply; auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; if (is_cccd_configured()) { auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; uint32_t err_code = sd_ble_gatts_rw_authorize_reply(p_achs->conn_handle, &auth_reply); (void)err_code; } else { auth_reply.params.write.gatt_status = ACH_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED; uint32_t err_code = sd_ble_gatts_rw_authorize_reply(p_achs->conn_handle, &auth_reply); (void)err_code; return; } uint8_t op_code = p_evt_write->data[0]; //lint --e{415} uint8_t command = p_evt_write->data[1]; if (op_code == ACH_OP_COMMAND) { switch (command) { case ACH_CMD_REPORTING_MODE_OFF: { //Load up the last received command structure so the application //gets recent data when it asks for it m_last_received_command.command = REPORTING_MODE_OFF; m_last_received_command.master_id = EVERY_MASTER_ID; //Set the command received flag so the application will know to ask for //the most recent command. asc_event_set(&m_event_flags, EVENT_ASC_COMMAND_RECEIVED); } break; case ACH_CMD_REPORTING_MODE_ON: { //Load up the last received command structure so the application //gets recent data when it asks for it m_last_received_command.command = REPORTING_MODE_ON; m_last_received_command.master_id = EVERY_MASTER_ID; //Set the command received flag so the application will know to ask for //the most recent command. asc_event_set(&m_event_flags, EVENT_ASC_COMMAND_RECEIVED); } break; case ACH_CMD_REPORTING_MODE_WARNINGS: { /* this command is not currently supported by this demo //Load up the last received command structure so the application //gets recent data when it asks for it m_last_received_command.command = REPORTING_MODE_WARNINGS; m_last_received_command.master_id = EVERY_MASTER_ID; //Set the command received flag so the application will know to ask for //the most recent command. asc_event_set(&m_event_flags, EVENT_ASC_COMMAND_RECEIVED); */ } break; case ACH_CMD_PERI_ON: { //Load up the last received command structure so the application //gets recent data when it asks for it m_last_received_command.command = TURN_ON; //lint --e{415} //lint --e{416} m_last_received_command.shared_address = p_evt_write->data[2]; //lint --e{415} //lint --e{416} m_last_received_command.master_id = uint16_decode(&p_evt_write->data[4]); m_last_received_command.group_number = NO_GROUPS;/**< @todo can the demo actually use groups? Double check this everywhere*/ //Set the command received flag so the application will know to ask for //the most recent command. asc_event_set(&m_event_flags, EVENT_ASC_COMMAND_RECEIVED); } break; case ACH_CMD_PERI_OFF: { //Load up the last received command structure so the application //gets recent data when it asks for it m_last_received_command.command = TURN_OFF; //lint --e{416} m_last_received_command.shared_address = p_evt_write->data[2]; //lint --e{416} m_last_received_command.master_id = uint16_decode(&p_evt_write->data[4]); m_last_received_command.group_number = NO_GROUPS; //Set the command received flag so the application will know to ask for //the most recent command. asc_event_set(&m_event_flags, EVENT_ASC_COMMAND_RECEIVED); } break; case ACH_CMD_GROUP_ASSIGN: { //Load up the last received command structure so the application //gets recent data when it asks for it m_last_received_command.command = ASSIGN_TO_GROUP; //lint --e{416} m_last_received_command.shared_address = p_evt_write->data[2]; //lint --e{416} m_last_received_command.master_id = uint16_decode(&p_evt_write->data[4]); m_last_received_command.group_number = p_evt_write->data[3]; //Set the command received flag so the application will know to ask for //the most recent command. asc_event_set(&m_event_flags, EVENT_ASC_COMMAND_RECEIVED); } break; case ACH_CMD_GROUP_ON: { //Load up the last received command structure so the application //gets recent data when it asks for it m_last_received_command.command = TURN_ON; m_last_received_command.shared_address = EVERY_DEVICE_ADDRESS; //lint --e{416} m_last_received_command.master_id = uint16_decode(&p_evt_write->data[3]); m_last_received_command.group_number = p_evt_write->data[2]; asc_event_set(&m_event_flags, EVENT_ASC_COMMAND_RECEIVED); } break; case ACH_CMD_GROUP_OFF: { //Load up the last received command structure so the application //gets recent data when it asks for it m_last_received_command.command = TURN_OFF; m_last_received_command.shared_address = EVERY_DEVICE_ADDRESS; //lint --e{416} m_last_received_command.master_id = uint16_decode(&p_evt_write->data[3]); m_last_received_command.group_number = p_evt_write->data[2]; asc_event_set(&m_event_flags, EVENT_ASC_COMMAND_RECEIVED); } break; default: break; } // end switch(command) } }