2
0
mirror of synced 2025-02-23 23:08:14 +00:00
mobile/exp/sensor/darwin_armx.go
Burcu Dogan 1b12574c99 exp/sensor: don't enable a sensor on a sender
The underlying implementation was not enabling the sensors on a
particular sender even though the Enable signature accepts different
instances of Sender to enable.

Consider the following program:

  type A struct{}
  func (a A) Send(ev interface{}) {}

  type B struct{}
  func (b B) Send(ev interface{}) {}

  sensor.Enable(A{}, sensor.Gyroscope, time.Millisecond)
  sensor.Enable(B{}, sensor.Accelerometer, time.Millisecond)

is going to compile but only A will be notified when there are new
gyroscope and accelerometer events.

In order to improve the misleading APIs, this CL introduces a
Notify function that users can register a Sender implementation to
listen the changes. If set nil, the sensor package will keep
reading the events but will won't notify.

  sensor.Notify(A{})
  sensor.Enable(sensor.Gyroscope, time.Millisecond)
  sensor.Enable(sensor.Accelerometer, time.Millisecond)

Change-Id: I25e43349e4ae682930baa2d32430f46f24b588b7
Reviewed-on: https://go-review.googlesource.com/15650
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
2015-10-19 21:21:50 +00:00

155 lines
3.4 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
// enable enables the sensor t on sender. A non-nil sender is
// required before calling enable.
func enable(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(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(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(&timestamp))
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.
sender.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
}