Esempio n. 1
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;
}
/**************************************************************************
 *
 *   Handles low level ACI events, and passes them up to an application
 *   level callback when appropriate
 *
 **************************************************************************/
void GoosciBleGatt::pollACI() {
  static bool setup_required = false;

  // We enter the if statement only when there is a ACI event
  // available to be processed
  if (lib_aci_event_get(&aci_state, &aci_data)) {
    aci_evt_t *aci_evt;
    aci_evt = &aci_data.evt;
    // DEBUG_PRINTLN(F("pollACI"));
    // DEBUG_PRINT("evt opcode: ");
    // DEBUG_PRINTLN2(aci_evt->evt_opcode, HEX);
    // DEBUG_PRINT(F("State Total credit: "));
    // DEBUG_PRINTLN(aci_state.data_credit_total);
    // DEBUG_PRINT(F("State Available credit: "));
    // DEBUG_PRINTLN(aci_state.data_credit_available);
    // DEBUG_PRINT("Event Available credit: ");
    // DEBUG_PRINTLN(aci_evt->params.device_started.credit_available);
    switch (aci_evt->evt_opcode) {
      case ACI_EVT_DEVICE_STARTED: {
	// DEBUG_PRINTLN("STARTED");
        aci_state.data_credit_total =
            aci_evt->params.device_started.credit_available;
        switch (aci_evt->params.device_started.device_mode) {
          case ACI_DEVICE_SETUP: {
	    // DEBUG_PRINTLN("SETUP");
            aci_state.device_state = ACI_DEVICE_SETUP;
            setup_required = true;
            break;
          }

          case ACI_DEVICE_STANDBY: {
	    // DEBUG_PRINTLN("STANDBY");
            aci_state.device_state = ACI_DEVICE_STANDBY;

            // sleep_to_wakeup_timeout = 30;

            if (aci_evt->params.device_started.hw_error) {
              // Magic number used to make sure the HW error
              // event is handled correctly.
              delay(20);
            } else {
	      get_address();
	      // DEBUG_PRINTLN("lib_aci_connect");
              lib_aci_connect(adTimeout, adInterval);
            }
            break;
          }
          case ACI_DEVICE_INVALID: {
            DEBUG_PRINTLN(F("Evt Device Invalid"));
            break;
          }

          case ACI_DEVICE_TEST: {
            break;
          }

          case ACI_DEVICE_SLEEP: {
            break;
          }
        }
        break;  // case ACI_EVT_DEVICE_STARTED:
      }

      case ACI_EVT_CMD_RSP: {
        DEBUG_PRINTLN("ACI_EVT_CMD_RSP");
        // If an ACI command response event comes with an error -> stop
        if (ACI_STATUS_SUCCESS != aci_evt->params.cmd_rsp.cmd_status) {
          // ACI ReadDynamicData and ACI WriteDynamicData
          // will have status codes of
          // TRANSACTION_CONTINUE and TRANSACTION_COMPLETE
          // all other ACI commands will have status code of
          // ACI_STATUS_SCUCCESS for a successful command
          DEBUG_PRINT(F("ACI Command 0x"));
          DEBUG_PRINTLN2(aci_evt->params.cmd_rsp.cmd_opcode, HEX);
          DEBUG_PRINT(F("Evt Cmd response: Error. "));
          DEBUG_PRINTLN2(aci_evt->params.cmd_rsp.cmd_status, HEX);
        }
        if (ACI_CMD_GET_DEVICE_ADDRESS == aci_evt->params.cmd_rsp.cmd_opcode) {
          // If this is a response to get device address, save the address
          addrReceived = true;
          // DEBUG_PRINT(F("Get device address response: "));
          for (int i = BTLE_DEVICE_ADDRESS_SIZE - 1; i >= 0; --i) {
            deviceAddress[i] = aci_evt->params.cmd_rsp.params.get_device_address
                .bd_addr_own[i];
            //   DEBUG_PRINT2(deviceAddress[i], HEX);
            //   DEBUG_PRINT(F(":"));
          }
          // DEBUG_PRINTLN(F(""));
        } else if (ACI_CMD_OPEN_ADV_PIPE ==
                   aci_evt->params.cmd_rsp.cmd_opcode) {
          DEBUG_PRINTLN(
              F("Open advertising pipe response, setting service data."));
          lib_aci_set_local_data(
              &aci_state, PIPE_DEVICE_INFORMATION_MODEL_NUMBER_STRING_BROADCAST,
              (unsigned char *)longName, 8);
          DEBUG_PRINT(F("Advertising starting for "));
          DEBUG_PRINTLN(deviceName);
          lib_aci_connect(adTimeout, adInterval);
        } else if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode) {
          DEBUG_PRINTLN("ACI_CMD_GET_DEVICE_VERSION");
        } else if (ACI_CMD_SET_LOCAL_DATA == aci_evt->params.cmd_rsp.cmd_opcode) {
          DEBUG_PRINTLN("ACI_CMD_SET_LOCAL_DATA");
        } else if (ACI_CMD_CONNECT == aci_evt->params.cmd_rsp.cmd_opcode) {
          DEBUG_PRINTLN("ACI_CMD_CONNECT");
        } else if (ACI_CMD_DISCONNECT == aci_evt->params.cmd_rsp.cmd_opcode) {
          DEBUG_PRINTLN("ACI_CMD_DISCONNECT");
        } else if (ACI_CMD_CHANGE_TIMING == aci_evt->params.cmd_rsp.cmd_opcode) {
          DEBUG_PRINTLN("ACI_CMD_CHANGE_TIMING");
        }  else {
          // print command
          DEBUG_PRINT(F("Unexpected ACI Command 0x"));
          DEBUG_PRINTLN2(aci_evt->params.cmd_rsp.cmd_opcode, HEX);
        }
        break;
      }

      case ACI_EVT_CONNECTED: {
        // The nRF8001 is now connected to the peer device.
        DEBUG_PRINTLN(F("Evt Connected"));
        aci_state.data_credit_available = aci_state.data_credit_total;
        timing_change_done = false;
        break;
      }

      case ACI_EVT_PIPE_STATUS: {
        DEBUG_PRINTLN(F("Evt Pipe Status: "));
        // DEBUG_PRINT2((int) aci_evt->params.pipe_status.pipes_open_bitmap, HEX);
        // DEBUG_PRINT(" ");
        // DEBUG_PRINTLN2((int) aci_evt->params.pipe_status.pipes_closed_bitmap, HEX);
        if (lib_aci_is_pipe_available(&aci_state, PIPE_GOOSCI_SENSOR_VALUE_TX) && !timing_change_done) {
          lib_aci_change_timing(6, 6, 0, 600); // Low-latency parameters
        timing_change_done = true;
      }

        break;
      }

      case ACI_EVT_TIMING: {
        // DEBUG_PRINT("ACI_EVT_TIMING: ");
        // DEBUG_PRINT(aci_evt->params.timing.conn_rf_interval);
        // DEBUG_PRINT(" ");
        // DEBUG_PRINT(aci_evt->params.timing.conn_slave_rf_latency);
        // DEBUG_PRINT(" ");
        // DEBUG_PRINT(aci_evt->params.timing.conn_rf_timeout);
		// DEBUG_PRINT(" ");
        // DEBUG_PRINTLN(aci_evt->params.timing.conn_rf_interval);
        break;
      }

      case ACI_EVT_DISCONNECTED: {
        // Advertise again if the advertising timed out.
        DEBUG_PRINTLN(F("Evt Disconnected."));
        // TODO(dek): figure out why the transition to using credits
        // broke disconnection (packets are still transmitted).
        // Setting the credits to 0 was an experiment but it didn't work.
        // aci_state.data_credit_available = 0; 
        lib_aci_connect(adTimeout, adInterval);
        timing_change_done = false;
        break;
      }

      case ACI_EVT_DATA_RECEIVED: {
	DEBUG_PRINTLN("ACI_EVT_DATA_RECEIVED");
        if (aci_evt->params.data_received.rx_data.pipe_number == PIPE_GOOSCI_SENSOR_CONFIGURATION_RX_ACK_AUTO) {
          int8_t packet_length = aci_evt->len;
	  handle(aci_evt->params.data_received.rx_data.aci_data, aci_evt->len);
	} else {
	  DEBUG_PRINT(F(" Data(Hex) : "));
	  for (int i = 0; i < aci_evt->len - 2; i++) {
	    DEBUG_PRINT2(aci_evt->params.data_received.rx_data.aci_data[i], HEX);
	    DEBUG_PRINT(F(" "));
	  }
	  DEBUG_PRINTLN(F(""));
	}
	break;
      }


      case ACI_EVT_DATA_CREDIT: {
        // DEBUG_PRINTLN(F("Evt Credit: Peer has received our send"));
        aci_state.data_credit_available = aci_state.data_credit_available + aci_evt->params.data_credit.credit;
        break;
      }

      case ACI_EVT_PIPE_ERROR: {
        // See the appendix in the nRF8001
        // Product Specication for details on the error codes
        DEBUG_PRINT(F("ACI Evt Pipe Error: Pipe #:"));
        DEBUG_PRINT2(aci_evt->params.pipe_error.pipe_number, DEC);
        DEBUG_PRINT(F("  Pipe Error Code: 0x"));
        DEBUG_PRINTLN2(aci_evt->params.pipe_error.error_code, HEX);

        // Increment the credit available as the data packet was not sent.
        // The pipe error also represents the Attribute protocol
        // Error Response sent from the peer and that should not be counted
        // for the credit.
        if (ACI_STATUS_ERROR_PEER_ATT_ERROR !=
            aci_evt->params.pipe_error.error_code) {
          aci_state.data_credit_available++;
        }
        break;
      }

      case ACI_EVT_DATA_ACK: {
        // DEBUG_PRINTLN(F("ACK"));
        break;
      }
      case ACI_EVT_HW_ERROR: {
        DEBUG_PRINTLN(F("HW error: "));
        DEBUG_PRINTLN2(aci_evt->params.hw_error.line_num, DEC);

        for (int counter = 0; counter <= (aci_evt->len - 3); counter++) {
          DEBUG_PRINT(aci_evt->params.hw_error.file_name[counter]);
        }
        DEBUG_PRINTLN();
        initLocalData();
        lib_aci_connect(adTimeout, adInterval);
        break;
      }

      default: {
        DEBUG_PRINT(F("Evt Opcode 0x"));
        DEBUG_PRINT2(aci_evt->evt_opcode, HEX);
        DEBUG_PRINTLN(F(" unhandled"));
        break;
      }
    }
  }

  // setup_required is set to true when the device starts
  // up and enters setup mode.
  // It indicates that do_aci_setup() should be called.
  // The flag should be cleared if do_aci_setup() returns
  // ACI_STATUS_TRANSACTION_COMPLETE.
  if (setup_required) {
    int result = do_aci_setup(&aci_state);
    if (result != SETUP_SUCCESS ) {
      switch(result) {
        case SETUP_FAIL_COMMAND_QUEUE_NOT_EMPTY:
          DEBUG_PRINTLN("SETUP_FAIL_COMMAND_QUEUE_NOT_EMPTY");
          break;
        case SETUP_FAIL_EVENT_QUEUE_NOT_EMPTY:
          DEBUG_PRINTLN("SETUP_EVENT_COMMAND_QUEUE_NOT_EMPTY");
          break;
        case SETUP_FAIL_NOT_SETUP_EVENT:
          DEBUG_PRINTLN("SETUP_FAIL_NOT_SETUP_EVENT");
          break;
        case SETUP_FAIL_NOT_COMMAND_RESPONSE:
          DEBUG_PRINTLN("SETUP_FAIL_NOT_COMMAND_RESPONSE");
          break;
      }
    } else {
      setup_required = false;
    }
  }
}
bool Adafruit_BLE_UART::uart_process_control_point_rx(uint8_t *byte, uint8_t length)
{
  bool status = false;
  aci_ll_conn_params_t *conn_params;

  if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_CONTROL_POINT_TX) )
  {
    Serial.println(*byte, HEX);
    switch(*byte)
    {
      /*
      Queues a ACI Disconnect to the nRF8001 when this packet is received.
      May cause some of the UART packets being sent to be dropped
      */
      case UART_OVER_BLE_DISCONNECT:
        /*
        Parameters:
        None
        */
        lib_aci_disconnect(&aci_state, ACI_REASON_TERMINATE);
        status = true;
        break;


      /*
      Queues an ACI Change Timing to the nRF8001
      */
      case UART_OVER_BLE_LINK_TIMING_REQ:
        /*
        Parameters:
        Connection interval min: 2 bytes
        Connection interval max: 2 bytes
        Slave latency:           2 bytes
        Timeout:                 2 bytes
        Same format as Peripheral Preferred Connection Parameters (See nRFgo studio -> nRF8001 Configuration -> GAP Settings
        Refer to the ACI Change Timing Request in the nRF8001 Product Specifications
        */
        conn_params = (aci_ll_conn_params_t *)(byte+1);
        lib_aci_change_timing( conn_params->min_conn_interval,
                                conn_params->max_conn_interval,
                                conn_params->slave_latency,
                                conn_params->timeout_mult);
        status = true;
        break;

      /*
      Clears the RTS of the UART over BLE
      */
      case UART_OVER_BLE_TRANSMIT_STOP:
        /*
        Parameters:
        None
        */
        uart_over_ble.uart_rts_local = false;
        status = true;
        break;


      /*
      Set the RTS of the UART over BLE
      */
      case UART_OVER_BLE_TRANSMIT_OK:
        /*
        Parameters:
        None
        */
        uart_over_ble.uart_rts_local = true;
        status = true;
        break;
    }
  }

  return status;
}