github.com/SkycoinProject/gomobile@v0.0.0-20190312151609-d3739f865fa6/exp/sensor/darwin_armx.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build darwin
     6  // +build arm arm64
     7  
     8  package sensor
     9  
    10  /*
    11  #cgo CFLAGS: -x objective-c
    12  #cgo LDFLAGS: -framework CoreMotion
    13  
    14  #import <stdlib.h>
    15  
    16  void GoIOS_createManager();
    17  
    18  void GoIOS_startAccelerometer(float interval);
    19  void GoIOS_stopAccelerometer();
    20  void GoIOS_readAccelerometer(int64_t* timestamp, float* vector);
    21  
    22  void GoIOS_startGyro(float interval);
    23  void GoIOS_stopGyro();
    24  void GoIOS_readGyro(int64_t* timestamp, float* vector);
    25  
    26  void GoIOS_startMagneto(float interval);
    27  void GoIOS_stopMagneto();
    28  void GoIOS_readMagneto(int64_t* timestamp, float* vector);
    29  
    30  void GoIOS_destroyManager();
    31  */
    32  import "C"
    33  import (
    34  	"fmt"
    35  	"sync"
    36  	"time"
    37  	"unsafe"
    38  )
    39  
    40  var channels struct {
    41  	sync.Mutex
    42  	done [nTypes]chan struct{}
    43  }
    44  
    45  func init() {
    46  	C.GoIOS_createManager()
    47  }
    48  
    49  // minDelay is the minimum delay allowed.
    50  //
    51  // From Event Handling Guide for iOS:
    52  //
    53  // "You can set the reporting interval to be as small as 10
    54  // milliseconds (ms), which corresponds to a 100 Hz update rate,
    55  // but most app operate sufficiently with a larger interval."
    56  //
    57  // There is no need to poll more frequently than once every 10ms.
    58  //
    59  // https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/motion_event_basics/motion_event_basics.html
    60  
    61  const minDelay = 10 * time.Millisecond
    62  
    63  // enable enables the sensor t on sender. A non-nil sender is
    64  // required before calling enable.
    65  func enable(t Type, delay time.Duration) error {
    66  	channels.Lock()
    67  	defer channels.Unlock()
    68  
    69  	if channels.done[t] != nil {
    70  		return fmt.Errorf("sensor: cannot enable; %v sensor is already enabled", t)
    71  	}
    72  	channels.done[t] = make(chan struct{})
    73  
    74  	if delay < minDelay {
    75  		delay = minDelay
    76  	}
    77  	interval := C.float(float64(delay) / float64(time.Second))
    78  
    79  	switch t {
    80  	case Accelerometer:
    81  		C.GoIOS_startAccelerometer(interval)
    82  	case Gyroscope:
    83  		C.GoIOS_startGyro(interval)
    84  	case Magnetometer:
    85  		C.GoIOS_startMagneto(interval)
    86  	}
    87  	go pollSensor(t, delay, channels.done[t])
    88  	return nil
    89  }
    90  
    91  func disable(t Type) error {
    92  	channels.Lock()
    93  	defer channels.Unlock()
    94  
    95  	if channels.done[t] == nil {
    96  		return fmt.Errorf("sensor: cannot disable; %v sensor is not enabled", t)
    97  	}
    98  	close(channels.done[t])
    99  	channels.done[t] = nil
   100  
   101  	switch t {
   102  	case Accelerometer:
   103  		C.GoIOS_stopAccelerometer()
   104  	case Gyroscope:
   105  		C.GoIOS_stopGyro()
   106  	case Magnetometer:
   107  		C.GoIOS_stopMagneto()
   108  	}
   109  	return nil
   110  }
   111  
   112  func pollSensor(t Type, d time.Duration, done chan struct{}) {
   113  	var lastTimestamp int64
   114  
   115  	var timestamp C.int64_t
   116  	var ev [3]C.float
   117  
   118  	for {
   119  		select {
   120  		case <-done:
   121  			return
   122  		default:
   123  			tp := (*C.int64_t)(unsafe.Pointer(&timestamp))
   124  			vp := (*C.float)(unsafe.Pointer(&ev[0]))
   125  
   126  			switch t {
   127  			case Accelerometer:
   128  				C.GoIOS_readAccelerometer(tp, vp)
   129  			case Gyroscope:
   130  				C.GoIOS_readGyro(tp, vp)
   131  			case Magnetometer:
   132  				C.GoIOS_readMagneto(tp, vp)
   133  			}
   134  			ts := int64(timestamp)
   135  			if ts > lastTimestamp {
   136  				// TODO(jbd): Do we need to convert the values to another unit?
   137  				// How does iOS units compare to the Android units.
   138  				sender.Send(Event{
   139  					Sensor:    t,
   140  					Timestamp: ts,
   141  					Data:      []float64{float64(ev[0]), float64(ev[1]), float64(ev[2])},
   142  				})
   143  				lastTimestamp = ts
   144  				time.Sleep(d / 2)
   145  			}
   146  		}
   147  	}
   148  }
   149  
   150  // TODO(jbd): Remove destroy?
   151  func destroy() error {
   152  	C.GoIOS_destroyManager()
   153  	return nil
   154  }