/** * This is the default process control point method. * * @param buffer - the data buffer * @param length - the data length */ bool NRF8001Driver::_uart_process_control_point(uint8_t* buffer, uint8_t length){ // Status container bool status = false; // Connection parameters pointer aci_ll_conn_params_t* conn_params; // If hte TX pipe is available if (lib_aci_is_pipe_available(this->_aci_state, PIPE_UART_OVER_BTLE_UART_CONTROL_POINT_TX) ){ // We switch on the buffer pointer switch(*buffer){ /** * Queues a ACI Disconnect to the nRF8001 when this packet is received. * May cause some of the UART packets being sent to be dropped */ case UART_OVER_BLE_DISCONNECT: /** * Parameters: * None */ lib_aci_disconnect(this->_aci_state, ACI_REASON_TERMINATE); status = true; break; /** * Queues an ACI Change Timing to the nRF8001 */ case UART_OVER_BLE_LINK_TIMING_REQ: /** * Parameters: * Connection interval min: 2 bytes * Connection interval max: 2 bytes * Slave latency: 2 bytes * Timeout: 2 bytes * Same format as Peripheral Preferred Connection Parameters * (See nRFgo studio -> nRF8001 Configuration -> GAP Settings) * Refer to the ACI Change Timing Request in the nRF8001 Product Specifications */ #ifdef DEBUG Serial.print(F("UART over BLE linkin timing request.")); #endif conn_params = (aci_ll_conn_params_t*)(buffer + 1); lib_aci_change_timing(conn_params->min_conn_interval, conn_params->max_conn_interval, conn_params->slave_latency, conn_params->timeout_mult); status = true; break; /** * Clears the RTS of the UART over BLE */ case UART_OVER_BLE_TRANSMIT_STOP: /** * Parameters: * None */ this->_uart_over_ble.uart_rts_local = false; status = true; break; /** * Set the RTS of the UART over BLE */ case UART_OVER_BLE_TRANSMIT_OK: /** * Parameters: * None */ this->_uart_over_ble.uart_rts_local = true; status = true; break; } } return status; }
/************************************************************************** * * Handles low level ACI events, and passes them up to an application * level callback when appropriate * **************************************************************************/ void GoosciBleGatt::pollACI() { static bool setup_required = false; // We enter the if statement only when there is a ACI event // available to be processed if (lib_aci_event_get(&aci_state, &aci_data)) { aci_evt_t *aci_evt; aci_evt = &aci_data.evt; // DEBUG_PRINTLN(F("pollACI")); // DEBUG_PRINT("evt opcode: "); // DEBUG_PRINTLN2(aci_evt->evt_opcode, HEX); // DEBUG_PRINT(F("State Total credit: ")); // DEBUG_PRINTLN(aci_state.data_credit_total); // DEBUG_PRINT(F("State Available credit: ")); // DEBUG_PRINTLN(aci_state.data_credit_available); // DEBUG_PRINT("Event Available credit: "); // DEBUG_PRINTLN(aci_evt->params.device_started.credit_available); switch (aci_evt->evt_opcode) { case ACI_EVT_DEVICE_STARTED: { // DEBUG_PRINTLN("STARTED"); aci_state.data_credit_total = aci_evt->params.device_started.credit_available; switch (aci_evt->params.device_started.device_mode) { case ACI_DEVICE_SETUP: { // DEBUG_PRINTLN("SETUP"); aci_state.device_state = ACI_DEVICE_SETUP; setup_required = true; break; } case ACI_DEVICE_STANDBY: { // DEBUG_PRINTLN("STANDBY"); aci_state.device_state = ACI_DEVICE_STANDBY; // sleep_to_wakeup_timeout = 30; if (aci_evt->params.device_started.hw_error) { // Magic number used to make sure the HW error // event is handled correctly. delay(20); } else { get_address(); // DEBUG_PRINTLN("lib_aci_connect"); lib_aci_connect(adTimeout, adInterval); } break; } case ACI_DEVICE_INVALID: { DEBUG_PRINTLN(F("Evt Device Invalid")); break; } case ACI_DEVICE_TEST: { break; } case ACI_DEVICE_SLEEP: { break; } } break; // case ACI_EVT_DEVICE_STARTED: } case ACI_EVT_CMD_RSP: { DEBUG_PRINTLN("ACI_EVT_CMD_RSP"); // If an ACI command response event comes with an error -> stop if (ACI_STATUS_SUCCESS != aci_evt->params.cmd_rsp.cmd_status) { // ACI ReadDynamicData and ACI WriteDynamicData // will have status codes of // TRANSACTION_CONTINUE and TRANSACTION_COMPLETE // all other ACI commands will have status code of // ACI_STATUS_SCUCCESS for a successful command DEBUG_PRINT(F("ACI Command 0x")); DEBUG_PRINTLN2(aci_evt->params.cmd_rsp.cmd_opcode, HEX); DEBUG_PRINT(F("Evt Cmd response: Error. ")); DEBUG_PRINTLN2(aci_evt->params.cmd_rsp.cmd_status, HEX); } if (ACI_CMD_GET_DEVICE_ADDRESS == aci_evt->params.cmd_rsp.cmd_opcode) { // If this is a response to get device address, save the address addrReceived = true; // DEBUG_PRINT(F("Get device address response: ")); for (int i = BTLE_DEVICE_ADDRESS_SIZE - 1; i >= 0; --i) { deviceAddress[i] = aci_evt->params.cmd_rsp.params.get_device_address .bd_addr_own[i]; // DEBUG_PRINT2(deviceAddress[i], HEX); // DEBUG_PRINT(F(":")); } // DEBUG_PRINTLN(F("")); } else if (ACI_CMD_OPEN_ADV_PIPE == aci_evt->params.cmd_rsp.cmd_opcode) { DEBUG_PRINTLN( F("Open advertising pipe response, setting service data.")); lib_aci_set_local_data( &aci_state, PIPE_DEVICE_INFORMATION_MODEL_NUMBER_STRING_BROADCAST, (unsigned char *)longName, 8); DEBUG_PRINT(F("Advertising starting for ")); DEBUG_PRINTLN(deviceName); lib_aci_connect(adTimeout, adInterval); } else if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode) { DEBUG_PRINTLN("ACI_CMD_GET_DEVICE_VERSION"); } else if (ACI_CMD_SET_LOCAL_DATA == aci_evt->params.cmd_rsp.cmd_opcode) { DEBUG_PRINTLN("ACI_CMD_SET_LOCAL_DATA"); } else if (ACI_CMD_CONNECT == aci_evt->params.cmd_rsp.cmd_opcode) { DEBUG_PRINTLN("ACI_CMD_CONNECT"); } else if (ACI_CMD_DISCONNECT == aci_evt->params.cmd_rsp.cmd_opcode) { DEBUG_PRINTLN("ACI_CMD_DISCONNECT"); } else if (ACI_CMD_CHANGE_TIMING == aci_evt->params.cmd_rsp.cmd_opcode) { DEBUG_PRINTLN("ACI_CMD_CHANGE_TIMING"); } else { // print command DEBUG_PRINT(F("Unexpected ACI Command 0x")); DEBUG_PRINTLN2(aci_evt->params.cmd_rsp.cmd_opcode, HEX); } break; } case ACI_EVT_CONNECTED: { // The nRF8001 is now connected to the peer device. DEBUG_PRINTLN(F("Evt Connected")); aci_state.data_credit_available = aci_state.data_credit_total; timing_change_done = false; break; } case ACI_EVT_PIPE_STATUS: { DEBUG_PRINTLN(F("Evt Pipe Status: ")); // DEBUG_PRINT2((int) aci_evt->params.pipe_status.pipes_open_bitmap, HEX); // DEBUG_PRINT(" "); // DEBUG_PRINTLN2((int) aci_evt->params.pipe_status.pipes_closed_bitmap, HEX); if (lib_aci_is_pipe_available(&aci_state, PIPE_GOOSCI_SENSOR_VALUE_TX) && !timing_change_done) { lib_aci_change_timing(6, 6, 0, 600); // Low-latency parameters timing_change_done = true; } break; } case ACI_EVT_TIMING: { // DEBUG_PRINT("ACI_EVT_TIMING: "); // DEBUG_PRINT(aci_evt->params.timing.conn_rf_interval); // DEBUG_PRINT(" "); // DEBUG_PRINT(aci_evt->params.timing.conn_slave_rf_latency); // DEBUG_PRINT(" "); // DEBUG_PRINT(aci_evt->params.timing.conn_rf_timeout); // DEBUG_PRINT(" "); // DEBUG_PRINTLN(aci_evt->params.timing.conn_rf_interval); break; } case ACI_EVT_DISCONNECTED: { // Advertise again if the advertising timed out. DEBUG_PRINTLN(F("Evt Disconnected.")); // TODO(dek): figure out why the transition to using credits // broke disconnection (packets are still transmitted). // Setting the credits to 0 was an experiment but it didn't work. // aci_state.data_credit_available = 0; lib_aci_connect(adTimeout, adInterval); timing_change_done = false; break; } case ACI_EVT_DATA_RECEIVED: { DEBUG_PRINTLN("ACI_EVT_DATA_RECEIVED"); if (aci_evt->params.data_received.rx_data.pipe_number == PIPE_GOOSCI_SENSOR_CONFIGURATION_RX_ACK_AUTO) { int8_t packet_length = aci_evt->len; handle(aci_evt->params.data_received.rx_data.aci_data, aci_evt->len); } else { DEBUG_PRINT(F(" Data(Hex) : ")); for (int i = 0; i < aci_evt->len - 2; i++) { DEBUG_PRINT2(aci_evt->params.data_received.rx_data.aci_data[i], HEX); DEBUG_PRINT(F(" ")); } DEBUG_PRINTLN(F("")); } break; } case ACI_EVT_DATA_CREDIT: { // DEBUG_PRINTLN(F("Evt Credit: Peer has received our send")); aci_state.data_credit_available = aci_state.data_credit_available + aci_evt->params.data_credit.credit; break; } case ACI_EVT_PIPE_ERROR: { // See the appendix in the nRF8001 // Product Specication for details on the error codes DEBUG_PRINT(F("ACI Evt Pipe Error: Pipe #:")); DEBUG_PRINT2(aci_evt->params.pipe_error.pipe_number, DEC); DEBUG_PRINT(F(" Pipe Error Code: 0x")); DEBUG_PRINTLN2(aci_evt->params.pipe_error.error_code, HEX); // Increment the credit available as the data packet was not sent. // The pipe error also represents the Attribute protocol // Error Response sent from the peer and that should not be counted // for the credit. if (ACI_STATUS_ERROR_PEER_ATT_ERROR != aci_evt->params.pipe_error.error_code) { aci_state.data_credit_available++; } break; } case ACI_EVT_DATA_ACK: { // DEBUG_PRINTLN(F("ACK")); break; } case ACI_EVT_HW_ERROR: { DEBUG_PRINTLN(F("HW error: ")); DEBUG_PRINTLN2(aci_evt->params.hw_error.line_num, DEC); for (int counter = 0; counter <= (aci_evt->len - 3); counter++) { DEBUG_PRINT(aci_evt->params.hw_error.file_name[counter]); } DEBUG_PRINTLN(); initLocalData(); lib_aci_connect(adTimeout, adInterval); break; } default: { DEBUG_PRINT(F("Evt Opcode 0x")); DEBUG_PRINT2(aci_evt->evt_opcode, HEX); DEBUG_PRINTLN(F(" unhandled")); break; } } } // setup_required is set to true when the device starts // up and enters setup mode. // It indicates that do_aci_setup() should be called. // The flag should be cleared if do_aci_setup() returns // ACI_STATUS_TRANSACTION_COMPLETE. if (setup_required) { int result = do_aci_setup(&aci_state); if (result != SETUP_SUCCESS ) { switch(result) { case SETUP_FAIL_COMMAND_QUEUE_NOT_EMPTY: DEBUG_PRINTLN("SETUP_FAIL_COMMAND_QUEUE_NOT_EMPTY"); break; case SETUP_FAIL_EVENT_QUEUE_NOT_EMPTY: DEBUG_PRINTLN("SETUP_EVENT_COMMAND_QUEUE_NOT_EMPTY"); break; case SETUP_FAIL_NOT_SETUP_EVENT: DEBUG_PRINTLN("SETUP_FAIL_NOT_SETUP_EVENT"); break; case SETUP_FAIL_NOT_COMMAND_RESPONSE: DEBUG_PRINTLN("SETUP_FAIL_NOT_COMMAND_RESPONSE"); break; } } else { setup_required = false; } } }
bool Adafruit_BLE_UART::uart_process_control_point_rx(uint8_t *byte, uint8_t length) { bool status = false; aci_ll_conn_params_t *conn_params; if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_CONTROL_POINT_TX) ) { Serial.println(*byte, HEX); switch(*byte) { /* Queues a ACI Disconnect to the nRF8001 when this packet is received. May cause some of the UART packets being sent to be dropped */ case UART_OVER_BLE_DISCONNECT: /* Parameters: None */ lib_aci_disconnect(&aci_state, ACI_REASON_TERMINATE); status = true; break; /* Queues an ACI Change Timing to the nRF8001 */ case UART_OVER_BLE_LINK_TIMING_REQ: /* Parameters: Connection interval min: 2 bytes Connection interval max: 2 bytes Slave latency: 2 bytes Timeout: 2 bytes Same format as Peripheral Preferred Connection Parameters (See nRFgo studio -> nRF8001 Configuration -> GAP Settings Refer to the ACI Change Timing Request in the nRF8001 Product Specifications */ conn_params = (aci_ll_conn_params_t *)(byte+1); lib_aci_change_timing( conn_params->min_conn_interval, conn_params->max_conn_interval, conn_params->slave_latency, conn_params->timeout_mult); status = true; break; /* Clears the RTS of the UART over BLE */ case UART_OVER_BLE_TRANSMIT_STOP: /* Parameters: None */ uart_over_ble.uart_rts_local = false; status = true; break; /* Set the RTS of the UART over BLE */ case UART_OVER_BLE_TRANSMIT_OK: /* Parameters: None */ uart_over_ble.uart_rts_local = true; status = true; break; } } return status; }