From 4cdaceda76013999ca0e81d6ddd6eeec8c596f0d Mon Sep 17 00:00:00 2001 From: Greg Date: Wed, 4 Dec 2019 17:06:14 -0500 Subject: [PATCH] Working Android version using Blessed library. --- Ble.jar | Bin 7223 -> 6951 bytes BleConnect.java | 267 -------------------------------------------- BlessedConnect.java | 40 +++---- ble_android.go | 34 +++--- blessed-full.jar | Bin 78708 -> 78587 bytes 5 files changed, 31 insertions(+), 310 deletions(-) delete mode 100644 BleConnect.java diff --git a/Ble.jar b/Ble.jar index 49dd545430ae644ef086a872dd9b5867af274da7..aa2c4bcc859487f207f6f663d6bd1da474f0416c 100644 GIT binary patch delta 5973 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 chrs = serv.getCharacteristics(); - if (chrs.isEmpty()) { - Log.d("gio", "BleConnect: no characteristics found!"); - } - for (BluetoothGattCharacteristic chr : chrs) { - Log.d("gio","BleConnect: -- " + chr.getUuid().toString()); - onDiscoverCharacteristic(gatt.getDevice().getAddress(), serv.getUuid().toString(), serv, chr.getUuid().toString(), chr); - } - } - - public void setCharacteristicNotification(BluetoothGatt gatt, BluetoothGattCharacteristic chr) { - gatt.setCharacteristicNotification(chr, true); - - BluetoothGattDescriptor descriptor = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); // Client Characteristic Config - descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); - gatt.writeDescriptor(descriptor); - } - - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - Log.d("gio", "BleConnect: onActivityResult()"); - if (requestCode == REQUEST_ENABLE_BT) { - Log.d("gio", "BleConnect: onActivityResult() REQUEST_ENABLE_BT"); - switch (resultCode) { - case Activity.RESULT_OK: { - Log.d("gio", "BleConnect: onActivityResult() -- OK"); - if (wantScan) { - scan(); - } - break; - } - case Activity.RESULT_CANCELED: { - Log.d("gio", "BleConnect: onActivityResult() -- Cancelled"); - break; - } - } - } - } - - @Override - public void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults) { - Log.d("gio", "BleConnect: onRequestPermissionsResult"); - if (requestCode == PERMISSION_REQUEST) { - boolean granted = true; - for (int x : grantResults) { - if (x == PackageManager.PERMISSION_DENIED) { - granted = false; - break; - } - } - if (!granted) { - Log.d("gio", "BleConnect: permissions not granted"); - return; - } - Log.d("gio", "BleConnect: permissions granted"); - if (wantScan) { - scan(); - } - } - } - - static private native void installComplete(BleConnect p); - static private native void updateState(int s); - static private native void onScan(String name, String id, int rssi, BluetoothDevice dev); - static private native void onConnect(BluetoothGatt gatt, String id); - static private native void onDiscoverService(String id, String uuid, BluetoothGattService serv); - static private native void onDiscoverCharacteristic(String id, String suuid, BluetoothGattService serv, String cuuid, BluetoothGattCharacteristic chr); - static private native void characteristicChanged(String id, String cuuid, BluetoothGattCharacteristic chr, byte[] value, int length); -} - diff --git a/BlessedConnect.java b/BlessedConnect.java index 0db8486..3491964 100644 --- a/BlessedConnect.java +++ b/BlessedConnect.java @@ -18,8 +18,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.Manifest; -import android.os.Handler; -import android.os.HandlerThread; import android.util.Log; import com.welie.blessed.BluetoothCentral; @@ -45,11 +43,7 @@ public class BlessedConnect extends Fragment { if (ctx.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST); } - Log.d("gio", "BlessedConnect: creating HandlerThread"); - HandlerThread thread = new HandlerThread("Bluetooth Thread"); -thread.start(); - Handler handler = new Handler(thread.getLooper()); - central = new BluetoothCentral(ctx, centralCallback, handler); + central = new BluetoothCentral(ctx, centralCallback, null); installComplete(this); } @@ -67,9 +61,8 @@ thread.start(); Context ctx = getContext(); //The Blessed library does not expose this functionality, so //we need to get our own BluetoothAdapter and check its status. - //BluetoothAdapter adapter = ((BluetoothManager)ctx.getSystemService(ctx.BLUETOOTH_SERVICE)).getAdapter(); - //return (adapter != null && adapter.isEnabled()); - return true; + BluetoothAdapter adapter = ((BluetoothManager)ctx.getSystemService(ctx.BLUETOOTH_SERVICE)).getAdapter(); + return (adapter != null && adapter.isEnabled()); } @Override @@ -81,12 +74,10 @@ thread.start(); } public void scan() { - Log.d("gio", "BlessedConnect: Scan"); central.scanForPeripherals(); } public void stopScan() { - Log.d("gio", "BlessedConnect: Stop scan"); central.stopScan(); } @@ -117,7 +108,6 @@ thread.start(); @Override public void onScanFailed(int errorCode) { Log.d("gio", "BlessedConnect: Scan failed"); - } }; @@ -135,20 +125,15 @@ thread.start(); public void onBondLost(BluetoothPeripheral peripheral) { Log.d("gio", "BlessedConnect: onBondLost()"); } - public void onCharacteristicUpdate(BluetoothPeripheral peripheral, byte[] value, BluetoothGattCharacteristic characteristic) { + public void onCharacteristicUpdate(BluetoothPeripheral peripheral, byte[] value, BluetoothGattCharacteristic characteristic, int status) { Log.d("gio", "BlessedConnect: onCharacteristicUpdate()"); characteristicChanged(peripheral.getAddress(), characteristic.getUuid().toString(), characteristic, value, value.length); } public void onCharacteristicWrite(BluetoothPeripheral peripheral, byte[] value, android.bluetooth.BluetoothGattCharacteristic characteristic, int status) { Log.d("gio", "onCharacteristicWrite(): " + characteristic.getUuid().toString()); } - public void onDescriptorRead(BluetoothPeripheral peripheral, byte[] value, android.bluetooth.BluetoothGattDescriptor descriptor) { + public void onDescriptorRead(BluetoothPeripheral peripheral, byte[] value, android.bluetooth.BluetoothGattDescriptor descriptor, int status) { Log.d("gio", "onDescriptorRead()"); - if (value == BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) { - Log.d("gio", "onDescriptorRead(): " + descriptor.getUuid().toString() + ": notification enabled"); - } else { - Log.d("gio", "onDescriptorRead(): " + descriptor.getUuid().toString() + ": notification not enabled"); - } } public void onDescriptorWrite(BluetoothPeripheral peripheral, byte[] value, android.bluetooth.BluetoothGattDescriptor descriptor, int status) { Log.d("gio", "onDescriptorWrite(): " + descriptor.getUuid().toString()); @@ -156,16 +141,13 @@ thread.start(); public void onMtuChanged(BluetoothPeripheral peripheral, int mtu, int status) { Log.d("gio", "onMtuChanged()"); } - public void onReadRemoteRssi(BluetoothPeripheral peripheral, int rssi, int status) { + public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { Log.d("gio", "onReadRemoteRssi"); } public void onNotificationStateUpdate(BluetoothPeripheral peripheral, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { if(peripheral.isNotifying(characteristic)) { Log.i("gio", String.format("BlessedConnect: Notify set to 'on' for %s", characteristic.getUuid())); - BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); - Log.d("gio", "Reading descriptor"); - peripheral.readDescriptor(descriptor); } else { Log.i("gio", String.format("BlessedConnect: Notify set to 'off' for %s", characteristic.getUuid())); } @@ -205,6 +187,9 @@ thread.start(); } public void discoverCharacteristics(BluetoothPeripheral peripheral, BluetoothGattService serv) { + if (peripheral == null || serv == null) { + return; + } List chrs = serv.getCharacteristics(); for (BluetoothGattCharacteristic chr : chrs) { onDiscoverCharacteristic(peripheral.getAddress(), serv.getUuid().toString(), serv, chr.getUuid().toString(), chr); @@ -212,9 +197,15 @@ thread.start(); } public void readCharacteristic(BluetoothPeripheral peripheral, BluetoothGattCharacteristic chr) { + if (peripheral == null || chr == null) { + return; + } peripheral.readCharacteristic(chr); } public boolean setCharacteristicNotification(BluetoothPeripheral peripheral, BluetoothGattCharacteristic chr) { + if (peripheral == null || chr == null) { + return false; + } return peripheral.setNotify(chr, true); } @@ -269,4 +260,3 @@ thread.start(); static private native void onDiscoverCharacteristic(String id, String suuid, BluetoothGattService serv, String cuuid, BluetoothGattCharacteristic chr); static private native void characteristicChanged(String id, String cuuid, BluetoothGattCharacteristic chr, byte[] value, int length); } - diff --git a/ble_android.go b/ble_android.go index 779a94f..fff5776 100644 --- a/ble_android.go +++ b/ble_android.go @@ -24,7 +24,7 @@ import "C" // Types required for ble.go type bleHandle struct { - BleConnect C.jobject + BlessedConnect C.jobject state int } @@ -131,7 +131,7 @@ func (b *BLE) readyToScan() bool { connect() var ret bool runInJVM(func(env *C.JNIEnv) { - ret = C.enabled(env, b.handle.BleConnect) == C.JNI_TRUE + ret = C.enabled(env, b.handle.BlessedConnect) == C.JNI_TRUE }) return ret } @@ -140,7 +140,7 @@ func (b *BLE) readyToScan() bool { func (b *BLE) scan() { connect() runInJVM(func(env *C.JNIEnv) { - C.scan(env, b.handle.BleConnect); + C.scan(env, b.handle.BlessedConnect); }) } @@ -148,14 +148,14 @@ func (b *BLE) scan() { func (b *BLE) stopScan() { connect() runInJVM(func(env *C.JNIEnv) { - C.stopScan(env, b.handle.BleConnect); + C.stopScan(env, b.handle.BlessedConnect); }) } //connectPeripheral attempts to connect to a Peripheral func (b *BLE) connectPeripheral(x Peripheral) { runInJVM(func(env *C.JNIEnv) { - C.connect(env, b.handle.BleConnect, x.peripheral) + C.connect(env, b.handle.BlessedConnect, x.peripheral) }) } @@ -163,7 +163,7 @@ func (b *BLE) connectPeripheral(x Peripheral) { func (b *BLE) cancelConnection(p Peripheral) { connect() runInJVM(func(env *C.JNIEnv) { - C.disconnect(env, b.handle.BleConnect, p.peripheral) + C.disconnect(env, b.handle.BlessedConnect, p.peripheral) }) } @@ -177,12 +177,12 @@ func (b *BLE) knownPeripheral(p Peripheral) (Peripheral, bool) { //DiscoverServices asks a Peripheral for its Services func (p Peripheral) DiscoverServices() { //launch a goroutine because this function calls back directly - //from the same thread (underlying Java call is synchronous) + //from the same thread (the underlying Java call is synchronous) go func() { connect() log.Printf("discovering services") runInJVM(func(env *C.JNIEnv) { - C.discoverServices(env, gBLE.handle.BleConnect, p.peripheral) + C.discoverServices(env, gBLE.handle.BlessedConnect, p.peripheral) }) }() } @@ -191,23 +191,23 @@ func (p Peripheral) DiscoverServices() { //to a Service func (p Peripheral) DiscoverCharacteristics(serv Service) { //launch a goroutine because this function calls back directly - //from the same thread (underlying Java call is synchronous) + //from the same thread (the underlying Java call is synchronous) go func() { connect() log.Printf("discovering characteristics") runInJVM(func(env *C.JNIEnv) { - C.discoverCharacteristics(env, gBLE.handle.BleConnect, p.peripheral, serv.service) + C.discoverCharacteristics(env, gBLE.handle.BlessedConnect, p.peripheral, serv.service) }) - log.Printf("discovering characteristics done") }() } //SetNotifyValue subscribes to a characteristic func (p Peripheral) SetNotifyValue(c Characteristic) { runInJVM(func(env *C.JNIEnv) { - C.readCharacteristic(env, gBLE.handle.BleConnect, p.peripheral, c.characteristic) - //result := (C.setCharacteristicNotification(env, gBLE.handle.BleConnect, p.peripheral, c.characteristic) == C.JNI_TRUE) - //log.Printf("setCharacteristicNotification: %s = %t", c.UUID, result) + result := (C.setCharacteristicNotification(env, gBLE.handle.BlessedConnect, p.peripheral, c.characteristic) == C.JNI_TRUE) + if (!result) { + log.Printf("setCharacteristicNotification: %s failed", c.UUID) + } }) } @@ -236,10 +236,10 @@ func Java_st_wow_git_ble_BlessedConnect_installComplete(env *C.JNIEnv, class C.j if (b == 0) { log.Printf("BlessedConnect object is nil!") } - gBLE.handle.BleConnect = (C.NewGlobalRef)(env,b) + gBLE.handle.BlessedConnect = (C.NewGlobalRef)(env,b) h := app.PlatformHandle() setJVM(h.JVM) - if C.enabled(env, gBLE.handle.BleConnect) == C.JNI_TRUE { + if C.enabled(env, gBLE.handle.BlessedConnect) == C.JNI_TRUE { gBLE.handle.state = STATE_ON gBLE.ready = true gBLE.events <- UpdateStateEvent{State: gBLE.stringState()} @@ -384,8 +384,6 @@ func goOnDiscoverCharacteristic(cid, csuuid *C.char, serv C.jobject, ccuuid *C.c func goOnCharacteristicChanged(cid, ccuuid *C.char, char C.jobject, cvalue *C.char, length C.jint) { id := C.GoString(cid) cuuid := C.GoString(ccuuid) - log.Printf("goOnCharacteristicChanged: %s", cuuid) - log.Printf("goOnCharacteristicChanged: length = %d", length) var peripheral Peripheral found := false diff --git a/blessed-full.jar b/blessed-full.jar index cb9affac749bc6e3d52e24c25e7ca672947ea968..e6cd12a53c597a9cb4679160fd8c1d5e9c6c56dc 100644 GIT binary patch delta 15330 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 Q|H}$W1LcGF-x@&v4^zkKmH+?%