Further restructuring and add stub implementation for Android.
This commit is contained in:
parent
206bd70461
commit
f036c5e134
2
ble.go
2
ble.go
|
@ -245,7 +245,7 @@ func (b *BLE) Connect(p Peripheral) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
b.Unlock()
|
b.Unlock()
|
||||||
if p.p == nil {
|
if p.IsIncomplete() {
|
||||||
var ok bool
|
var ok bool
|
||||||
p, ok = b.knownPeripheral(p)
|
p, ok = b.knownPeripheral(p)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
103
ble_android.go
Normal file
103
ble_android.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package ble
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gioui.org/app"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Types required for ble.go
|
||||||
|
|
||||||
|
type bleState string
|
||||||
|
|
||||||
|
type bleHandle struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type Peripheral struct {
|
||||||
|
Name string
|
||||||
|
RSSI int
|
||||||
|
Identifier string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service string
|
||||||
|
type Characteristic string
|
||||||
|
|
||||||
|
// Internal global variables
|
||||||
|
|
||||||
|
// Functions required by API
|
||||||
|
|
||||||
|
//Init needs to be called before the BLE library can be used. On Android we
|
||||||
|
//need to set up the JVM by calling setJVM in jni_android.go.
|
||||||
|
func Init() {
|
||||||
|
h := app.PlatformHandle()
|
||||||
|
setJVM(h.JVM, h.Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
//peripheralLookup returns a pointer to a BLE struct related to the given
|
||||||
|
//Peripheral.
|
||||||
|
func peripheralLookup(p Peripheral) *BLE {
|
||||||
|
return &BLE{}
|
||||||
|
}
|
||||||
|
|
||||||
|
//newPeripheral creates a new Peripheral struct
|
||||||
|
func newPeripheral() Peripheral {
|
||||||
|
return Peripheral{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Peripheral) IsIncomplete() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Peripheral) Retain() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//stringState returns a string version of the BLE state
|
||||||
|
func (b *BLE) stringState() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//readyToScan returns true if the hardware is ready to initiate a scan
|
||||||
|
func (b *BLE) readyToScan() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//scan puts the BLE hardware into scanning mode
|
||||||
|
func (b *BLE) scan() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//stopScan stops a scan in progress
|
||||||
|
func (b *BLE) stopScan() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//connectPeripheral attempts to connect to a Peripheral
|
||||||
|
func (b *BLE) connectPeripheral(x Peripheral) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//cancelConnection cancels an in-progress connection attempt
|
||||||
|
func (b *BLE) cancelConnection(p Peripheral) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//knownPeripheral returns a Peripheral that is known to the system without
|
||||||
|
//scanning
|
||||||
|
func (b *BLE) knownPeripheral(p Peripheral) (Peripheral, bool) {
|
||||||
|
return Peripheral{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
//DiscoverServices asks a Peripheral for its Services
|
||||||
|
func (x Peripheral) DiscoverServices() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//DiscoverCharacteristics asks a Peripheral for the Characteristics related
|
||||||
|
//to a Service
|
||||||
|
func (p Peripheral) DiscoverCharacteristics(serv Service) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//SetNotifyValue subscribes to a characteristic
|
||||||
|
func (p Peripheral) SetNotifyValue(c Characteristic) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewBLE returns a pointer to a BLE struct after setting up the OS
|
||||||
|
//Bluetooth API.
|
||||||
|
func NewBLE() *BLE {
|
||||||
|
ps := Peripherals{items: make([]PeripheralListItem, 0)}
|
||||||
|
return &BLE{events: make(chan interface{}), peripherals: ps}
|
||||||
|
}
|
||||||
|
|
|
@ -21,10 +21,6 @@ type bleHandle struct {
|
||||||
cm *ns.CBCentralManager
|
cm *ns.CBCentralManager
|
||||||
}
|
}
|
||||||
|
|
||||||
var cdLookup map[unsafe.Pointer]*BLE
|
|
||||||
var pdLookup map[unsafe.Pointer]*BLE
|
|
||||||
var pcache map[unsafe.Pointer]*Peripheral
|
|
||||||
|
|
||||||
type Peripheral struct {
|
type Peripheral struct {
|
||||||
Name string
|
Name string
|
||||||
RSSI int
|
RSSI int
|
||||||
|
@ -36,11 +32,13 @@ type Peripheral struct {
|
||||||
type Service *ns.CBService
|
type Service *ns.CBService
|
||||||
type Characteristic *ns.CBCharacteristic
|
type Characteristic *ns.CBCharacteristic
|
||||||
|
|
||||||
// Functions required by API
|
// Internal global variables
|
||||||
|
|
||||||
func peripheralLookup(p Peripheral) *BLE {
|
var cdLookup map[unsafe.Pointer]*BLE
|
||||||
return pdLookup[p.p.Ptr()]
|
var pdLookup map[unsafe.Pointer]*BLE
|
||||||
}
|
var pcache map[unsafe.Pointer]*Peripheral
|
||||||
|
|
||||||
|
// Functions required by API
|
||||||
|
|
||||||
//Init needs to be called before the BLE library can be used. No setup needed
|
//Init needs to be called before the BLE library can be used. No setup needed
|
||||||
//on Darwin.
|
//on Darwin.
|
||||||
|
@ -48,6 +46,12 @@ func Init() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//peripheralLookup returns a pointer to a BLE struct related to the given
|
||||||
|
//Peripheral.
|
||||||
|
func peripheralLookup(p Peripheral) *BLE {
|
||||||
|
return pdLookup[p.p.Ptr()]
|
||||||
|
}
|
||||||
|
|
||||||
//newPeripheral creates a new Peripheral struct
|
//newPeripheral creates a new Peripheral struct
|
||||||
func newPeripheral(x *ns.CBPeripheral) Peripheral {
|
func newPeripheral(x *ns.CBPeripheral) Peripheral {
|
||||||
if pcache == nil {
|
if pcache == nil {
|
||||||
|
@ -66,6 +70,19 @@ func newPeripheral(x *ns.CBPeripheral) Peripheral {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Peripheral) IsIncomplete() bool {
|
||||||
|
return p.p == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x Peripheral) Retain() {
|
||||||
|
//NOTE: ns.ObjectAtIndex() calls SetFinalizer for us, which will be a problem
|
||||||
|
//later when we call GC(), so we always first clear the finalizer before
|
||||||
|
//setting a new one.
|
||||||
|
runtime.SetFinalizer(x.p, nil)
|
||||||
|
x.p.Retain()
|
||||||
|
x.p.GC()
|
||||||
|
}
|
||||||
|
|
||||||
//stringState returns a string version of the BLE state
|
//stringState returns a string version of the BLE state
|
||||||
func (b *BLE) stringState() string {
|
func (b *BLE) stringState() string {
|
||||||
x := b.state
|
x := b.state
|
||||||
|
@ -319,15 +336,6 @@ func peripheralName(p *ns.CBPeripheral) string {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Peripheral) Retain() {
|
|
||||||
//NOTE: ns.ObjectAtIndex() calls SetFinalizer for us, which will be a problem
|
|
||||||
//later when we call GC(), so we always first clear the finalizer before
|
|
||||||
//setting a new one.
|
|
||||||
runtime.SetFinalizer(x.p, nil)
|
|
||||||
x.p.Retain()
|
|
||||||
x.p.GC()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BLE) setState(x ns.CBManagerState) {
|
func (b *BLE) setState(x ns.CBManagerState) {
|
||||||
b.Lock()
|
b.Lock()
|
||||||
defer b.Unlock()
|
defer b.Unlock()
|
||||||
|
|
131
jni_android.go
Normal file
131
jni_android.go
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package ble
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -landroid
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <jni.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
static jobject gClassLoader;
|
||||||
|
static jmethodID gFindClassMethod;
|
||||||
|
|
||||||
|
void
|
||||||
|
SetLoader(JNIEnv* env, jobject context) {
|
||||||
|
jclass cclass = (*env)->GetObjectClass(env, context);
|
||||||
|
jmethodID gcl_id = (*env)->GetMethodID(env, cclass, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
||||||
|
jobject loader = (*env)->CallObjectMethod(env, context, gcl_id);
|
||||||
|
gClassLoader = (*env)->NewGlobalRef(env, loader);
|
||||||
|
jclass lclass = (*env)->GetObjectClass(env, loader);
|
||||||
|
gFindClassMethod = (*env)->GetMethodID(env, lclass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass
|
||||||
|
FindClass(JNIEnv* env, char* name) {
|
||||||
|
jstring strClassName = (*env)->NewStringUTF(env, name);
|
||||||
|
return (*env)->CallObjectMethod(env, gClassLoader, gFindClassMethod, strClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject
|
||||||
|
CreateObject(JNIEnv* env, jclass cls) {
|
||||||
|
jmethodID init = (*env)->GetMethodID(env, cls, "<init>", "()V");
|
||||||
|
return (*env)->NewObject(env, cls, init);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID) {
|
||||||
|
(*env)->CallVoidMethod(env, obj, methodID);
|
||||||
|
}
|
||||||
|
|
||||||
|
jint CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID) {
|
||||||
|
return (*env)->CallIntMethod(env, obj, methodID);
|
||||||
|
}
|
||||||
|
|
||||||
|
jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
|
||||||
|
return (*env)->GetMethodID(env, clazz, name, sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
jint GetEnv(JavaVM *vm, JNIEnv **env, jint version) {
|
||||||
|
return (*vm)->GetEnv(vm, (void **)env, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args) {
|
||||||
|
return (*vm)->AttachCurrentThread(vm, p_env, thr_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
jint DetachCurrentThread(JavaVM *vm) {
|
||||||
|
return (*vm)->DetachCurrentThread(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var theJVM *C.JavaVM
|
||||||
|
|
||||||
|
type JNIEnv = C.JNIEnv
|
||||||
|
|
||||||
|
func setJVM(jvm, context uintptr) {
|
||||||
|
log.Print("set theJVM")
|
||||||
|
theJVM = (*C.JavaVM)(unsafe.Pointer(jvm))
|
||||||
|
log.Printf("theJVM = %d", uintptr(unsafe.Pointer(theJVM)))
|
||||||
|
RunInJVM(func(env *C.JNIEnv) {
|
||||||
|
C.SetLoader(env, (C.jobject)(context))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindClass(env *C.JNIEnv, name string) C.jclass {
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
return C.FindClass((*C.JNIEnv)(env), cname)
|
||||||
|
}
|
||||||
|
|
||||||
|
func JniCallVoidMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) {
|
||||||
|
C.CallVoidMethod(env, obj, methodID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func JniCallIntMethod(env *C.JNIEnv, obj C.jobject, methodID C.jmethodID) int {
|
||||||
|
return (int)(C.CallIntMethod(env, obj, methodID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func JniGetMethodID(env *C.JNIEnv, cls C.jclass, name, sig string) C.jmethodID {
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
csig := C.CString(sig)
|
||||||
|
defer C.free(unsafe.Pointer(csig))
|
||||||
|
return C.GetMethodID(env, cls, cname, csig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateObject(env *C.JNIEnv, cls C.jclass) C.jobject {
|
||||||
|
return C.CreateObject(env, (C.jclass)(cls))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunInJVM(f func(env *C.JNIEnv)) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
var env *C.JNIEnv
|
||||||
|
var detach bool
|
||||||
|
log.Printf("RunInJVM(): theJVM = %d", uintptr(unsafe.Pointer(theJVM)))
|
||||||
|
if res := C.GetEnv(theJVM, &env, C.JNI_VERSION_1_6); res != C.JNI_OK {
|
||||||
|
if res != C.JNI_EDETACHED {
|
||||||
|
panic(fmt.Errorf("JNI GetEnv failed with error %d", res))
|
||||||
|
}
|
||||||
|
if C.AttachCurrentThread(theJVM, &env, nil) != C.JNI_OK {
|
||||||
|
panic(errors.New("runInJVM: AttachCurrentThread failed"))
|
||||||
|
}
|
||||||
|
detach = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if detach {
|
||||||
|
defer func() {
|
||||||
|
C.DetachCurrentThread(theJVM)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
f(env)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user