exp/sensor: remove the manager type
The manager type is not required, because the APIs don't allow more than one event sources as they used to. In this CL, I am flattening out the underlying implementations by removing the manager type. Change-Id: I3b606ac160b9cecd85cb657e3df1d7d789604764 Reviewed-on: https://go-review.googlesource.com/14293 Reviewed-by: Nigel Tao <nigeltao@golang.org>
This commit is contained in:
parent
043428404d
commit
c76d5c8830
@ -9,39 +9,38 @@
|
|||||||
|
|
||||||
#include <android/sensor.h>
|
#include <android/sensor.h>
|
||||||
|
|
||||||
#include "android.h"
|
#define GO_ANDROID_SENSOR_LOOPER_ID 100
|
||||||
|
|
||||||
void GoAndroid_createManager(int looperId, GoAndroid_SensorManager* dst) {
|
ASensorEventQueue* queue = NULL;
|
||||||
|
ALooper* looper = NULL;
|
||||||
|
|
||||||
|
void GoAndroid_createManager() {
|
||||||
ASensorManager* manager = ASensorManager_getInstance();
|
ASensorManager* manager = ASensorManager_getInstance();
|
||||||
|
looper = ALooper_forThread();
|
||||||
ALooper* looper = ALooper_forThread();
|
|
||||||
if (looper == NULL) {
|
if (looper == NULL) {
|
||||||
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
||||||
}
|
}
|
||||||
ASensorEventQueue* queue = ASensorManager_createEventQueue(manager, looper, looperId, NULL, NULL);
|
queue = ASensorManager_createEventQueue(manager, looper, GO_ANDROID_SENSOR_LOOPER_ID, NULL, NULL);
|
||||||
dst->looper = looper;
|
|
||||||
dst->queue = queue;
|
|
||||||
dst->looperId = looperId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int GoAndroid_enableSensor(ASensorEventQueue* q, int s, int32_t usec) {
|
int GoAndroid_enableSensor(int s, int32_t usec) {
|
||||||
ASensorManager* manager = ASensorManager_getInstance();
|
ASensorManager* manager = ASensorManager_getInstance();
|
||||||
const ASensor* sensor = ASensorManager_getDefaultSensor(manager, s);
|
const ASensor* sensor = ASensorManager_getDefaultSensor(manager, s);
|
||||||
if (sensor == NULL) {
|
if (sensor == NULL) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
ASensorEventQueue_enableSensor(q, sensor);
|
ASensorEventQueue_enableSensor(queue, sensor);
|
||||||
ASensorEventQueue_setEventRate(q, sensor, usec);
|
ASensorEventQueue_setEventRate(queue, sensor, usec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GoAndroid_disableSensor(ASensorEventQueue* q, int s) {
|
void GoAndroid_disableSensor(int s) {
|
||||||
ASensorManager* manager = ASensorManager_getInstance();
|
ASensorManager* manager = ASensorManager_getInstance();
|
||||||
const ASensor* sensor = ASensorManager_getDefaultSensor(manager, s);
|
const ASensor* sensor = ASensorManager_getDefaultSensor(manager, s);
|
||||||
ASensorEventQueue_disableSensor(q, sensor);
|
ASensorEventQueue_disableSensor(queue, sensor);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GoAndroid_readQueue(int looperId, ASensorEventQueue* q, int n, int32_t* types, int64_t* timestamps, float* vectors) {
|
int GoAndroid_readQueue(int n, int32_t* types, int64_t* timestamps, float* vectors) {
|
||||||
int id;
|
int id;
|
||||||
int events;
|
int events;
|
||||||
ASensorEvent event;
|
ASensorEvent event;
|
||||||
@ -50,10 +49,10 @@ int GoAndroid_readQueue(int looperId, ASensorEventQueue* q, int n, int32_t* type
|
|||||||
// If anytime timeout occurs, don't retry to read and immediately return.
|
// If anytime timeout occurs, don't retry to read and immediately return.
|
||||||
// Consume the event queue entirely between polls.
|
// Consume the event queue entirely between polls.
|
||||||
while (i < n && (id = ALooper_pollAll(-1, NULL, &events, NULL)) >= 0) {
|
while (i < n && (id = ALooper_pollAll(-1, NULL, &events, NULL)) >= 0) {
|
||||||
if (id != looperId) {
|
if (id != GO_ANDROID_SENSOR_LOOPER_ID) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
while (i < n && ASensorEventQueue_getEvents(q, &event, 1)) {
|
while (i < n && ASensorEventQueue_getEvents(queue, &event, 1)) {
|
||||||
types[i] = event.type;
|
types[i] = event.type;
|
||||||
timestamps[i] = event.timestamp;
|
timestamps[i] = event.timestamp;
|
||||||
vectors[i*3] = event.vector.x;
|
vectors[i*3] = event.vector.x;
|
||||||
@ -65,8 +64,8 @@ int GoAndroid_readQueue(int looperId, ASensorEventQueue* q, int n, int32_t* type
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GoAndroid_destroyManager(GoAndroid_SensorManager* m) {
|
void GoAndroid_destroyManager() {
|
||||||
ASensorManager* manager = ASensorManager_getInstance();
|
ASensorManager* manager = ASensorManager_getInstance();
|
||||||
ASensorManager_destroyEventQueue(manager, m->queue);
|
ASensorManager_destroyEventQueue(manager, queue);
|
||||||
ALooper_release(m->looper);
|
ALooper_release(looper);
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,17 @@ package sensor
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <android/sensor.h>
|
#include <android/sensor.h>
|
||||||
|
|
||||||
#include "android.h"
|
void GoAndroid_createManager();
|
||||||
|
void GoAndroid_destroyManager();
|
||||||
|
int GoAndroid_enableSensor(int, int32_t);
|
||||||
|
void GoAndroid_disableSensor(int);
|
||||||
|
int GoAndroid_readQueue(int n, int32_t* types, int64_t* timestamps, float* vectors);
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -32,8 +35,6 @@ var (
|
|||||||
collecting bool
|
collecting bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var nextLooperID int64 // each underlying ALooper should have a unique ID.
|
|
||||||
|
|
||||||
// initSignal initializes an underlying looper and event queue.
|
// initSignal initializes an underlying looper and event queue.
|
||||||
type initSignal struct{}
|
type initSignal struct{}
|
||||||
|
|
||||||
@ -69,43 +70,34 @@ type inOut struct {
|
|||||||
out chan struct{}
|
out chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// manager is the Android-specific implementation of Manager.
|
var inout = make(chan inOut)
|
||||||
type manager struct {
|
|
||||||
m *C.GoAndroid_SensorManager
|
|
||||||
inout chan inOut
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize inits the manager and creates a goroutine to proxy the CGO calls.
|
// init inits the manager and creates a goroutine to proxy the CGO calls.
|
||||||
// All actions related to an ALooper needs to be performed from the same
|
// All actions related to an ALooper needs to be performed from the same
|
||||||
// OS thread. The goroutine proxy locks itself to an OS thread and handles the
|
// OS thread. The goroutine proxy locks itself to an OS thread and handles the
|
||||||
// CGO traffic on the same thread.
|
// CGO traffic on the same thread.
|
||||||
func (m *manager) initialize() {
|
func init() {
|
||||||
m.inout = make(chan inOut)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
for {
|
for {
|
||||||
v := <-m.inout
|
v := <-inout
|
||||||
switch s := v.in.(type) {
|
switch s := v.in.(type) {
|
||||||
case initSignal:
|
case initSignal:
|
||||||
id := atomic.AddInt64(&nextLooperID, 1)
|
C.GoAndroid_createManager()
|
||||||
var mgr C.GoAndroid_SensorManager
|
|
||||||
C.GoAndroid_createManager(C.int(id), &mgr)
|
|
||||||
m.m = &mgr
|
|
||||||
case enableSignal:
|
case enableSignal:
|
||||||
usecsDelay := s.delay.Nanoseconds() / 1000
|
usecsDelay := s.delay.Nanoseconds() / 1000
|
||||||
code := int(C.GoAndroid_enableSensor(m.m.queue, typeToInt(s.t), C.int32_t(usecsDelay)))
|
code := int(C.GoAndroid_enableSensor(typeToInt(s.t), C.int32_t(usecsDelay)))
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
*s.err = fmt.Errorf("sensor: no default %v sensor on the device", s.t)
|
*s.err = fmt.Errorf("sensor: no default %v sensor on the device", s.t)
|
||||||
}
|
}
|
||||||
case disableSignal:
|
case disableSignal:
|
||||||
C.GoAndroid_disableSensor(m.m.queue, typeToInt(s.t))
|
C.GoAndroid_disableSensor(typeToInt(s.t))
|
||||||
case readSignal:
|
case readSignal:
|
||||||
n, err := readEvents(m, s.dst)
|
n, err := readEvents(s.dst)
|
||||||
*s.n = n
|
*s.n = n
|
||||||
*s.err = err
|
*s.err = err
|
||||||
case closeSignal:
|
case closeSignal:
|
||||||
C.GoAndroid_destroyManager(m.m)
|
C.GoAndroid_destroyManager()
|
||||||
close(v.out)
|
close(v.out)
|
||||||
return // we don't need this goroutine anymore
|
return // we don't need this goroutine anymore
|
||||||
}
|
}
|
||||||
@ -113,22 +105,20 @@ func (m *manager) initialize() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if m.m == nil {
|
done := make(chan struct{})
|
||||||
done := make(chan struct{})
|
inout <- inOut{
|
||||||
m.inout <- inOut{
|
in: initSignal{},
|
||||||
in: initSignal{},
|
out: done,
|
||||||
out: done,
|
|
||||||
}
|
|
||||||
<-done
|
|
||||||
}
|
}
|
||||||
|
<-done
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) enable(s Sender, t Type, delay time.Duration) error {
|
func enable(s Sender, t Type, delay time.Duration) error {
|
||||||
m.startCollecting(s)
|
startCollecting(s)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
m.inout <- inOut{
|
inout <- inOut{
|
||||||
in: enableSignal{t: t, delay: delay, err: &err},
|
in: enableSignal{t: t, delay: delay, err: &err},
|
||||||
out: done,
|
out: done,
|
||||||
}
|
}
|
||||||
@ -136,7 +126,7 @@ func (m *manager) enable(s Sender, t Type, delay time.Duration) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) startCollecting(s Sender) {
|
func startCollecting(s Sender) {
|
||||||
collectingMu.Lock()
|
collectingMu.Lock()
|
||||||
defer collectingMu.Unlock()
|
defer collectingMu.Unlock()
|
||||||
|
|
||||||
@ -159,7 +149,7 @@ func (m *manager) startCollecting(s Sender) {
|
|||||||
// TODO(jbd): readSignal is not required anymore. Use the proxying
|
// TODO(jbd): readSignal is not required anymore. Use the proxying
|
||||||
// goroutine to continously poll the queue and send the events to s.
|
// goroutine to continously poll the queue and send the events to s.
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
m.inout <- inOut{
|
inout <- inOut{
|
||||||
in: readSignal{dst: ev, n: &n, err: &err},
|
in: readSignal{dst: ev, n: &n, err: &err},
|
||||||
out: done,
|
out: done,
|
||||||
}
|
}
|
||||||
@ -171,9 +161,9 @@ func (m *manager) startCollecting(s Sender) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) disable(t Type) error {
|
func disable(t Type) error {
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
m.inout <- inOut{
|
inout <- inOut{
|
||||||
in: disableSignal{t: t},
|
in: disableSignal{t: t},
|
||||||
out: done,
|
out: done,
|
||||||
}
|
}
|
||||||
@ -181,14 +171,13 @@ func (m *manager) disable(t Type) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readEvents(m *manager, e []Event) (n int, err error) {
|
func readEvents(e []Event) (n int, err error) {
|
||||||
num := len(e)
|
num := len(e)
|
||||||
types := make([]C.int32_t, num)
|
types := make([]C.int32_t, num)
|
||||||
timestamps := make([]C.int64_t, num)
|
timestamps := make([]C.int64_t, num)
|
||||||
vectors := make([]C.float, 3*num)
|
vectors := make([]C.float, 3*num)
|
||||||
|
|
||||||
n = int(C.GoAndroid_readQueue(
|
n = int(C.GoAndroid_readQueue(
|
||||||
m.m.looperId, m.m.queue,
|
|
||||||
C.int(num),
|
C.int(num),
|
||||||
(*C.int32_t)(unsafe.Pointer(&types[0])),
|
(*C.int32_t)(unsafe.Pointer(&types[0])),
|
||||||
(*C.int64_t)(unsafe.Pointer(×tamps[0])),
|
(*C.int64_t)(unsafe.Pointer(×tamps[0])),
|
||||||
@ -208,10 +197,10 @@ func readEvents(m *manager, e []Event) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jbd): Remove close?
|
// TODO(jbd): Remove destroy?
|
||||||
func (m *manager) close() error {
|
func destroy() error {
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
m.inout <- inOut{
|
inout <- inOut{
|
||||||
in: closeSignal{},
|
in: closeSignal{},
|
||||||
out: done,
|
out: done,
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build android
|
|
||||||
|
|
||||||
#ifndef GO_SENSORS_ANDROID_H
|
|
||||||
#define GO_SENSORS_ANDROID_H
|
|
||||||
|
|
||||||
typedef struct GoAndroid_SensorManager {
|
|
||||||
ASensorEventQueue* queue;
|
|
||||||
ALooper* looper;
|
|
||||||
int looperId;
|
|
||||||
} GoAndroid_SensorManager;
|
|
||||||
|
|
||||||
void GoAndroid_createManager(int looperId, GoAndroid_SensorManager* dst);
|
|
||||||
void GoAndroid_destroyManager(GoAndroid_SensorManager* m);
|
|
||||||
int GoAndroid_enableSensor(ASensorEventQueue*, int, int32_t);
|
|
||||||
void GoAndroid_disableSensor(ASensorEventQueue*, int);
|
|
||||||
int GoAndroid_readQueue(int looperId, ASensorEventQueue* q, int n, int32_t* types, int64_t* timestamps, float* vectors);
|
|
||||||
|
|
||||||
#endif
|
|
@ -42,10 +42,7 @@ var channels struct {
|
|||||||
done [nTypes]chan struct{}
|
done [nTypes]chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type manager struct {
|
func init() {
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manager) initialize() {
|
|
||||||
C.GoIOS_createManager()
|
C.GoIOS_createManager()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +60,7 @@ func (m *manager) initialize() {
|
|||||||
|
|
||||||
const minDelay = 10 * time.Millisecond
|
const minDelay = 10 * time.Millisecond
|
||||||
|
|
||||||
func (m *manager) enable(s Sender, t Type, delay time.Duration) error {
|
func enable(s Sender, t Type, delay time.Duration) error {
|
||||||
channels.Lock()
|
channels.Lock()
|
||||||
defer channels.Unlock()
|
defer channels.Unlock()
|
||||||
|
|
||||||
@ -85,11 +82,11 @@ func (m *manager) enable(s Sender, t Type, delay time.Duration) error {
|
|||||||
case Magnetometer:
|
case Magnetometer:
|
||||||
C.GoIOS_startMagneto(interval)
|
C.GoIOS_startMagneto(interval)
|
||||||
}
|
}
|
||||||
go m.pollSensor(s, t, delay, channels.done[t])
|
go pollSensor(s, t, delay, channels.done[t])
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) disable(t Type) error {
|
func disable(t Type) error {
|
||||||
channels.Lock()
|
channels.Lock()
|
||||||
defer channels.Unlock()
|
defer channels.Unlock()
|
||||||
|
|
||||||
@ -110,7 +107,7 @@ func (m *manager) disable(t Type) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) pollSensor(s Sender, t Type, d time.Duration, done chan struct{}) {
|
func pollSensor(s Sender, t Type, d time.Duration, done chan struct{}) {
|
||||||
var lastTimestamp int64
|
var lastTimestamp int64
|
||||||
|
|
||||||
var timestamp C.int64_t
|
var timestamp C.int64_t
|
||||||
@ -148,8 +145,8 @@ func (m *manager) pollSensor(s Sender, t Type, d time.Duration, done chan struct
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jbd): Remove close?
|
// TODO(jbd): Remove destroy?
|
||||||
func (m *manager) close() error {
|
func destroy() error {
|
||||||
C.GoIOS_destroyManager()
|
C.GoIOS_destroyManager()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -11,18 +11,14 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type manager struct{}
|
func enable(s Sender, t Type, delay time.Duration) error {
|
||||||
|
|
||||||
func (m *manager) initialize() {}
|
|
||||||
|
|
||||||
func (m *manager) enable(s Sender, t Type, delay time.Duration) error {
|
|
||||||
return errors.New("sensor: no sensors available")
|
return errors.New("sensor: no sensors available")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) disable(t Type) error {
|
func disable(t Type) error {
|
||||||
return errors.New("sensor: no sensors available")
|
return errors.New("sensor: no sensors available")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) close() error {
|
func destroy() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ type Type int
|
|||||||
|
|
||||||
var sensorNames = map[Type]string{
|
var sensorNames = map[Type]string{
|
||||||
Accelerometer: "Accelerometer",
|
Accelerometer: "Accelerometer",
|
||||||
Gyroscope: "Gyrsocope",
|
Gyroscope: "Gyroscope",
|
||||||
Magnetometer: "Magnetometer",
|
Magnetometer: "Magnetometer",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,9 +71,6 @@ type Sender interface {
|
|||||||
Send(event interface{})
|
Send(event interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// m is the underlying platform-specific sensor manager.
|
|
||||||
var m = newManager()
|
|
||||||
|
|
||||||
// Enable enables the specified sensor type with the given delay rate.
|
// Enable enables the specified sensor type with the given delay rate.
|
||||||
// Sensor events will be sent to s, a typical example of Sender
|
// Sensor events will be sent to s, a typical example of Sender
|
||||||
// implementations is app.App.
|
// implementations is app.App.
|
||||||
@ -82,7 +79,7 @@ func Enable(s Sender, t Type, delay time.Duration) error {
|
|||||||
if t < 0 || int(t) >= len(sensorNames) {
|
if t < 0 || int(t) >= len(sensorNames) {
|
||||||
return errors.New("sensor: unknown sensor type")
|
return errors.New("sensor: unknown sensor type")
|
||||||
}
|
}
|
||||||
return m.enable(s, t, delay)
|
return enable(s, t, delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable disables to feed the manager with the specified sensor.
|
// Disable disables to feed the manager with the specified sensor.
|
||||||
@ -91,13 +88,5 @@ func Disable(t Type) error {
|
|||||||
if t < 0 || int(t) >= len(sensorNames) {
|
if t < 0 || int(t) >= len(sensorNames) {
|
||||||
return errors.New("sensor: unknown sensor type")
|
return errors.New("sensor: unknown sensor type")
|
||||||
}
|
}
|
||||||
return m.disable(t)
|
return disable(t)
|
||||||
}
|
|
||||||
|
|
||||||
func newManager() *manager {
|
|
||||||
// TODO(jbd): manager type is unnecessary, flatten out the
|
|
||||||
// platform specific implementation.
|
|
||||||
mgr := new(manager)
|
|
||||||
mgr.initialize()
|
|
||||||
return mgr
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user