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);
}
}
};
}