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>
153 lines
3.3 KiB
Go
153 lines
3.3 KiB
Go
// 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 darwin
|
|
// +build arm arm64
|
|
|
|
package sensor
|
|
|
|
/*
|
|
#cgo CFLAGS: -x objective-c
|
|
#cgo LDFLAGS: -framework CoreMotion
|
|
|
|
#import <stdlib.h>
|
|
|
|
void GoIOS_createManager();
|
|
|
|
void GoIOS_startAccelerometer(float interval);
|
|
void GoIOS_stopAccelerometer();
|
|
void GoIOS_readAccelerometer(int64_t* timestamp, float* vector);
|
|
|
|
void GoIOS_startGyro(float interval);
|
|
void GoIOS_stopGyro();
|
|
void GoIOS_readGyro(int64_t* timestamp, float* vector);
|
|
|
|
void GoIOS_startMagneto(float interval);
|
|
void GoIOS_stopMagneto();
|
|
void GoIOS_readMagneto(int64_t* timestamp, float* vector);
|
|
|
|
void GoIOS_destroyManager();
|
|
*/
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
var channels struct {
|
|
sync.Mutex
|
|
done [nTypes]chan struct{}
|
|
}
|
|
|
|
func init() {
|
|
C.GoIOS_createManager()
|
|
}
|
|
|
|
// minDelay is the minimum delay allowed.
|
|
//
|
|
// From Event Handling Guide for iOS:
|
|
//
|
|
// "You can set the reporting interval to be as small as 10
|
|
// milliseconds (ms), which corresponds to a 100 Hz update rate,
|
|
// but most app operate sufficiently with a larger interval."
|
|
//
|
|
// There is no need to poll more frequently than once every 10ms.
|
|
//
|
|
// https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/motion_event_basics/motion_event_basics.html
|
|
|
|
const minDelay = 10 * time.Millisecond
|
|
|
|
func enable(s Sender, t Type, delay time.Duration) error {
|
|
channels.Lock()
|
|
defer channels.Unlock()
|
|
|
|
if channels.done[t] != nil {
|
|
return fmt.Errorf("sensor: cannot enable; %v sensor is already enabled", t)
|
|
}
|
|
channels.done[t] = make(chan struct{})
|
|
|
|
if delay < minDelay {
|
|
delay = minDelay
|
|
}
|
|
interval := C.float(float64(delay) / float64(time.Second))
|
|
|
|
switch t {
|
|
case Accelerometer:
|
|
C.GoIOS_startAccelerometer(interval)
|
|
case Gyroscope:
|
|
C.GoIOS_startGyro(interval)
|
|
case Magnetometer:
|
|
C.GoIOS_startMagneto(interval)
|
|
}
|
|
go pollSensor(s, t, delay, channels.done[t])
|
|
return nil
|
|
}
|
|
|
|
func disable(t Type) error {
|
|
channels.Lock()
|
|
defer channels.Unlock()
|
|
|
|
if channels.done[t] == nil {
|
|
return fmt.Errorf("sensor: cannot disable; %v sensor is not enabled", t)
|
|
}
|
|
close(channels.done[t])
|
|
channels.done[t] = nil
|
|
|
|
switch t {
|
|
case Accelerometer:
|
|
C.GoIOS_stopAccelerometer()
|
|
case Gyroscope:
|
|
C.GoIOS_stopGyro()
|
|
case Magnetometer:
|
|
C.GoIOS_stopMagneto()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func pollSensor(s Sender, t Type, d time.Duration, done chan struct{}) {
|
|
var lastTimestamp int64
|
|
|
|
var timestamp C.int64_t
|
|
var ev [3]C.float
|
|
|
|
for {
|
|
select {
|
|
case <-done:
|
|
return
|
|
default:
|
|
tp := (*C.int64_t)(unsafe.Pointer(×tamp))
|
|
vp := (*C.float)(unsafe.Pointer(&ev[0]))
|
|
|
|
switch t {
|
|
case Accelerometer:
|
|
C.GoIOS_readAccelerometer(tp, vp)
|
|
case Gyroscope:
|
|
C.GoIOS_readGyro(tp, vp)
|
|
case Magnetometer:
|
|
C.GoIOS_readMagneto(tp, vp)
|
|
}
|
|
ts := int64(timestamp)
|
|
if ts > lastTimestamp {
|
|
// TODO(jbd): Do we need to convert the values to another unit?
|
|
// How does iOS units compare to the Android units.
|
|
s.Send(Event{
|
|
Sensor: t,
|
|
Timestamp: ts,
|
|
Data: []float64{float64(ev[0]), float64(ev[1]), float64(ev[2])},
|
|
})
|
|
lastTimestamp = ts
|
|
time.Sleep(d / 2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO(jbd): Remove destroy?
|
|
func destroy() error {
|
|
C.GoIOS_destroyManager()
|
|
return nil
|
|
}
|