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