diff --git a/BleConnect.java b/BleConnect.java index fea3cf2..49d046d 100644 --- a/BleConnect.java +++ b/BleConnect.java @@ -1,6 +1,9 @@ package st.wow.git.ble; import java.lang.Runnable; +import java.lang.String; +import java.util.List; +import java.util.UUID; import android.util.Log; import java.lang.Class; import java.lang.ClassLoader; @@ -12,6 +15,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothManager; @@ -26,6 +30,7 @@ import android.Manifest; public class BleConnect extends Fragment { BluetoothManager manager; BluetoothAdapter adapter; + Handler handler; final int PERMISSION_REQUEST = 1; @@ -42,9 +47,9 @@ public class BleConnect extends Fragment { manager = (BluetoothManager) ctx.getSystemService(ctx.BLUETOOTH_SERVICE); Log.d("gio", "BleUtil Enable: adapter"); adapter = manager.getAdapter(); + handler = new Handler(ctx.getMainLooper()); if (!enabled()) { Log.d("gio", "BleConnect: enabling adapter"); - Handler handler = new Handler(ctx.getMainLooper()); Intent enableBtIntent = new Intent(adapter.ACTION_REQUEST_ENABLE); Log.d("gio", "BleConnect: handler.post"); handler.post(new Runnable() { @@ -94,7 +99,11 @@ public class BleConnect extends Fragment { if (!enabled()) { return; } - adapter.startLeScan(scanCallback); + handler.post(new Runnable() { + public void run() { + adapter.startLeScan(scanCallback); + } + }); } public void stopScan() { @@ -102,68 +111,104 @@ public class BleConnect extends Fragment { return; } Log.d("gio", "Stop scan"); - adapter.stopLeScan(scanCallback); + handler.post(new Runnable() { + public void run() { + adapter.stopLeScan(scanCallback); + } + }); } - private BluetoothDevice device; - private BluetoothGatt bluetoothGatt; - private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { - if (newState == BluetoothProfile.STATE_CONNECTED) { - Log.d("gio", "Connected"); - String addr = device.getAddress(); - Log.d("gio", "Address = " + addr); - onConnect(device.getAddress()); + switch (newState) { + case BluetoothProfile.STATE_CONNECTED: { + BluetoothDevice device = gatt.getDevice(); + Log.d("gio", "Connected"); + String addr = device.getAddress(); + Log.d("gio", "Address = " + addr); + onConnect(gatt, device.getAddress()); + break; + } + case BluetoothProfile.STATE_DISCONNECTED: { + Log.d("gio", "Disconnected"); + break; + } + default: { + Log.d("gio", "onConnectionStateChange: unknown state"); + break; + } } } public void onServicesDiscovered(BluetoothGatt gatt, int status) { for (BluetoothGattService serv : gatt.getServices()) { - onDiscoverService(device.getAddress(), serv.getUuid().toString(), serv); + onDiscoverService(gatt.getDevice().getAddress(), serv.getUuid().toString(), serv); } } + public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic chr) { + byte[] v = chr.getValue(); + characteristicChanged(gatt.getDevice().getAddress(), chr.getUuid().toString(), chr, v, v.length); + } }; - public void connect(BluetoothDevice dev) { if (dev == null) { return; } Log.d("gio","BleConnect: connect"); - device = dev; - bluetoothGatt = dev.connectGatt(getContext(), false, gattCallback); + + handler.post(new Runnable() { + public void run() { + dev.connectGatt(getContext(), false, gattCallback, BluetoothDevice.TRANSPORT_LE); + } + }); } - public void disconnect() { - device = null; - if (bluetoothGatt == null) { + public void disconnect(BluetoothGatt gatt) { + if (gatt == null) { return; } Log.d("gio","BleConnect: disconnect"); - bluetoothGatt.disconnect(); + handler.post(new Runnable() { + public void run() { + gatt.disconnect(); + } + }); } - public void discoverServices(BluetoothDevice dev) { - if (bluetoothGatt == null || device == null) { + public void discoverServices(BluetoothGatt gatt) { + if (gatt == null) { return; } - if (!dev.getAddress().equals(device.getAddress())) { - disconnect(); - return; - } - bluetoothGatt.discoverServices(); + handler.post(new Runnable() { + public void run() { + gatt.discoverServices(); + } + }); } - public void discoverCharacteristics(BluetoothGattService serv) { + public void discoverCharacteristics(BluetoothGatt gatt, BluetoothGattService serv) { Log.d("gio","BleConnect: discoverCharacteristics()"); - if (bluetoothGatt == null || device == null) { + if (gatt == null) { + Log.d("gio","BleConnect: gatt == null"); return; } - for (BluetoothGattCharacteristic chr : serv.getCharacteristics()) { - Log.d("gio","BleConnect: -- " + chr.getUuid().toString()); - onDiscoverCharacteristic(device.getAddress(), serv.getUuid().toString(), serv, chr.getUuid().toString(), chr); + List 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) { @@ -186,8 +231,9 @@ public class BleConnect extends Fragment { 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(String id); + 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/ble.go b/ble.go index 306dd66..ba352ec 100644 --- a/ble.go +++ b/ble.go @@ -220,7 +220,7 @@ func connectTracker(b *BLE, x ConnectionListItem) bool { } go func() { - tick := time.NewTicker(time.Second * 5) + tick := time.NewTicker(time.Second * 60) select { case <-b.connections.close: fmt.Printf("connectTracker(): Closing connection to %s\n", x.p.Name) diff --git a/ble_android.go b/ble_android.go index 3d487b1..568bda1 100644 --- a/ble_android.go +++ b/ble_android.go @@ -8,9 +8,10 @@ package ble import ( "log" "sync" + "unsafe" "gioui.org/app" - _ "gioui.org/app/permission/bluetooth_le" + _ "gioui.org/app/permission/bluetooth" "git.wow.st/gmp/ble/gatt" ) @@ -34,6 +35,7 @@ type Peripheral struct { RSSI int Identifier string device C.jobject + gatt C.jobject } type Service struct { @@ -50,11 +52,18 @@ type Characteristic struct { var ( gBLE *BLE // FIXME: move to lookup tables as in ble_darwin.go? + + // FIXME: lifecycle, this may need to fire again? Or can I depend + // on my Fragment re-starting? Or call setRetained(true) from the + // fragment so we don't have to re-discover our BluetoothGatt and + // BluetoothDevice objects? installCompleteOnce sync.Once waitch chan struct{} ) const ( + // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html + // FIXME: create a type for these? STATE_OFF int = 10 STATE_TURNING_ON = 11 STATE_ON = 12 @@ -78,6 +87,9 @@ func peripheralLookup(p Peripheral) *BLE { } //newPeripheral creates a new Peripheral struct +// FIXME: check what happens with "incomplete" Peripherals that have only +// an Identifier set. Do the other functions on Peripherals do something +// sensible? func newPeripheral(name, id string, rssi int, dev C.jobject) Peripheral { return Peripheral{ Name: name, @@ -95,6 +107,7 @@ func (p Peripheral) IsIncomplete() bool { } } +// FIXME: should I call NewGlobalRef() here? func (p Peripheral) Retain() { } @@ -152,7 +165,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) + C.disconnect(env, b.handle.BleConnect, p.gatt) }) } @@ -164,11 +177,11 @@ func (b *BLE) knownPeripheral(p Peripheral) (Peripheral, bool) { } //DiscoverServices asks a Peripheral for its Services -func (x Peripheral) DiscoverServices() { +func (p Peripheral) DiscoverServices() { connect() log.Printf("discovering services") runInJVM(func(env *C.JNIEnv) { - C.discoverServices(env, gBLE.handle.BleConnect, x.device) + C.discoverServices(env, gBLE.handle.BleConnect, p.gatt) }) } @@ -181,7 +194,7 @@ func (p Peripheral) DiscoverCharacteristics(serv Service) { connect() log.Printf("discovering characteristics") runInJVM(func(env *C.JNIEnv) { - C.discoverCharacteristics(env, gBLE.handle.BleConnect, serv.service) + C.discoverCharacteristics(env, gBLE.handle.BleConnect, p.gatt, serv.service) }) log.Printf("discovering characteristics done") }() @@ -189,6 +202,10 @@ func (p Peripheral) DiscoverCharacteristics(serv Service) { //SetNotifyValue subscribes to a characteristic func (p Peripheral) SetNotifyValue(c Characteristic) { + runInJVM(func(env *C.JNIEnv) { + log.Printf("setCharacteristicNotification: %s", c.UUID) + C.setCharacteristicNotification(env, gBLE.handle.BleConnect, p.gatt, c.characteristic) + }) } //NewBLE returns a pointer to a BLE struct after setting up the OS @@ -205,11 +222,7 @@ func NewBLE() *BLE { //Enable func (b *BLE) Enable(w *app.Window) { log.Printf("ble.Enable()") - err := w.RegisterFragment("st/wow/git/ble/BleConnect") - log.Printf("ble.Enable() RegisterFragment() returned") - if err != nil { - log.Printf("Error! %s", err) - } + w.RegisterFragment("st/wow/git/ble/BleConnect") } // Go callbacks from Java @@ -258,16 +271,18 @@ func goOnScan(cname, cid *C.char, rssi C.int, dev C.jobject) { } //export goOnConnect -func goOnConnect(cid *C.char) { +func goOnConnect(gatt C.jobject, cid *C.char) { id := C.GoString(cid) var peripheral Peripheral found := false gBLE.peripherals.Lock() - for _, item := range gBLE.peripherals.items { + for n, item := range gBLE.peripherals.items { if item.p.Identifier == id { peripheral = item.p + peripheral.gatt = gatt + gBLE.peripherals.items[n].p = peripheral found = true break } @@ -278,6 +293,10 @@ func goOnConnect(cid *C.char) { log.Printf("Go: peripheral not found!") } + if peripheral.gatt == 0 { + log.Printf("goOnConnect(): gatt == null") + } + gBLE.connections.UpdateState(peripheral, "connected") gBLE.events <- ConnectEvent{peripheral} log.Printf("Go: goOnConnect returning\n") @@ -357,3 +376,40 @@ func goOnDiscoverCharacteristic(cid, csuuid *C.char, serv C.jobject, ccuuid *C.c Gatt: gatt.Characteristic{cuuid}, } } + +//export goOnCharacteristicChanged +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 + + gBLE.peripherals.Lock() + + for _, item := range gBLE.peripherals.items { + if item.p.Identifier == id { + peripheral = item.p + found = true + break + } + } + gBLE.peripherals.Unlock() + + if !found { + log.Printf("Go: peripheral not found!") + } + + characteristic := Characteristic{ + UUID: cuuid, + characteristic: char, + } + + gBLE.events <- UpdateValueEvent{ + Peripheral: peripheral, + Characteristic: characteristic, + Data: C.GoBytes(unsafe.Pointer(cvalue), length), + } +} diff --git a/gatt/gatt_android.go b/gatt/gatt_android.go index ba575f2..5b928e3 100644 --- a/gatt/gatt_android.go +++ b/gatt/gatt_android.go @@ -3,3 +3,7 @@ package gatt func (s Service) IsHRM() bool { return len(s.UUID) >= 8 && s.UUID[:8] == "0000180d" } + +func (c Characteristic) IsHRV() bool { + return len(c.UUID) >= 0 && c.UUID[:8] == "00002a37" +} diff --git a/gatt/gatt_darwin.go b/gatt/gatt_darwin.go index e941f47..87e20b7 100644 --- a/gatt/gatt_darwin.go +++ b/gatt/gatt_darwin.go @@ -3,3 +3,7 @@ package gatt func (s Service) IsHRM() bool { return s.UUID == "180D" } + +func (c Characteristic) IsHRV() bool { + return c.UUID == "2A37" +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..85db993 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module git.wow.st/gmp/ble + +go 1.13 + +require gioui.org v0.0.0-20191126175243-2ca2e5462f16 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4847b9f --- /dev/null +++ b/go.sum @@ -0,0 +1,24 @@ +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20191126175243-2ca2e5462f16 h1:p31rtmKm51xpj2QtqGNlljAyHEP1oStU8MDRl2Dv7Gs= +gioui.org v0.0.0-20191126175243-2ca2e5462f16/go.mod h1:KqFFi2Dq5gYA3FJ0sDOt8OBXoMsuxMtE8v2f0JExXAY= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/jni_android.c b/jni_android.c index bab0661..112f05f 100644 --- a/jni_android.c +++ b/jni_android.c @@ -28,28 +28,35 @@ void connect(JNIEnv *env, jobject b, jobject d) { jclass cls = (*env)->GetObjectClass(env, b); jmethodID mid = (*env)->GetMethodID(env, cls, "connect", "(Landroid/bluetooth/BluetoothDevice;)V"); - (*env)->CallVoidMethod(env, b, mid, d); + (*env)->CallObjectMethod(env, b, mid, d); } void -disconnect(JNIEnv *env, jobject b) { +disconnect(JNIEnv *env, jobject b, jobject g) { jclass cls = (*env)->GetObjectClass(env, b); - jmethodID mid = (*env)->GetMethodID(env, cls, "disconnect", "()V"); - (*env)->CallVoidMethod(env, b, mid); + jmethodID mid = (*env)->GetMethodID(env, cls, "disconnect", "(Landroid/bluetooth/BluetoothGatt;)V"); + (*env)->CallVoidMethod(env, b, mid, g); } void discoverServices(JNIEnv *env, jobject b, jobject p) { jclass cls = (*env)->GetObjectClass(env, b); - jmethodID mid = (*env)->GetMethodID(env, cls, "discoverServices", "(Landroid/bluetooth/BluetoothDevice;)V"); + jmethodID mid = (*env)->GetMethodID(env, cls, "discoverServices", "(Landroid/bluetooth/BluetoothGatt;)V"); (*env)->CallVoidMethod(env, b, mid, p); } void -discoverCharacteristics(JNIEnv *env, jobject b, jobject s) { +discoverCharacteristics(JNIEnv *env, jobject b, jobject g, jobject s) { jclass cls = (*env)->GetObjectClass(env, b); - jmethodID mid = (*env)->GetMethodID(env, cls, "discoverCharacteristics", "(Landroid/bluetooth/BluetoothGattService;)V"); - (*env)->CallVoidMethod(env, b, mid, s); + jmethodID mid = (*env)->GetMethodID(env, cls, "discoverCharacteristics", "(Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattService;)V"); + (*env)->CallVoidMethod(env, b, mid, g, s); +} + +void +setCharacteristicNotification(JNIEnv *env, jobject b, jobject g, jobject c) { + jclass cls = (*env)->GetObjectClass(env, b); + jmethodID mid = (*env)->GetMethodID(env, cls, "setCharacteristicNotification", "(Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattCharacteristic;)V"); + (*env)->CallVoidMethod(env, b, mid, g, c); } jint @@ -74,8 +81,8 @@ NewGlobalRef(JNIEnv *env, jobject o) { void Java_st_wow_git_ble_BleConnect_onScan(JNIEnv *env, jclass class, jstring jname, jstring jid, jint jrssi, jobject dev) { - char* name = (*env)->GetStringUTFChars(env, jname, NULL); - char* id = (*env)->GetStringUTFChars(env, jid, NULL); + const char* name = (*env)->GetStringUTFChars(env, jname, NULL); + const char* id = (*env)->GetStringUTFChars(env, jid, NULL); jobject gdev = (*env)->NewGlobalRef(env, dev); goOnScan(name, id, (int)jrssi, gdev); (*env)->ReleaseStringUTFChars(env, jname, name); @@ -83,16 +90,17 @@ Java_st_wow_git_ble_BleConnect_onScan(JNIEnv *env, jclass class, jstring jname, } void -Java_st_wow_git_ble_BleConnect_onConnect(JNIEnv *env, jclass class, jstring jid) { - char* id = (*env)->GetStringUTFChars(env, jid, NULL); - goOnConnect(id); +Java_st_wow_git_ble_BleConnect_onConnect(JNIEnv *env, jclass class, jobject gatt, jstring jid) { + const char* id = (*env)->GetStringUTFChars(env, jid, NULL); + jobject ggatt = (*env)->NewGlobalRef(env, gatt); + goOnConnect(ggatt, id); (*env)->ReleaseStringUTFChars(env, jid, id); } void Java_st_wow_git_ble_BleConnect_onDiscoverService(JNIEnv *env, jclass class, jstring jid, jstring juuid, jobject serv) { - char* id = (*env)->GetStringUTFChars(env, jid, NULL); - char* uuid = (*env)->GetStringUTFChars(env, juuid, NULL); + const char* id = (*env)->GetStringUTFChars(env, jid, NULL); + const char* uuid = (*env)->GetStringUTFChars(env, juuid, NULL); jobject gserv = (*env)->NewGlobalRef(env, serv); goOnDiscoverService(id, uuid, gserv); (*env)->ReleaseStringUTFChars(env, jid, id); @@ -101,12 +109,24 @@ Java_st_wow_git_ble_BleConnect_onDiscoverService(JNIEnv *env, jclass class, jstr void Java_st_wow_git_ble_BleConnect_onDiscoverCharacteristic(JNIEnv *env, jclass class, jstring jid, jstring jsuuid, jobject serv, jstring jcuuid, jobject chr) { - char* id = (*env)->GetStringUTFChars(env, jid, NULL); - char* suuid = (*env)->GetStringUTFChars(env, jsuuid, NULL); - char* cuuid = (*env)->GetStringUTFChars(env, jcuuid, NULL); + const char* id = (*env)->GetStringUTFChars(env, jid, NULL); + const char* suuid = (*env)->GetStringUTFChars(env, jsuuid, NULL); + const char* cuuid = (*env)->GetStringUTFChars(env, jcuuid, NULL); jobject gchr = (*env)->NewGlobalRef(env, chr); goOnDiscoverCharacteristic(id, suuid, serv, cuuid, gchr); (*env)->ReleaseStringUTFChars(env, jid, id); (*env)->ReleaseStringUTFChars(env, jsuuid, suuid); + (*env)->ReleaseStringUTFChars(env, jcuuid, cuuid); } + +void +Java_st_wow_git_ble_BleConnect_characteristicChanged(JNIEnv *env, jclass class, jstring jid, jstring jcuuid, jobject chr, jbyteArray jvalue, jint len) { + const char* id = (*env)->GetStringUTFChars(env, jid, NULL); + const char* cuuid = (*env)->GetStringUTFChars(env, jcuuid, NULL); + jbyte* value = (*env)->GetByteArrayElements(env, jvalue, NULL); + goOnCharacteristicChanged(id, cuuid, chr, value, len); + (*env)->ReleaseStringUTFChars(env, jid, id); + (*env)->ReleaseStringUTFChars(env, jcuuid, cuuid); + (*env)->ReleaseByteArrayElements(env, jvalue, value, len); +} diff --git a/jni_android.h b/jni_android.h index 784d0a1..da4f0ea 100644 --- a/jni_android.h +++ b/jni_android.h @@ -4,9 +4,10 @@ jboolean enabled(JNIEnv *env, jobject p); void scan(JNIEnv *env, jobject b); void stopScan(JNIEnv *env, jobject b); void connect(JNIEnv *env, jobject b, jobject d); -void disconnect(JNIEnv *env, jobject b); +void disconnect(JNIEnv *env, jobject b, jobject g); void discoverServices(JNIEnv *env, jobject b, jobject p); -void discoverCharacteristics(JNIEnv *env, jobject b, jobject s); +void discoverCharacteristics(JNIEnv *env, jobject b, jobject g, jobject s); +void setCharacteristicNotification(JNIEnv *env, jobject b, jobject g, jobject c); jint GetEnv(JavaVM *vm, JNIEnv **env, jint version); jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args); jint DetachCurrentThread(JavaVM *vm);