summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2014-12-03 23:39:15 +0100
committerTrygve Laugstøl <trygvis@inamo.no>2014-12-03 23:39:15 +0100
commit2d887e4226d60347a97518c8efafa507d7ab7bed (patch)
treef9158683edef81fb81b0de7914fe4b666d7508c7
parent1784a0ee9bfc3937aef6f8cb1f9404c4817ee946 (diff)
downloadfiken-display-android-2d887e4226d60347a97518c8efafa507d7ab7bed.tar.gz
fiken-display-android-2d887e4226d60347a97518c8efafa507d7ab7bed.tar.bz2
fiken-display-android-2d887e4226d60347a97518c8efafa507d7ab7bed.tar.xz
fiken-display-android-2d887e4226d60347a97518c8efafa507d7ab7bed.zip
o Rewritten how the BT callbacks are handled. Now with a small queue of actions.
o Can successfully read bytes from a BT device.
-rw-r--r--app/src/main/java/no/topi/fiken/display/DefaultDisplayService.java354
-rw-r--r--app/src/main/java/no/topi/fiken/display/DisplayControlActivity.java3
-rw-r--r--app/src/main/java/no/topi/fiken/display/DisplayService.java5
-rw-r--r--app/src/main/res/layout/activity_display_control.xml8
-rw-r--r--app/src/main/res/values/strings.xml1
5 files changed, 268 insertions, 103 deletions
diff --git a/app/src/main/java/no/topi/fiken/display/DefaultDisplayService.java b/app/src/main/java/no/topi/fiken/display/DefaultDisplayService.java
index 3bd2dd0..53b00fc 100644
--- a/app/src/main/java/no/topi/fiken/display/DefaultDisplayService.java
+++ b/app/src/main/java/no/topi/fiken/display/DefaultDisplayService.java
@@ -16,8 +16,10 @@ import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
-import java.lang.reflect.Array;
-import java.util.Arrays;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
public class DefaultDisplayService extends Service implements DisplayService {
private final Context context = DefaultDisplayService.this;
@@ -27,10 +29,15 @@ public class DefaultDisplayService extends Service implements DisplayService {
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
- private BluetoothGatt gatt;
- private BluetoothGattService displayService;
- private BluetoothGattCharacteristic gaugeCtrl;
- private BluetoothGattCharacteristic gaugeData;
+
+ private State state;
+
+ private static class State {
+ BluetoothGatt gatt;
+ BluetoothGattService displayService;
+ BluetoothGattCharacteristic gaugeCtrl;
+ BluetoothGattCharacteristic gaugeData;
+ }
private Handler handler;
private int UPDATE_RSSI_DELAY = 100 * 1000;
@@ -38,8 +45,8 @@ public class DefaultDisplayService extends Service implements DisplayService {
private Runnable updateRssi = new Runnable() {
@Override
public void run() {
- if (gatt != null) {
- gatt.readRemoteRssi();
+ if (state != null && state.gatt != null) {
+ state.gatt.readRemoteRssi();
}
handler.postDelayed(this, UPDATE_RSSI_DELAY);
@@ -94,7 +101,7 @@ public class DefaultDisplayService extends Service implements DisplayService {
@Override
public boolean connect(final String address) {
if (serviceState != ServiceState.IDLE) {
- if (!(serviceState == ServiceState.CONNECTED && gatt.getDevice().getAddress().equals(address))) {
+ if (!(serviceState == ServiceState.CONNECTED && state.gatt.getDevice().getAddress().equals(address))) {
Log.e(TAG, "connect(): Not idle: " + serviceState);
return false;
}
@@ -103,129 +110,100 @@ public class DefaultDisplayService extends Service implements DisplayService {
return true;
}
+ state = new State();
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
- gatt = device.connectGatt(this, false, new BluetoothGattCallback() {
+ BtActionExecutor executor = new BtActionExecutor();
+
+ executor.onSuccess(new BtCallback() {
@Override
- public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
-// Toast.makeText(context, "Connected", Toast.LENGTH_SHORT).show();
- if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothGatt.STATE_CONNECTED) {
- boolean ok = gatt.discoverServices();
+ public boolean onConnectionStateChange(BluetoothGatt gatt, int newState) {
+ boolean ok = gatt.discoverServices();
- if (!ok) {
- disconnect();
- } else {
- Intent intent = IntentAction.DEVICE_UPDATE.intent();
- intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), address);
- intent.putExtra(IntentExtra.CONNECTED.name(), true);
- sendBroadcast(intent);
- }
- } else {
- Log.w(TAG, "Could not connect to device");
-// Toast.makeText(context, "Could not connect to device", Toast.LENGTH_SHORT).show();
+ if (!ok) {
+ return false;
}
- }
- @Override
- public void onServicesDiscovered(BluetoothGatt gatt, int status) {
- Log.i(TAG, "onServicesDiscovered");
-
- Log.i(TAG, "Constants.TRYGVIS_IO_FIKEN_STATUS_PANEL_UUID = " + Constants.TRYGVIS_IO_FIKEN_STATUS_PANEL_UUID);
+ Intent intent = IntentAction.DEVICE_UPDATE.intent();
+ intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), address);
+ intent.putExtra(IntentExtra.CONNECTED.name(), true);
+ sendBroadcast(intent);
- for (BluetoothGattService bluetoothGattService : gatt.getServices()) {
- Log.i(TAG, "bluetoothGattService.getUuid() = " + bluetoothGattService.getUuid());
- }
+ return true;
+ }
+ }).onSuccess(new BtCallback() {
+ @Override
+ public boolean onServicesDiscovered(BluetoothGatt gatt) {
+ Log.i(TAG, "Services discovered");
- displayService = gatt.getService(Constants.TRYGVIS_IO_FIKEN_STATUS_PANEL_UUID);
- gaugeCtrl = displayService.getCharacteristic(Constants.TRYGVIS_IO_GAUGE_CTRL_UUID);
- gaugeData = displayService.getCharacteristic(Constants.TRYGVIS_IO_GAUGE_DATA_UUID);
+ state.displayService = gatt.getService(Constants.TRYGVIS_IO_FIKEN_STATUS_PANEL_UUID);
+ state.gaugeCtrl = state.displayService.getCharacteristic(Constants.TRYGVIS_IO_GAUGE_CTRL_UUID);
+ state.gaugeData = state.displayService.getCharacteristic(Constants.TRYGVIS_IO_GAUGE_DATA_UUID);
- Log.i(TAG, "service=" + displayService + ", gaugeCtrl=" + gaugeCtrl + ", gaugeData=" + gaugeData);
+ Log.i(TAG, "service=" + state.displayService + ", gaugeCtrl=" + state.gaugeCtrl + ", gaugeData=" + state.gaugeData);
Intent intent = IntentAction.DEVICE_UPDATE.intent();
intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), address);
- intent.putExtra(IntentExtra.DEVICE_IS_DISPLAY.name(), displayService != null);
+ intent.putExtra(IntentExtra.DEVICE_IS_DISPLAY.name(), state.displayService != null);
sendBroadcast(intent);
- BluetoothGattDescriptor ccg = gaugeCtrl.getDescriptor(Constants.CLIENT_CHARACTERISTIC_CONFIG);
+ BluetoothGattDescriptor ccg = state.gaugeCtrl.getDescriptor(Constants.CLIENT_CHARACTERISTIC_CONFIG);
ccg.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
- gatt.writeDescriptor(ccg);
- Log.i(TAG, "ccg=" + ccg);
-
- // Send a request for gauge count.
-
-// gaugeCtrl.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
-// gaugeCtrl.setValue(new byte[]{0x01});
-// gaugeCtrl.getDe
-// gatt.setCharacteristicNotification(gaugeCtrl, true);
-// gatt.writeCharacteristic(gaugeCtrl);
-// gatt.readCharacteristic(gaugeCtrl);
+ gatt.setCharacteristicNotification(state.gaugeCtrl, true);
+ return gatt.writeDescriptor(ccg);
}
-
+ }).onSuccess(new BtCallback() {
@Override
- public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
- Log.i(TAG, "onCharacteristicRead");
+ public boolean onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) {
+ state.gaugeCtrl.setValue(new byte[]{0x01});
+ gatt.writeCharacteristic(state.gaugeCtrl);
- String s = "";
- for (byte b : characteristic.getValue()) {
- s += Integer.toHexString(b);
- }
-
- Log.i(TAG, "uuid=" + characteristic.getUuid() + ", value=" + s);
+ return true;
}
-
+ }).onSuccess(new BtCallback() {
@Override
- public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
- Log.i(TAG, "onCharacteristicWrite");
-
- String s = "";
- for (byte b : characteristic.getValue()) {
- s += Integer.toHexString(b);
- }
-
- Log.i(TAG, "uuid=" + characteristic.getUuid() + ", value=0x" + s + ", status=" + status);
+ public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ Log.w(TAG, "wait for it...!");
+ return true;
}
-
+ }).onSuccess(new BtCallback() {
@Override
- public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
- Log.i(TAG, "onCharacteristicChanged");
+ public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ byte[] value = state.gaugeCtrl.getValue();
+
+ Log.w(TAG, "gauge bytes: " + toHexString(value));
- String s = "";
- for (byte b : characteristic.getValue()) {
- s += Integer.toHexString(b);
+ if (value.length != 2) {
+ Log.w(TAG, "Bad response, expected value.length to be 2, was " + value.length);
+ return false;
}
- Log.i(TAG, "uuid=" + characteristic.getUuid() + ", value=0x" + s);
- }
+ int gaugeCount = (int) value[1];
- @Override
- public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
- Log.i(TAG, "onDescriptorRead");
- }
+ Log.d(TAG, "Gauge count=" + gaugeCount);
- @Override
- public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
- Log.i(TAG, "onDescriptorWrite, status=" + status + ", descriptor=" + descriptor.getUuid());
- }
+ Intent intent = IntentAction.DEVICE_UPDATE.intent();
+ intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), address);
+ intent.putExtra(IntentExtra.GAUGE_COUNT.name(), gaugeCount);
+ sendBroadcast(intent);
- @Override
- public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
- Log.i(TAG, "onReliableWriteCompleted, status=" + status);
+ return true;
}
+ });
+ executor.onRemoteRssi(new BluetoothGattCallback() {
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
-// Log.i(TAG, "onReadRemoteRssi, status=" + status + ", rssi=" + rssi);
- if (status == BluetoothGatt.GATT_SUCCESS) {
- Intent intent = IntentAction.DEVICE_UPDATE.intent();
- intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), gatt.getDevice().getAddress());
- intent.putExtra(IntentExtra.RSSI.name(), rssi);
- sendBroadcast(intent);
- }
+ Intent intent = IntentAction.DEVICE_UPDATE.intent();
+ intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), gatt.getDevice().getAddress());
+ intent.putExtra(IntentExtra.RSSI.name(), rssi);
+ sendBroadcast(intent);
}
});
- if (gatt != null) {
+ state.gatt = device.connectGatt(this, false, executor.asCallback());
+
+ if (state.gatt != null) {
serviceState = ServiceState.CONNECTED;
return true;
} else {
@@ -233,6 +211,164 @@ public class DefaultDisplayService extends Service implements DisplayService {
}
}
+ private static class BtCallback {
+ public boolean onConnectionStateChange(BluetoothGatt gatt, int newState) {
+ throw new NotOverriddenException();
+ }
+
+ public boolean onServicesDiscovered(BluetoothGatt gatt) {
+ throw new NotOverriddenException();
+ }
+
+ public boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ throw new NotOverriddenException();
+ }
+
+ public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ throw new NotOverriddenException();
+ }
+
+ public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ throw new NotOverriddenException();
+ }
+
+ public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) {
+ throw new NotOverriddenException();
+ }
+
+ public boolean onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) {
+ throw new NotOverriddenException();
+ }
+
+ public boolean onReliableWriteCompleted(BluetoothGatt gatt) {
+ throw new NotOverriddenException();
+ }
+
+ public boolean onReadRemoteRssi(BluetoothGatt gatt, int rssi) {
+ throw new NotOverriddenException();
+ }
+ }
+
+ private static class NotOverriddenException extends RuntimeException {
+ }
+
+ private class BtActionExecutor {
+ Queue<BtCallback> actions = new ArrayDeque<BtCallback>();
+ List<BluetoothGattCallback> remoteRssi = new ArrayList<BluetoothGattCallback>();
+
+
+ public BtActionExecutor onSuccess(BtCallback btCallback) {
+ actions.add(btCallback);
+ return this;
+ }
+
+ public BtActionExecutor onRemoteRssi(BluetoothGattCallback callback) {
+ remoteRssi.add(callback);
+ return this;
+ }
+
+ public void onEvent(String key, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int status, int newState) {
+ if (status != BluetoothGatt.GATT_SUCCESS) {
+ Log.w(TAG, "Operation failed: " + key);
+ }
+
+ Log.i(TAG, "Bt action completed successfully: callback=" + key);
+
+ if (!actions.isEmpty()) {
+ BtCallback btCallback = actions.remove();
+ Log.i(TAG, "Executing bt action");
+
+ boolean ok;
+
+ try {
+ if (key.equals("onConnectionStateChange")) {
+ ok = btCallback.onConnectionStateChange(gatt, newState);
+ } else if (key.equals("onServicesDiscovered")) {
+ ok = btCallback.onServicesDiscovered(gatt);
+ } else if (key.equals("onCharacteristicRead")) {
+ ok = btCallback.onCharacteristicRead(gatt, characteristic);
+ } else if (key.equals("onCharacteristicWrite")) {
+ ok = btCallback.onCharacteristicWrite(gatt, characteristic);
+ } else if (key.equals("onCharacteristicChanged")) {
+ ok = btCallback.onCharacteristicChanged(gatt, characteristic);
+ } else if (key.equals("onDescriptorRead")) {
+ ok = btCallback.onDescriptorRead(gatt, descriptor);
+ } else if (key.equals("onDescriptorWrite")) {
+ ok = btCallback.onDescriptorWrite(gatt, descriptor);
+ } else if (key.equals("onReliableWriteCompleted")) {
+ ok = btCallback.onReliableWriteCompleted(gatt);
+ } else {
+ Log.w(TAG, "Unknown callback: " + key);
+ return;
+ }
+ } catch (NotOverriddenException e) {
+ Log.w(TAG, "Unexpected callback by listener: " + key);
+ disconnect();
+ return;
+ }
+
+ if (!ok) {
+ Log.w(TAG, "Error performing Bluetooth action.");
+ disconnect();
+ }
+ } else {
+ Log.d(TAG, "All Bluetooth actions are done");
+ }
+ }
+
+ public BluetoothGattCallback asCallback() {
+ return new BluetoothGattCallback() {
+
+ @Override
+ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+ onEvent("onConnectionStateChange", gatt, null, null, status, newState);
+ }
+
+ @Override
+ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+ onEvent("onServicesDiscovered", gatt, null, null, status, 9);
+ }
+
+ @Override
+ public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
+ onEvent("onCharacteristicRead", gatt, characteristic, null, status, 0);
+ }
+
+ @Override
+ public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
+ onEvent("onCharacteristicWrite", gatt, characteristic, null, status, 0);
+ }
+
+ @Override
+ public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ onEvent("onCharacteristicChanged", gatt, characteristic, null, BluetoothGatt.GATT_SUCCESS, 0);
+ }
+
+ @Override
+ public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ onEvent("onDescriptorRead", gatt, null, descriptor, status, 0);
+ }
+
+ @Override
+ public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ onEvent("onDescriptorWrite", gatt, null, descriptor, status, 0);
+ }
+
+ @Override
+ public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
+ onEvent("onReliableWriteCompleted", gatt, null, null, status, 0);
+ }
+
+ @Override
+ public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
+ for (BluetoothGattCallback callback : remoteRssi) {
+ callback.onReadRemoteRssi(gatt, rssi, status);
+ }
+ }
+ };
+ }
+ }
+
@Override
public void disconnect() {
if (serviceState != ServiceState.CONNECTED) {
@@ -242,21 +378,23 @@ public class DefaultDisplayService extends Service implements DisplayService {
serviceState = ServiceState.IDLE;
- if (gatt != null) {
+ if (state.gatt != null) {
try {
- gatt.disconnect();
+ state.gatt.disconnect();
} catch (Exception e) {
Log.w(TAG, "gatt.disconnect()", e);
}
try {
- gatt.close();
+ state.gatt.close();
} catch (Exception e) {
Log.w(TAG, "gatt.close()", e);
}
- gatt = null;
+ state.gatt = null;
}
- displayService = null;
+ state.displayService = null;
+
+ state = new State();
}
@Override
@@ -294,4 +432,16 @@ public class DefaultDisplayService extends Service implements DisplayService {
sendBroadcast(intent);
}
};
+
+ public static String toHexString(byte[] bytes) {
+ StringBuilder s = new StringBuilder();
+ for (byte b : bytes) {
+ if (b < 10) {
+ s.append('0');
+ }
+ s.append(Integer.toHexString(b));
+ }
+
+ return s.toString();
+ }
}
diff --git a/app/src/main/java/no/topi/fiken/display/DisplayControlActivity.java b/app/src/main/java/no/topi/fiken/display/DisplayControlActivity.java
index 1147c0c..1a537d9 100644
--- a/app/src/main/java/no/topi/fiken/display/DisplayControlActivity.java
+++ b/app/src/main/java/no/topi/fiken/display/DisplayControlActivity.java
@@ -28,6 +28,7 @@ public class DisplayControlActivity extends Activity {
private TextView deviceNameView;
private TextView deviceRssiView;
+ private TextView gaugeCountView;
private LinearLayout gaugesLayout;
@Override
@@ -45,6 +46,7 @@ public class DisplayControlActivity extends Activity {
deviceNameView = (TextView) findViewById(R.id.device_name);
deviceRssiView = (TextView) findViewById(R.id.device_rssi);
+ gaugeCountView = (TextView) findViewById(R.id.gauge_count);
gaugesLayout = (LinearLayout) findViewById(R.id.gauges);
Button disconnectButton = (Button) findViewById(R.id.button_disconnect);
@@ -61,6 +63,7 @@ public class DisplayControlActivity extends Activity {
private void updateValues() {
deviceNameView.setText(deviceInfo.name != null ? deviceInfo.name : getText(R.string.name_unknown));
deviceRssiView.setText(getText(R.string.rssi) + ": " + (deviceInfo.rssi != 0 ? valueOf(deviceInfo.rssi) : ""));
+ gaugeCountView.setText(getText(R.string.gauge_count) + ": " + (deviceInfo.gaugeCount));
}
@Override
diff --git a/app/src/main/java/no/topi/fiken/display/DisplayService.java b/app/src/main/java/no/topi/fiken/display/DisplayService.java
index c907138..666a750 100644
--- a/app/src/main/java/no/topi/fiken/display/DisplayService.java
+++ b/app/src/main/java/no/topi/fiken/display/DisplayService.java
@@ -13,6 +13,7 @@ public interface DisplayService {
RSSI,
SCANNING,
CONNECTED,
+ GAUGE_COUNT,
}
public static enum IntentAction {
@@ -64,6 +65,7 @@ public interface DisplayService {
class DeviceInfo {
final String address;
int rssi = 0;
+ int gaugeCount = 0;
Boolean isDisplay = null;
String name;
@@ -97,6 +99,9 @@ public interface DisplayService {
if (intent.hasExtra(IntentExtra.DEVICE_NAME.name())) {
name = intent.getStringExtra(IntentExtra.DEVICE_NAME.name());
}
+ if (intent.hasExtra(IntentExtra.GAUGE_COUNT.name())) {
+ gaugeCount = intent.getIntExtra(IntentExtra.GAUGE_COUNT.name(), 0);
+ }
}
}
}
diff --git a/app/src/main/res/layout/activity_display_control.xml b/app/src/main/res/layout/activity_display_control.xml
index 4151184..7b19429 100644
--- a/app/src/main/res/layout/activity_display_control.xml
+++ b/app/src/main/res/layout/activity_display_control.xml
@@ -22,12 +22,18 @@
android:textSize="12sp"
android:layout_below="@+id/device_name"/>
+ <TextView
+ android:id="@+id/gauge_count"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/device_rssi"/>
+
<Button
android:id="@+id/button_disconnect"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/disconnect"
- android:layout_below="@+id/device_rssi"
+ android:layout_below="@+id/gauge_count"
/>
<LinearLayout
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0cea3b4..3a1c3a8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -17,6 +17,7 @@
<string name="unknown_characteristic">Unknown characteristic</string>
<string name="unknown_service">Unknown service</string>
<string name="rssi">RSSI</string>
+ <string name="gauge_count">Gauge count</string>
<string name="name_unknown">Unknown name</string>
<string name="rssi_unknown">unknown</string>
<string name="connect">Connect</string>