| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- // 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.
- //go:build darwin && (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(×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.
- 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
- }
|