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
  }
}
Exemple #2
0
void ble_disconnect(void)
{
	lib_aci_disconnect(&aci_state, ACI_REASON_TERMINATE);
}
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;
}
Exemple #4
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;
}
/**
 * This method is used to generic system wide actions
 *
 * @param command						- The issued command
 */
void ConnectionProtocolHandler::server(uint8_t command, void* object){

	//! Cast the object
	ConnectionProtocolHandler* access = (ConnectionProtocolHandler*) object;

	//! We switch on the command
	switch(command){

		//! We reset the device
		case CONNECT_CALLBACK:
			
			// Set the new connection state and write the ACK
			access->_utils->connection_state = CONNECTED_STATE;
			access->_rf->write((uint8_t*)OK_CALLBACK, 0x01);
			
			#ifdef DEBUG
				Serial.println("Connected from Remote node.");
			#endif
			break;

                //! We start the device
		case REBOOT_CALLBACK:
		
			// Set the new connection state and write the ACK
			access->_utils->connection_state = CLOSED_STATE;
			access->_rf->write((uint8_t*)OK_CALLBACK, 0x01);
			
			#ifdef DEBUG
				Serial.println("Rebooting...");
			#endif
			
			// Stop the main thread
            access->_utils->start_engine = false;
			
			// Disconnect and reset
			while(!lib_aci_disconnect(access->_rf->_aci_state, 
									  ACI_REASON_TERMINATE));
			while(!lib_aci_radio_reset());

			// Delay and then reboot the system
			delay(1000);
            access->_utils->reboot();
            break;

		//! We stop the device
		case DISCONNECT_CALLBACK:
		
			// Set the new connection state and write the ACK
			access->_utils->connection_state = DISCONNECTED_STATE;
			access->_rf->write((uint8_t*)OK_CALLBACK, 0x01);
			
			// Disconnect
			while(!lib_aci_disconnect(access->_rf->_aci_state,
										ACI_REASON_TERMINATE));

			#ifdef DEBUG
				Serial.println("Disconnected from Remote node.");
			#endif
			
			// We are now connected
			access->_utils->start_engine = true;
            break;
       
		//! Nothing happens
		default:
			break;
	}
}