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;
}
Example #2
0
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;
}
Example #6
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;
}
Example #10
0
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;
}
Example #12
0
File: main.c Project: linkinlzm/MCU
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;
}
Example #15
0
/**
 * 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;
}
Example #16
0
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
  }
}
Example #19
0
/**
 * 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;
		}
	}
}
Example #20
0
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
			}
}
Example #21
0
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;
}
Example #24
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
  }
}
Example #27
0
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;
        }
    }
}