package com.arduinoandroid.mobilerobot; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import com.arduinoandroid.mobilerobot.Bluetooth.BluetoothUtils; import java.nio.charset.Charset; import java.util.UUID; public class RobotControlActivity extends Activity { //User Interface Elements Button fwdBtn; Button leftBtn; Button rightBtn; Button backBtn; Button stopBtn; Button connectBtn; TextView connectionSts; //Logging Variables private final String LOG_TAG = RobotControlActivity.class.getSimpleName(); // UUIDs for UAT service and associated characteristics. public static UUID UART_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); public static UUID TX_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"); public static UUID RX_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"); // UUID for the BTLE client characteristic which is necessary for notifications. public static UUID CLIENT_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); // BTLE stateta private BluetoothAdapter adapter; private BluetoothGatt gatt; private BluetoothGattCharacteristic tx; private BluetoothGattCharacteristic rx; private boolean areServicesAccessible = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_robot_control); fwdBtn = (Button) findViewById(R.id.fwdBtn); leftBtn = (Button) findViewById(R.id.leftBtn); rightBtn = (Button) findViewById(R.id.rightBtn); backBtn = (Button) findViewById(R.id.backwardBtn); stopBtn = (Button) findViewById(R.id.stopBtn); connectBtn = (Button) findViewById(R.id.connectBtn); connectionSts = (TextView)findViewById(R.id.connectionStsView); fwdBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String setOutputMessage = "/forward /"; tx.setValue(setOutputMessage.getBytes(Charset.forName("UTF-8"))); if (gatt.writeCharacteristic(tx)) { writeConnectionData("Sent: " + setOutputMessage); } else { writeConnectionData("Couldn't write TX characteristic!"); } } }); leftBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String setOutputMessage = "/left /"; tx.setValue(setOutputMessage.getBytes(Charset.forName("UTF-8"))); if (gatt.writeCharacteristic(tx)) { writeConnectionData("Sent: " + setOutputMessage); } else { writeConnectionData("Couldn't write TX characteristic!"); } } }); rightBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String setOutputMessage = "/right /"; tx.setValue(setOutputMessage.getBytes(Charset.forName("UTF-8"))); if (gatt.writeCharacteristic(tx)) { writeConnectionData("Sent: " + setOutputMessage); } else { writeConnectionData("Couldn't write TX characteristic!"); } } }); backBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String setOutputMessage = "/backward /"; tx.setValue(setOutputMessage.getBytes(Charset.forName("UTF-8"))); if (gatt.writeCharacteristic(tx)) { writeConnectionData("Sent: " + setOutputMessage); } else { writeConnectionData("Couldn't write TX characteristic!"); } } }); stopBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String setOutputMessage = "/stop /"; tx.setValue(setOutputMessage.getBytes(Charset.forName("UTF-8"))); if (gatt.writeCharacteristic(tx)) { writeConnectionData("Sent: " + setOutputMessage); } else { writeConnectionData("Couldn't write TX characteristic!"); } } }); connectBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { restartScan(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.robot_control, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } private void writeConnectionData(final CharSequence text) { Log.e(LOG_TAG, text.toString()); connectionSts.setText(text.toString()); } // BTLE device scanning bluetoothGattCallback. // Main BTLE device bluetoothGattCallback where much of the logic occurs. private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() { // Called whenever the device connection state changes, i.e. from disconnected to connected. @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); if (newState == BluetoothGatt.STATE_CONNECTED) { writeConnectionData("Connected!"); // Discover services. if (!gatt.discoverServices()) { writeConnectionData("Failed to start discovering services!"); } } else if (newState == BluetoothGatt.STATE_DISCONNECTED) { writeConnectionData("Disconnected!"); } else { writeConnectionData("Connection state changed. New state: " + newState); } } // Called when services have been discovered on the remote device. // It seems to be necessary to wait for this discovery to occur before // manipulating any services or characteristics. public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); if (status == BluetoothGatt.GATT_SUCCESS) { writeConnectionData("Service discovery completed!"); } else { writeConnectionData("Service discovery failed with status: " + status); } // Save reference to each characteristic. tx = gatt.getService(UART_UUID).getCharacteristic(TX_UUID); rx = gatt.getService(UART_UUID).getCharacteristic(RX_UUID); // Setup notifications on RX characteristic changes (i.e. data received). // First call setCharacteristicNotification to enable notification. if (!gatt.setCharacteristicNotification(rx, true)) { writeConnectionData("Couldn't set notifications for RX characteristic!"); } // Next update the RX characteristic's client descriptor to enable notifications. if (rx.getDescriptor(CLIENT_UUID) != null) { BluetoothGattDescriptor desc = rx.getDescriptor(CLIENT_UUID); desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); if (!gatt.writeDescriptor(desc)) { writeConnectionData("Couldn't write RX client descriptor value!"); } } else { writeConnectionData("Couldn't get RX client descriptor!"); } areServicesAccessible = true; } }; protected void onStart() { Log.d(LOG_TAG,"onStart has been called"); super.onStart(); // / Scan for all BTLE devices. // The first one with the UART service will be chosen--see the code in the scanCallback. adapter = BluetoothAdapter.getDefaultAdapter(); startScan(); } //When this Activity isn't visible anymore protected void onStop() { Log.d(LOG_TAG,"onStop has been called"); //disconnect and close Bluetooth Connection for better reliability if (gatt != null) { gatt.disconnect(); gatt.close(); gatt = null; tx = null; rx = null; } super.onStop(); } //BLUETOOTH METHODS private void startScan() { if (!adapter.isEnabled()) { adapter.enable(); } if (!adapter.isDiscovering()) { adapter.startDiscovery(); } writeConnectionData("Scanning for devices..."); adapter.startLeScan(scanCallback); } private void stopScan() { if (adapter.isDiscovering()) { adapter.cancelDiscovery(); } writeConnectionData("Stopping scan"); adapter.stopLeScan(scanCallback); } private void restartScan() { stopScan(); startScan(); } /** * Main callback following an LE device scan */ private BluetoothAdapter.LeScanCallback scanCallback = new BluetoothAdapter.LeScanCallback() { // Called when a device is found. @Override public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) { Log.d(LOG_TAG, bluetoothDevice.getAddress()); writeConnectionData("Found device: " + bluetoothDevice.getAddress()); // Check if the device has the UART service. if (BluetoothUtils.parseUUIDs(bytes).contains(UART_UUID)) { // Found a device, stop the scan. adapter.stopLeScan(scanCallback); writeConnectionData("Found UART service!"); // Connect to the device. // Control flow will now go to the bluetoothGattCallback functions when BTLE events occur. gatt = bluetoothDevice.connectGatt(getApplicationContext(), false, bluetoothGattCallback); } } }; }