boolean BLE::writeBufferToPipe(uint8_t *buffer, uint8_t byteCount, uint8_t pipe) { boolean success = false; if (lib_aci_is_pipe_available(&aci_state, pipe) && (aci_state.data_credit_available >= 1)) { #ifdef ACI_DEBUG Serial.print(byteCount); Serial.println(F(" bytes sent to pipe")); #endif success = lib_aci_send_data(pipe, buffer, byteCount); if (success) { aci_state.data_credit_available--; waitForDataCredit(); } else Serial.println(F("lib_aci_send_data() failed")); } else { /* notification pipe not available when no client ask for notification */ //Serial.println(F("Pipe not available or no remaining data credits: ")); } return success; }
void update_battery(aci_state_t *aci_stat, uint8_t percent_level) { bool is_discharging = false; uint8_t level_difference = 0; // Serial.print(F(" Is discharging: ")); // Serial.print(is_discharging); // Serial.print(F(" level_difference: ")); // Serial.print(level_difference); // Serial.print(F(" BATTERY_LVL_CHANGE_THRESHOLD: ")); // Serial.println(BATTERY_LVL_CHANGE_THRESHOLD); is_discharging = get_battery_evolution(&level_difference, percent_level); if (level_difference >= BATTERY_LVL_CHANGE_THRESHOLD) { //Serial.print(F(" Setting battery level ...")); lib_aci_set_local_data(aci_stat, PIPE_BATTERY_BATTERY_LEVEL_SET, &percent_level, sizeof(percent_level)); if(lib_aci_is_pipe_available(aci_stat, PIPE_BATTERY_BATTERY_LEVEL_TX)) { //Serial.print(F(" Sending battery level over the air ...")); if (lib_aci_send_data(PIPE_BATTERY_BATTERY_LEVEL_TX, &percent_level, sizeof(percent_level))) { aci_stat->data_credit_available--; } } previous_battery_level = percent_level; } }
size_t Adafruit_BLE_UART::write(uint8_t buffer) { bool status = false; size_t sent = 0; #ifdef BLE_RW_DEBUG Serial.print(F("\tWriting one byte 0x")); Serial.println(buffer, HEX); #endif if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) { // Get back whether we actually sent this bit or not status = lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &buffer, 1); // Validate that we actually sent the bit then // move the counter if ( status ) { aci_state.data_credit_available--; sent = 1; } delay(BLE_W_DELAY); // required delay between sends return sent; } pollACI(); return sent; }
size_t Adafruit_BLE_UART::write(uint8_t * buffer, uint8_t len) { uint8_t bytesThisPass, sent = 0; #ifdef BLE_RW_DEBUG Serial.print(F("\tWriting out to BTLE:")); for (uint8_t i=0; i<len; i++) { Serial.print(F(" 0x")); Serial.print(buffer[i], HEX); } Serial.println(); #endif while(len) { // Parcelize into chunks bytesThisPass = len; if(bytesThisPass > ACI_PIPE_TX_DATA_MAX_LEN) bytesThisPass = ACI_PIPE_TX_DATA_MAX_LEN; if(!lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) { pollACI(); continue; } lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &buffer[sent], bytesThisPass); aci_state.data_credit_available--; delay(35); // required delay between sends if(!(len -= bytesThisPass)) break; sent += bytesThisPass; } return sent; }
size_t Adafruit_BLE_UART::write(uint8_t buffer) { /* Blocking delay waiting for available credit(s) */ while (0 == aci_state.data_credit_available) { pollACI(); delay(10); } #ifdef BLE_RW_DEBUG Serial.print(F("\tWriting one byte 0x")); Serial.println(buffer, HEX); #endif if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) { lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &buffer, 1); aci_state.data_credit_available--; delay(35); // required delay between sends return 1; } pollACI(); return 0; }
void ble_do_events() { spi_old = SPCR; SPI.setBitOrder(LSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV8); SPI.setDataMode(SPI_MODE0); if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) { if(tx_buffer_len > 0) { unsigned char Index = 0; while(tx_buffer_len > 20) { if(true == lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &tx_buff[Index], 20)) { Serial.print("data transmmit success! Length: "); Serial.print(20, DEC); Serial.print(" "); } else { Serial.println("data transmmit fail !"); } tx_buffer_len -= 20; Index += 20; aci_state.data_credit_available--; Serial.print("Data Credit available: "); Serial.println(aci_state.data_credit_available,DEC); ack = 0; while (!ack) process_events(); } if(true == lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX,& tx_buff[Index], tx_buffer_len)) { Serial.print("data transmmit success! Length: "); Serial.print(tx_buffer_len, DEC); Serial.print(" "); } else { Serial.println("data transmmit fail !"); } tx_buffer_len = 0; aci_state.data_credit_available--; Serial.print("Data Credit available: "); Serial.println(aci_state.data_credit_available,DEC); ack = 0; while (!ack) process_events(); } } process_events(); SPCR = spi_old; }
void battery_on_pipe_status(aci_state_t *aci_stat) { if (percent_level_on_connect != battery_level_on_disconnect) { if(lib_aci_is_pipe_available(aci_stat, PIPE_BATTERY_BATTERY_LEVEL_TX)) { lib_aci_send_data(PIPE_BATTERY_BATTERY_LEVEL_TX, &percent_level_on_connect, sizeof(percent_level_on_connect)); } } }
void RCTelemetry_BLE::sendRSSI(uint8_t rssi) { if (lib_aci_is_pipe_available(&aci_state, PIPE_RC_TELEMETRY_RSSI_TX)) { lib_aci_send_data(PIPE_RC_TELEMETRY_RSSI_TX, &rssi, 1); aci_state.data_credit_available--; delay(35); // required delay between sends return; } pollACI(); // TODO: how to handle when pipe is not available? retry? cache for later? warning on overriding cache? }
bool nRF8001MeteoStation::send_humidity(float p_humidity) { if ((m_ack_humidity_measure_pending == false) && (p_humidity != m_last_hum)) { if (lib_aci_is_pipe_available(&aci_state, PIPE_METEO_STATION_HUMIDITY_MEASUREMENT_TX_ACK)) { m_hum_measure.measurement[0] = 0; m_hum_measure.measurement[1] = p_humidity; m_ack_humidity_measure_pending = lib_aci_send_data(PIPE_METEO_STATION_HUMIDITY_MEASUREMENT_TX_ACK, (uint8_t *)&m_hum_measure, PIPE_METEO_STATION_HUMIDITY_MEASUREMENT_TX_ACK_MAX_SIZE); if (m_ack_humidity_measure_pending) m_last_hum = p_humidity; return m_ack_humidity_measure_pending; } } return false; }
void ble_do_events() { if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) { if(tx_buffer_len > 0) { unsigned char Index = 0; while(tx_buffer_len > 20) { if(true == lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &tx_buff[Index], 20)) { Serial.print("data transmmit success! Length: "); Serial.print(20, DEC); Serial.print(" "); } else { Serial.println("data transmmit fail !"); } tx_buffer_len -= 20; Index += 20; aci_state.data_credit_available--; Serial.print("Data Credit available: "); Serial.println(aci_state.data_credit_available,DEC); ack = 0; while (!ack) process_events(); } if(true == lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX,& tx_buff[Index], tx_buffer_len)) { Serial.print("data transmmit success! Length: "); Serial.print(tx_buffer_len, DEC); Serial.print(" "); } else { Serial.println("data transmmit fail !"); } tx_buffer_len = 0; aci_state.data_credit_available--; Serial.print("Data Credit available: "); Serial.println(aci_state.data_credit_available,DEC); ack = 0; while (!ack) process_events(); } } process_events(); }
bool Adafruit_BLE_UART::uart_tx(uint8_t *buffer, uint8_t buffer_len) { bool status = false; if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (aci_state.data_credit_available >= 1)) { status = lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, buffer, buffer_len); if (status) { aci_state.data_credit_available--; } } return status; }
int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer initializeClocks(); InitializeButton(); InitializeLeds(); //This will reset the nRF8001. ACI Device Started Event is generated by the nRF8001 device //as soon as the reset is complete hal_aci_tl_init(); // Reset nRF8001 resetDevice(); _BIS_SR(GIE); begin_BLE(&aci_state); // Main application loop for (;;) { //_BIS_SR(LPM0_bits + GIE); // Enter LPM0 w/interrupt _nop(); // For debugger //Not entirely sure if any of this if statement needs to be here... if(rdynFlag == 1) { rdynFlag = 0; m_rdy_line_handle(); } pollACI(&aci_state, &aci_data, &aci_cmd); state = getState(); if ((getState() == ACI_EVT_CONNECTED) && (!ctr) && lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) { //make sure pipe is available //#define UART #ifdef UART write("80 98 37 998", 12, &aci_state, &aci_data, &aci_cmd); #else write(data, 6, &aci_state, &aci_data, &aci_cmd); #endif //lib_aci_get_battery_level(); } ctr++; } }
void update_battery(aci_state_t * aci_state, uint8_t percent_level) { uint8_t level_difference = 0; get_battery_evolution(&level_difference, percent_level); if (level_difference >= BATTERY_LVL_CHANGE_THRESHOLD) { lib_aci_set_local_data(aci_state, PIPE_BATTERY_BATTERY_LEVEL_SET, &percent_level, sizeof(percent_level)); //Set battery level previous_battery_level = percent_level; if(lib_aci_is_pipe_available(aci_state, PIPE_BATTERY_BATTERY_LEVEL_TX)) { if(aci_state->data_credit_available > 0) { send_battery_update(aci_state, percent_level); } } } }
bool nRF8001MeteoStation::send_temperature(float p_temperature) { // if the last sending was acquitted and the temperature to send is different // from the earlier temperature, it checks if the pipe is available if ((m_ack_temperature_measure_pending == false) && (p_temperature != m_last_temp)) { if (lib_aci_is_pipe_available(&aci_state, PIPE_METEO_STATION_TEMPERATURE_MEASUREMENT_TX_ACK)) { // sets the structure with the corresponding flags (cf. .h) and the temperature with the given parameter m_temp_measure.flags = TEMPERATURE_MEASUREMENT_FLAGS; m_temp_measure.measurement[0] = p_temperature; m_temp_measure.measurement[1] = 0; m_temp_measure.measurement[2] = 0; m_temp_measure.measurement[3] = 0; // sends the temperature structure (Pipe, structure address, size) m_ack_temperature_measure_pending = lib_aci_send_data(PIPE_METEO_STATION_TEMPERATURE_MEASUREMENT_TX_ACK, (uint8_t *)&m_temp_measure, 5); // if the value was sent correctly, it stores the temperature if (m_ack_temperature_measure_pending) m_last_temp = p_temperature; return m_ack_temperature_measure_pending; } } return false; }
/** * This is the default write method. * * @param buffer - the data buffer * @param length - the data length * @returns bool - the write status */ bool NRF8001Driver::write(uint8_t* buffer, uint8_t length){ // Satus container bool status = false; // Check if we have a pipe free if (lib_aci_is_pipe_available(this->_aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (this->_aci_state->data_credit_available > 0)){ // Send the data status = lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, buffer, length); // If we have a good status if (status){ // Decrease the write tokens this->_aci_state->data_credit_available--; } } // Return the status return status; }
boolean BLE::writeBufferToPipe(uint8_t *buffer, uint8_t byteCount, uint8_t pipe) { boolean success = false; if (lib_aci_is_pipe_available(&aci_state, pipe) && (aci_state.data_credit_available >= 1)) { // Serial.print(byteCount); // Serial.println(F(" bytes sent to pipe")); success = lib_aci_send_data(pipe, buffer, byteCount); if (success) { aci_state.data_credit_available--; waitForDataCredit(); } else Serial.println(F("lib_aci_send_data() failed")); } //else Serial.println(F("Pipe not available or no remaining data credits")); return success; }
/************************************************************************** * * 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; } } }
void aci_loop() { // 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; switch(aci_evt->evt_opcode) { /** As soon as you reset the nRF8001 you will get an ACI Device Started Event */ case ACI_EVT_DEVICE_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: /** When the device is in the setup mode */ Serial.println(F("Evt Device Started: Setup")); if (ACI_STATUS_TRANSACTION_COMPLETE != do_aci_setup(&aci_state)) { Serial.println(F("Error in ACI Setup")); } break; case ACI_DEVICE_STANDBY: Serial.println(F("Evt Device Started: Standby")); { //Manage the bond in EEPROM of the AVR { uint8_t eeprom_status = 0; eeprom_status = EEPROM.read(0); if (eeprom_status != 0x00) { Serial.println(F("Previous Bond present. Restoring")); Serial.println(F("Using existing bond stored in EEPROM.")); Serial.println(F(" To delete the bond stored in EEPROM, connect Pin 6 to 3.3v and Reset.")); Serial.println(F(" Make sure that the bond on the phone/PC is deleted as well.")); //We must have lost power and restarted and must restore the bonding infromation using the ACI Write Dynamic Data if (ACI_STATUS_TRANSACTION_COMPLETE == bond_data_restore(&aci_state, eeprom_status, &bonded_first_time)) { Serial.println(F("Bond restored successfully")); } else { Serial.println(F("Bond restore failed. Delete the bond and try again.")); } } } // Start bonding as all proximity devices need to be bonded to be usable if (ACI_BOND_STATUS_SUCCESS != aci_state.bonded) { lib_aci_bond(180/* in seconds */, 0x0050 /* advertising interval 50ms*/); Serial.println(F("No Bond present in EEPROM.")); Serial.println(F("Advertising started : Waiting to be connected and bonded")); } else { //connect to an already bonded device //Use lib_aci_direct_connect for faster re-connections with PC, not recommended to use with iOS/OS X lib_aci_connect(100/* in seconds */, 0x0020 /* advertising interval 20ms*/); Serial.println(F("Already bonded : Advertising started : Waiting to be connected")); } } break; } } break; //ACI Device Started Event case 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 Serial.print(F("ACI Command ")); Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX); Serial.println(F("Evt Cmd respone: Error. Arduino is in an while(1); loop")); while (1); } if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode) { //Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET, (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t)); } break; case ACI_EVT_CONNECTED: Serial.println(F("Evt Connected")); Counter = BUZZER_OFF; aci_state.data_credit_available = aci_state.data_credit_total; timing_change_done = false; /* Get the device version of the nRF8001 and store it in the Hardware Revision String */ lib_aci_device_version(); break; case ACI_EVT_BOND_STATUS: aci_state.bonded = aci_evt->params.bond_status.status_code; break; case ACI_EVT_PIPE_STATUS: Serial.println(F("Evt Pipe Status")); //Link is encrypted when the PIPE_LINK_LOSS_ALERT_ALERT_LEVEL_RX_ACK_AUTO is available if ((false == timing_change_done) && lib_aci_is_pipe_available(&aci_state, PIPE_LINK_LOSS_ALERT_ALERT_LEVEL_RX_ACK_AUTO)) { lib_aci_change_timing_GAP_PPCP(); // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP. // Used to increase or decrease bandwidth timing_change_done = true; } // The pipe will be available only in an encrpyted link to the phone if ((ACI_BOND_STATUS_SUCCESS == aci_state.bonded) && (lib_aci_is_pipe_available(&aci_state, PIPE_LINK_LOSS_ALERT_ALERT_LEVEL_RX_ACK_AUTO)) && (lib_aci_is_pipe_available(&aci_state, PIPE_IMMEDIATE_ALERT_ALERT_LEVEL_RX))) { //Note: This may be called multiple times after the Arduino has connected to the right phone Serial.println(F("phone Detected.")); Serial.println(F("Do more stuff here. when your phone is detected")); // TODO: Add something here!! } break; case ACI_EVT_TIMING: Serial.println(F("Evt link connection interval changed")); //Disconnect as soon as we are bonded and required pipes are available //This is used to store the bonding info on disconnect and then re-connect to verify the bond if((ACI_BOND_STATUS_SUCCESS == aci_state.bonded) && (true == bonded_first_time) && (GAP_PPCP_MAX_CONN_INT >= aci_state.connection_interval) && (GAP_PPCP_MIN_CONN_INT <= aci_state.connection_interval) && //Timing change already done: Provide time for the the peer to finish (lib_aci_is_pipe_available(&aci_state, PIPE_LINK_LOSS_ALERT_ALERT_LEVEL_RX_ACK_AUTO)) && (lib_aci_is_pipe_available(&aci_state, PIPE_IMMEDIATE_ALERT_ALERT_LEVEL_RX))) { lib_aci_disconnect(&aci_state, ACI_REASON_TERMINATE); } break; case ACI_EVT_DISCONNECTED: Serial.println(F("Evt Disconnected. Link Lost or Advertising timed out")); if (ACI_BOND_STATUS_SUCCESS == aci_state.bonded) { if (ACI_STATUS_EXTENDED == aci_evt->params.disconnected.aci_status) //Link was disconnected { if (bonded_first_time) { bonded_first_time = false; //Store away the dynamic data of the nRF8001 in the Flash or EEPROM of the MCU // so we can restore the bond information of the nRF8001 in the event of power loss if (bond_data_read_store(&aci_state)) { Serial.println(F("Dynamic Data read and stored successfully")); } } if (0x24 == aci_evt->params.disconnected.btle_status) { //The error code appears when phone or Arduino has deleted the pairing/bonding information. //The Arduino stores the bonding information in EEPROM, which is deleted only by // the user action of connecting pin 6 to 3.3v and then followed by a reset. //While deleting bonding information delete on the Arduino and on the phone. Serial.println(F("phone/Arduino has deleted the bonding/pairing information")); } proximity_disconect_evt_rcvd (aci_evt->params.disconnected.btle_status); } lib_aci_connect(180/* in seconds */, 0x0100 /* advertising interval 100ms*/); Serial.println(F("Using existing bond stored in EEPROM.")); Serial.println(F(" To delete the bond stored in EEPROM, connect Pin 6 to 3.3v and Reset.")); Serial.println(F(" Make sure that the bond on the phone/PC is deleted as well.")); Serial.println(F("Advertising started. Connecting.")); } else { //There is no existing bond. Try to bond. lib_aci_bond(180/* in seconds */, 0x0050 /* advertising interval 50ms*/); Serial.println(F("Advertising started. Bonding.")); } proximity_disconect_evt_rcvd (aci_evt->params.disconnected.btle_status); break; case ACI_EVT_DATA_RECEIVED: Serial.print(F("Pipe #")); Serial.print(aci_evt->params.data_received.rx_data.pipe_number, DEC); Serial.print(F("-> ")); Serial.println(aci_evt->params.data_received.rx_data.aci_data[0], DEC); link_loss_pipes_updated_evt_rcvd(aci_evt->params.data_received.rx_data.pipe_number, &aci_evt->params.data_received.rx_data.aci_data[0]); immediate_alert_pipes_updated_evt_rcvd(aci_evt->params.data_received.rx_data.pipe_number, &aci_evt->params.data_received.rx_data.aci_data[0]); button_alert_pipes_updated_evt_rcvd(aci_evt->params.data_received.rx_data.pipe_number, &aci_evt->params.data_received.rx_data.aci_data[0]); break; case ACI_EVT_DATA_CREDIT: 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 Serial.print(F("ACI Evt Pipe Error: Pipe #:")); Serial.print(aci_evt->params.pipe_error.pipe_number, DEC); Serial.print(F(" Pipe Error Code: 0x")); Serial.println(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; } } else { //Serial.println(F("No ACI Events available")); // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep // Arduino can go to sleep now // Wakeup from sleep from the RDYN line } }
/** * This is the default run method. */ void NRF8001Driver::run(){ // We enter the if statement only when there is a ACI event available to be processed if (lib_aci_event_get(this->_aci_state, &this->_aci_data)){ // Get the event pointer aci_evt_t* aci_evt; aci_evt = &this->_aci_data.evt; // We switch on the event opcode switch(aci_evt->evt_opcode){ /** * As soon as you reset the nRF8001 you will get an ACI Device Started Event */ case ACI_EVT_DEVICE_STARTED: // Get the number of credits this->_aci_state->data_credit_total = aci_evt->params.device_started.credit_available; // Switch on the device mode switch(aci_evt->params.device_started.device_mode){ // In setup mode case ACI_DEVICE_SETUP: #ifdef DEBUG Serial.println(F("Evt Device Started: Setup")); #endif // A setup must to issued before use this->_setup_required = true; break; // In standby mode case ACI_DEVICE_STANDBY: #ifdef DEBUG Serial.println(F("Evt Device Started: Standby")); #endif // Looking for a device by sending radio advertisements // When the device connects to us we will get an ACI_EVT_CONNECTED event from the nRF8001 if (aci_evt->params.device_started.hw_error){ delay(20); //Magic number used to make sure the HW error event is handled correctly. }else{ // Connect lib_aci_connect(180/* in seconds */, 0x0050 /* advertising interval 50ms*/); #ifdef DEBUG Serial.println(F("Advertising process started")); #endif } break; } break; /** * If we get a command response */ case 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 #ifdef DEBUG Serial.print(F("ACI Command ")); Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX); Serial.print(F("Evt Cmd respone: Status ")); Serial.println(aci_evt->params.cmd_rsp.cmd_status, HEX); #endif } // If we get a Device Version request if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode){ // Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic lib_aci_set_local_data(this->_aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET, (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t)); } break; /** * If we get a connected event */ case ACI_EVT_CONNECTED: // UART setup is complete #ifdef DEBUG Serial.println(F("Evt Connected")); #endif this->_uart_over_ble_init(); this->_timing_change_done = false; this->_aci_state->data_credit_available = this->_aci_state->data_credit_total; /** * Get the device version of the nRF8001 and store it in the Hardware Revision String */ lib_aci_device_version(); break; /** * If we get a pipe status request */ case ACI_EVT_PIPE_STATUS: #ifdef DEBUG Serial.println(F("Evt Pipe Status")); #endif // Check the pipes if (lib_aci_is_pipe_available(this->_aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == this->_timing_change_done)){ // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP. // Used to increase or decrease bandwidth lib_aci_change_timing_GAP_PPCP(); this->_timing_change_done = true; } break; /** * If we get a timing change request */ case ACI_EVT_TIMING: #ifdef DEBUG Serial.println(F("Evt link connection interval changed")); #endif // Set the new timing lib_aci_set_local_data(this->_aci_state, PIPE_UART_OVER_BTLE_UART_LINK_TIMING_CURRENT_SET, (uint8_t *)&(aci_evt->params.timing.conn_rf_interval), /* Byte aligned */ PIPE_UART_OVER_BTLE_UART_LINK_TIMING_CURRENT_SET_MAX_SIZE); break; /** * If we get disconnected status */ case ACI_EVT_DISCONNECTED: #ifdef DEBUG Serial.println(F("Evt Disconnected/Advertising timed out")); #endif // Start advertising lib_aci_connect(180/* in seconds */, 0x0100 /* advertising interval 100ms*/); break; /** * If we get data from the remote node */ case ACI_EVT_DATA_RECEIVED: #ifdef DEBUG Serial.print(F("Pipe Number: ")); Serial.println(aci_evt->params.data_received.rx_data.pipe_number, DEC); #endif // If we have received data from the rx pipe if (PIPE_UART_OVER_BTLE_UART_RX_RX == aci_evt->params.data_received.rx_data.pipe_number){ // Reset the buffer memory memset(this->_uart_buffer.data, 0x00, sizeof(this->_uart_buffer)); // Reset the length this->_uart_buffer.length = 0; // Store the data received into a buffer type for(register uint8_t i = 0; i < aci_evt->len - 2; i++){ this->_uart_buffer.data[i] = aci_evt->params.data_received.rx_data.aci_data[i]; this->_uart_buffer.length ++; } #ifdef DEBUG Serial.print("Read data: "); Serial.write((uint8_t*)this->_uart_buffer.data, this->_uart_buffer.length); Serial.println(); #endif // Put the data within the ring buffer for(register uint8_t i = 0; i < this->_uart_buffer.length; i ++){ this->_utils->ring_buffer.put(this->_uart_buffer.data[i]); } } // If we got a control point byte if (PIPE_UART_OVER_BTLE_UART_CONTROL_POINT_RX == aci_evt->params.data_received.rx_data.pipe_number){ // We process the token this->_uart_process_control_point(&aci_evt->params.data_received.rx_data.aci_data[0], aci_evt->len - 2); //Subtract for Opcode and Pipe number } break; /** * If we get a data credit token */ case ACI_EVT_DATA_CREDIT: // We add a credit token to the queue this->_aci_state->data_credit_available += aci_evt->params.data_credit.credit; break; /** * If we get a pipe error */ case ACI_EVT_PIPE_ERROR: // See the appendix in the nRF8001 Product Specification for details on the error codes // 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){ this->_aci_state->data_credit_available++; } break; /** * If we get a hardware error */ case ACI_EVT_HW_ERROR: #ifdef DEBUG Serial.print(F("HW error: ")); Serial.println(aci_evt->params.hw_error.line_num, DEC); #endif // Restart the adversiting mode... lib_aci_connect(180/* in seconds */, 0x0050 /* advertising interval 50ms*/); break; } // End switch } // End If /** * If 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(this->_setup_required){ // If we setup properly if (SETUP_SUCCESS == do_aci_setup(this->_aci_state)) { this->_setup_required = false; } } }
static void process_events() { // 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; switch(aci_evt->evt_opcode) { /* As soon as you reset the nRF8001 you will get an ACI Device Started Event */ case ACI_EVT_DEVICE_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: /* When the device is in the setup mode*/ Serial.println(F("Evt Device Started: Setup")); if (ACI_STATUS_TRANSACTION_COMPLETE != do_aci_setup(&aci_state)) { Serial.println(F("Error in ACI Setup")); } break; case ACI_DEVICE_STANDBY: Serial.println(F("Evt Device Started: Standby")); //Looking for an iPhone by sending radio advertisements //When an iPhone connects to us we will get an ACI_EVT_CONNECTED event from the nRF8001 lib_aci_set_local_data(&aci_state, PIPE_GAP_DEVICE_NAME_SET , (uint8_t *)&device_name , strlen(device_name)); lib_aci_connect(180/* in seconds */, 0x0050 /* advertising interval 50ms*/); Serial.println(F("Advertising started")); break; } break; //ACI Device Started Event case 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 Serial.print(F("ACI Command ")); Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX); Serial.println(F("Evt Cmd respone: Error. Arduino is in an while(1); loop")); while (1); } if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode) { //Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET, (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t)); } break; case ACI_EVT_CONNECTED: is_connected = 1; Serial.println(F("Evt Connected")); aci_state.data_credit_available = aci_state.data_credit_total; /*Get the device version of the nRF8001 and store it in the Hardware Revision String*/ lib_aci_device_version(); break; case ACI_EVT_PIPE_STATUS: Serial.println(F("Evt Pipe Status")); if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == timing_change_done)) { lib_aci_change_timing_GAP_PPCP(); // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP. // Used to increase or decrease bandwidth timing_change_done = true; } break; case ACI_EVT_TIMING: Serial.println(F("Evt link connection interval changed")); break; case ACI_EVT_DISCONNECTED: is_connected = 0; ack = 1; Serial.println(F("Evt Disconnected/Advertising timed out")); lib_aci_connect(180/* in seconds */, 0x0100 /* advertising interval 100ms*/); Serial.println(F("Advertising started")); break; case ACI_EVT_DATA_RECEIVED: for(int i=0; i<aci_evt->len - 2; i++) { if(rx_buffer_len == MAX_RX_BUFF) { break; } else { if(p_back == &rx_buff[MAX_RX_BUFF]) { p_back = &rx_buff[0]; } *p_back = aci_evt->params.data_received.rx_data.aci_data[i]; rx_buffer_len++; p_back++; } } break; case ACI_EVT_DATA_CREDIT: aci_state.data_credit_available = aci_state.data_credit_available + aci_evt->params.data_credit.credit; Serial.print("ACI_EVT_DATA_CREDIT "); Serial.print("Data Credit available: "); Serial.println(aci_state.data_credit_available,DEC); ack=1; break; case ACI_EVT_PIPE_ERROR: //See the appendix in the nRF8001 Product Specication for details on the error codes Serial.print(F("ACI Evt Pipe Error: Pipe #:")); Serial.print(aci_evt->params.pipe_error.pipe_number, DEC); Serial.print(F(" Pipe Error Code: 0x")); Serial.println(aci_evt->params.pipe_error.error_code, HEX); //Increment the credit available as the data packet was not sent aci_state.data_credit_available++; Serial.print("Data Credit available: "); Serial.println(aci_state.data_credit_available,DEC); break; } } else { //Serial.println(F("No ACI Events available")); // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep // Arduino can go to sleep now // Wakeup from sleep from the RDYN line } }
void aci_loop(int *flag) { // 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; DBPRINTLN("There is an ACI Events available"); aci_evt = &aci_data.evt; switch(aci_evt->evt_opcode) { /* As soon as you reset the nRF8001 you will get an ACI Device Started Event */ case ACI_EVT_DEVICE_STARTED: { aci_state.data_credit_total = aci_evt->params.device_started.credit_available; switch(aci_evt->params.device_started.device_mode) { /** When the device is in the setup mode */ case ACI_DEVICE_SETUP: DBPRINTLN("Evt Device Started: Setup"); if (ACI_STATUS_TRANSACTION_COMPLETE != do_aci_setup(&aci_state)) DBPRINTLN("Error in ACI Setup"); break; case ACI_DEVICE_STANDBY: DBPRINTLN("Evt Device Started: Standby"); //Looking for an iPhone by sending radio advertisements //When an iPhone connects to us we will get an ACI_EVT_CONNECTED event from the nRF8001 lib_aci_connect(180/* in seconds */, 0x0050 /* advertising interval 50ms*/); DBPRINTLN("Advertising started"); break; } } break; //ACI Device Started Event case ACI_EVT_CMD_RSP: //If an ACI command response event comes with an error -> stop if (ACI_STATUS_TRANSACTION_CONTINUE == aci_evt->params.cmd_rsp.cmd_status) { DBPRINTLN("Reading/Writing dynamic data..."); } else if (ACI_STATUS_TRANSACTION_COMPLETE == aci_evt->params.cmd_rsp.cmd_status) { DBPRINTLN("Reading/Writing dynamic data finished."); } else 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 DBPRINT("Error ACI Command "); Serial.print(aci_evt->params.cmd_rsp.cmd_opcode, HEX); DBPRINT(" Evt Cmd respone error code: "); Serial.println(aci_evt->params.cmd_rsp.cmd_status, HEX); //while (1); } // react to different command responses switch (aci_evt->params.cmd_rsp.cmd_opcode) { case ACI_CMD_GET_DEVICE_VERSION: // Debug print DBPRINTLN("Debug: printting configuration id, aci version, setup format, id, and status from the cmd rsp opcode:"); DBPRINTLN(aci_evt->params.cmd_rsp.params.get_device_version.configuration_id); DBPRINTLN(aci_evt->params.cmd_rsp.params.get_device_version.aci_version); DBPRINTLN(aci_evt->params.cmd_rsp.params.get_device_version.setup_format); DBPRINTLN(aci_evt->params.cmd_rsp.params.get_device_version.setup_id); DBPRINTLN(aci_evt->params.cmd_rsp.params.get_device_version.setup_status); //Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET, (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t)); break; case ACI_CMD_GET_DEVICE_ADDRESS: // Debug print DBPRINTLN("Debug: printting device address, and address type:"); DBPRINTLN(aci_evt->params.cmd_rsp.params.get_device_address.bd_addr_own[0]); DBPRINTLN(aci_evt->params.cmd_rsp.params.get_device_address.bd_addr_type); break; case ACI_CMD_GET_TEMPERATURE: // Debug print DBPRINTLN("Debug: printting device temperature:"); DBPRINTLN(aci_evt->params.cmd_rsp.params.get_temperature.temperature_value/4); break; case ACI_CMD_READ_DYNAMIC_DATA: // Debug print DBPRINT("Debug: dynamic data:"); DBPRINTLN(aci_evt->params.cmd_rsp.params.get_temperature.temperature_value/4); break; } break; case ACI_EVT_CONNECTED: DBPRINTLN("Evt Connected"); aci_state.data_credit_available = aci_state.data_credit_total; // Get the device version of the nRF8001 and store it in the Hardware Revision String lib_aci_device_version(); break; case ACI_EVT_PIPE_STATUS: DBPRINTLN("Evt Pipe Status"); if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == timing_change_done)) { lib_aci_change_timing_GAP_PPCP(); // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP. // Used to increase or decrease bandwidth timing_change_done = true; } if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) { DBPRINTLN("UART pipe over BLE is available"); *flag = 1; } break; case ACI_EVT_TIMING: DBPRINTLN("Evt link connection interval changed"); break; case ACI_EVT_DISCONNECTED: DBPRINTLN("Evt Disconnected/Advertising timed out"); lib_aci_connect(180/* in seconds */, 0x0100 /* advertising interval 100ms*/); DBPRINTLN("Advertising started"); *flag = 0; break; case ACI_EVT_DATA_RECEIVED: DBPRINT("UART RX: 0x"); Serial.print(aci_evt->params.data_received.rx_data.pipe_number, HEX); { DBPRINT(" Data(Hex) : "); for(int i=0; i<aci_evt->len - 2; i++) { Serial.print(aci_evt->params.data_received.rx_data.aci_data[i], HEX); uart_buffer[i] = aci_evt->params.data_received.rx_data.aci_data[i]; DBPRINT(" "); } uart_buffer_len = aci_evt->len - 2; } DBPRINT("I got the request"); break; case ACI_EVT_DATA_CREDIT: 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 DBPRINT("ACI Evt Pipe Error: Pipe #:"); DBPRINT(aci_evt->params.pipe_error.pipe_number); DBPRINT(" Pipe Error Code: 0x"); DBPRINTLN(aci_evt->params.pipe_error.error_code); //Increment the credit available as the data packet was not sent aci_state.data_credit_available++; break; default: DBPRINTLN("Unrecognized Event"); break; } } else { //DBPRINTLN(F("No ACI Events available")); // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep // Arduino can go to sleep now // Wakeup from sleep from the RDYN line } }
void Adafruit_BLE_UART::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; switch(aci_evt->evt_opcode) { /** As soon as you reset the nRF8001 you will get an ACI Device Started Event */ case ACI_EVT_DEVICE_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: /** When the device is in the setup mode */ Serial.println(F("Evt Device Started: Setup")); setup_required = true; break; case ACI_DEVICE_STANDBY: Serial.println(F("Evt Device Started: Standby")); //Looking for an iPhone by sending radio advertisements //When an iPhone connects to us we will get an ACI_EVT_CONNECTED event from the nRF8001 if (aci_evt->params.device_started.hw_error) { delay(20); //Handle the HW error event correctly. if (debugMode) { Serial.println(F("Error in ACI Setup")); } } else { lib_aci_connect(0/* in seconds : 0 means forever */, 0x0050 /* advertising interval 50ms*/); defaultACICallback(ACI_EVT_DEVICE_STARTED); Serial.println(F("Advertising started : Tap Connect on the nRF UART app or client application")); } break; } } break; //ACI Device Started Event case 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 Serial.print(F("ACI Command ")); Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX); Serial.print(F("Evt Cmd respone: Status ")); Serial.println(aci_evt->params.cmd_rsp.cmd_status, HEX); } if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode) { //Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET, (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t)); } break; case ACI_EVT_CONNECTED: Serial.println(F("Evt Connected")); uart_over_ble_init(); timing_change_done = false; aci_state.data_credit_available = aci_state.data_credit_total; /* Get the device version of the nRF8001 and store it in the Hardware Revision String */ lib_aci_device_version(); defaultACICallback(ACI_EVT_CONNECTED); break; case ACI_EVT_PIPE_STATUS: Serial.println(F("Evt Pipe Status")); if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == timing_change_done)) { lib_aci_change_timing_GAP_PPCP(); // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP. // Used to increase or decrease bandwidth timing_change_done = true; } break; case ACI_EVT_TIMING: Serial.println(F("Evt link connection interval changed")); lib_aci_set_local_data(&aci_state, PIPE_UART_OVER_BTLE_UART_LINK_TIMING_CURRENT_SET, (uint8_t *)&(aci_evt->params.timing.conn_rf_interval), /* Byte aligned */ PIPE_UART_OVER_BTLE_UART_LINK_TIMING_CURRENT_SET_MAX_SIZE); break; case ACI_EVT_DISCONNECTED: defaultACICallback(ACI_EVT_DISCONNECTED); Serial.println(F("Evt Disconnected/Advertising timed out")); lib_aci_connect(0/* in seconds : 0 means forever */, 0x0050 /* advertising interval 50ms*/); defaultACICallback(ACI_EVT_DEVICE_STARTED); Serial.println(F("Advertising started. Tap Connect on the nRF UART app")); break; case ACI_EVT_DATA_RECEIVED: Serial.print(F("Pipe Number: ")); Serial.println(aci_evt->params.data_received.rx_data.pipe_number, DEC); defaultRX(aci_evt->params.data_received.rx_data.aci_data, aci_evt->len - 2); if (rx_event) { rx_event(aci_evt->params.data_received.rx_data.aci_data, aci_evt->len - 2); } if (PIPE_UART_OVER_BTLE_UART_RX_RX == aci_evt->params.data_received.rx_data.pipe_number) { Serial.print(F(" Data(Hex) : ")); for(int i=0; i<aci_evt->len - 2; i++) { Serial.print((char)aci_evt->params.data_received.rx_data.aci_data[i]); uart_buffer[i] = aci_evt->params.data_received.rx_data.aci_data[i]; Serial.print(F(" ")); } uart_buffer_len = aci_evt->len - 2; Serial.println(F("")); if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) { /*Do this to test the loopback otherwise comment it out*/ /* if (!uart_tx(&uart_buffer[0], aci_evt->len - 2)) { Serial.println(F("UART loopback failed")); } else { Serial.println(F("UART loopback OK")); } */ } } if (PIPE_UART_OVER_BTLE_UART_CONTROL_POINT_RX == aci_evt->params.data_received.rx_data.pipe_number) { uart_process_control_point_rx(&aci_evt->params.data_received.rx_data.aci_data[0], aci_evt->len - 2); //Subtract for Opcode and Pipe number } break; case ACI_EVT_DATA_CREDIT: 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 if ( debugMode ) { Serial.print(F("ACI Evt Pipe Error: Pipe #:")); Serial.print(aci_evt->params.pipe_error.pipe_number, DEC); Serial.print(F(" Pipe Error Code: 0x")); Serial.println(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_HW_ERROR: Serial.print(F("HW error: ")); Serial.println(aci_evt->params.hw_error.line_num, DEC); for(uint8_t counter = 0; counter <= (aci_evt->len - 3); counter++) { Serial.write(aci_evt->params.hw_error.file_name[counter]); //uint8_t file_name[20]; } Serial.println(); lib_aci_connect(0/* in seconds, 0 means forever */, 0x0050 /* advertising interval 50ms*/); Serial.println(F("Advertising started. Tap Connect on the nRF UART app")); break; } } else { if ( debugMode ) { //Serial.println(F("No ACI Events available")); } // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep // Arduino can go to sleep now // Wakeup from sleep from the RDYN line } /* 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) { if (SETUP_SUCCESS == do_aci_setup(&aci_state)) { setup_required = false; } } }
bool GoosciBleGatt::isReadyToSend() { return lib_aci_is_pipe_available(&aci_state, PIPE_GOOSCI_SENSOR_VALUE_TX) && aci_state.data_credit_available > 0; }
/** * 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; }
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; }
void Adafruit_BLE_UART::pollACI() { // 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; switch(aci_evt->evt_opcode) { /* As soon as you reset the nRF8001 you will get an ACI Device Started Event */ case ACI_EVT_DEVICE_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: /* Device is in setup mode! */ if (ACI_STATUS_TRANSACTION_COMPLETE != do_aci_setup(&aci_state)) { if (debugMode) { Serial.println(F("Error in ACI Setup")); } } break; case ACI_DEVICE_STANDBY: /* Start advertising ... first value is advertising time in seconds, the */ /* second value is the advertising interval in 0.625ms units */ if (device_name[0] != 0x00) { /* Update the device name */ lib_aci_set_local_data(&aci_state, PIPE_GAP_DEVICE_NAME_SET , (uint8_t *)&device_name, strlen(device_name)); } lib_aci_connect(adv_timeout, adv_interval); defaultACICallback(ACI_EVT_DEVICE_STARTED); if (aci_event) aci_event(ACI_EVT_DEVICE_STARTED); } } break; case 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_SUCCESS for a successful command if (debugMode) { Serial.print(F("ACI Command ")); Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX); Serial.println(F("Evt Cmd respone: Error. Arduino is in an while(1); loop")); } while (1); } if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode) { // Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET, (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t)); } break; case ACI_EVT_CONNECTED: aci_state.data_credit_available = aci_state.data_credit_total; /* Get the device version of the nRF8001 and store it in the Hardware Revision String */ lib_aci_device_version(); defaultACICallback(ACI_EVT_CONNECTED); if (aci_event) aci_event(ACI_EVT_CONNECTED); case ACI_EVT_PIPE_STATUS: if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == timing_change_done)) { lib_aci_change_timing_GAP_PPCP(); // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP. // Used to increase or decrease bandwidth timing_change_done = true; } break; case ACI_EVT_TIMING: /* Link connection interval changed */ break; case ACI_EVT_DISCONNECTED: /* Restart advertising ... first value is advertising time in seconds, the */ /* second value is the advertising interval in 0.625ms units */ defaultACICallback(ACI_EVT_DISCONNECTED); if (aci_event) aci_event(ACI_EVT_DISCONNECTED); lib_aci_connect(adv_timeout, adv_interval); defaultACICallback(ACI_EVT_DEVICE_STARTED); if (aci_event) aci_event(ACI_EVT_DEVICE_STARTED); break; case ACI_EVT_DATA_RECEIVED: defaultRX(aci_evt->params.data_received.rx_data.aci_data, aci_evt->len - 2); if (rx_event) rx_event(aci_evt->params.data_received.rx_data.aci_data, aci_evt->len - 2); break; case ACI_EVT_DATA_CREDIT: 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 */ if (debugMode) { Serial.print(F("ACI Evt Pipe Error: Pipe #:")); Serial.print(aci_evt->params.pipe_error.pipe_number, DEC); Serial.print(F(" Pipe Error Code: 0x")); Serial.println(aci_evt->params.pipe_error.error_code, HEX); } /* Increment the credit available as the data packet was not sent */ aci_state.data_credit_available++; break; } } else { // Serial.println(F("No ACI Events available")); // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep // Arduino can go to sleep now // Wakeup from sleep from the RDYN line } }
static void process_events() { 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; switch(aci_evt->evt_opcode) { /* As soon as you reset the nRF8001 you will get an ACI Device Started Event */ case ACI_EVT_DEVICE_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: /* When the device is in the setup mode*/ Serial.println(F("Evt Device Started: Setup")); setup_required = true; break; case ACI_DEVICE_STANDBY: Serial.println(F("Evt Device Started: Standby")); //Looking for an iPhone by sending radio advertisements //When an iPhone connects to us we will get an ACI_EVT_CONNECTED event from the nRF8001 if (aci_evt->params.device_started.hw_error) { delay(20); //Magic number used to make sure the HW error event is handled correctly. } else { lib_aci_set_local_data(&aci_state, PIPE_GAP_DEVICE_NAME_SET , (uint8_t *)&device_name , strlen(device_name)); lib_aci_connect(Adv_Timeout/* in seconds */, Adv_Interval /* advertising interval 50ms*/); Serial.println(F("Advertising started")); } break; } break; //ACI Device Started Event case 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 Serial.print(F("ACI Command ")); Serial.println(aci_evt->params.cmd_rsp.cmd_opcode, HEX); Serial.print(F("Evt Cmd respone: Status ")); Serial.println(aci_evt->params.cmd_rsp.cmd_status, HEX); } if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode) { //Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET, (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t)); } else if (ACI_CMD_GET_DEVICE_ADDRESS == aci_evt->params.cmd_rsp.cmd_opcode) { memcpy(bd_addr_own, aci_evt->params.cmd_rsp.params.get_device_address.bd_addr_own, BTLE_DEVICE_ADDRESS_SIZE); bd_addr_type = aci_evt->params.cmd_rsp.params.get_device_address.bd_addr_type; addr_get = 1; Serial.print(F("Device address: ")); for(uint8_t i=0; i<BTLE_DEVICE_ADDRESS_SIZE-1; i++) { Serial.print(bd_addr_own[i], HEX); Serial.print(":"); } Serial.println(bd_addr_own[BTLE_DEVICE_ADDRESS_SIZE-1], HEX); Serial.print(F("Device address type: ")); switch(bd_addr_type) { case ACI_BD_ADDR_TYPE_PUBLIC: Serial.println(F("Public address")); break; case ACI_BD_ADDR_TYPE_RANDOM_STATIC: Serial.println(F("Random static address")); break; case ACI_BD_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE: Serial.println(F("Private resolvable address")); break; case ACI_BD_ADDR_TYPE_RANDOM_PRIVATE_UNRESOLVABLE: Serial.println(F("Private unresolvable address")); break; default: Serial.println(F("Invalid address")); } } break; case ACI_EVT_CONNECTED: is_connected = 1; Serial.println(F("Evt Connected")); timing_change_done = false; aci_state.data_credit_available = aci_state.data_credit_total; /*Get the device version of the nRF8001 and store it in the Hardware Revision String*/ lib_aci_device_version(); break; case ACI_EVT_PIPE_STATUS: Serial.println(F("Evt Pipe Status")); if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == timing_change_done)) { lib_aci_change_timing_GAP_PPCP(); // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP. // Used to increase or decrease bandwidth timing_change_done = true; } break; case ACI_EVT_TIMING: Serial.println(F("Evt link connection interval changed")); break; case ACI_EVT_DISCONNECTED: is_connected = 0; ack = 1; Serial.println(F("Evt Disconnected/Advertising timed out")); lib_aci_connect(Adv_Timeout/* in seconds */, Adv_Interval /* advertising interval 50ms*/); Serial.println(F("Advertising started")); break; case ACI_EVT_DATA_RECEIVED: Serial.print(F("Pipe Number: ")); Serial.println(aci_evt->params.data_received.rx_data.pipe_number, DEC); for(int i=0; i<aci_evt->len - 2; i++) { if(rx_buffer_len == MAX_RX_BUFF) { break; } else { if(p_back == &rx_buff[MAX_RX_BUFF]) { p_back = &rx_buff[0]; } *p_back = aci_evt->params.data_received.rx_data.aci_data[i]; rx_buffer_len++; p_back++; } } break; case ACI_EVT_DATA_CREDIT: aci_state.data_credit_available = aci_state.data_credit_available + aci_evt->params.data_credit.credit; Serial.print("ACI_EVT_DATA_CREDIT "); Serial.print("Data Credit available: "); Serial.println(aci_state.data_credit_available,DEC); ack=1; break; case ACI_EVT_PIPE_ERROR: //See the appendix in the nRF8001 Product Specication for details on the error codes Serial.print(F("ACI Evt Pipe Error: Pipe #:")); Serial.print(aci_evt->params.pipe_error.pipe_number, DEC); Serial.print(F(" Pipe Error Code: 0x")); Serial.println(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++; } Serial.print("Data Credit available: "); Serial.println(aci_state.data_credit_available,DEC); break; case ACI_EVT_HW_ERROR: Serial.print(F("HW error: ")); Serial.println(aci_evt->params.hw_error.line_num, DEC); for(uint8_t counter = 0; counter <= (aci_evt->len - 3); counter++) { Serial.write(aci_evt->params.hw_error.file_name[counter]); //uint8_t file_name[20]; } Serial.println(); lib_aci_connect(Adv_Timeout/* in seconds */, Adv_Interval /* advertising interval 50ms*/); Serial.println(F("Advertising started")); break; } } else { //Serial.println(F("No ACI Events available")); // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep // Arduino can go to sleep now // Wakeup from sleep from the RDYN line } /* 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) { if (SETUP_SUCCESS == do_aci_setup(&aci_state)) { setup_required = false; } } }