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