github.com/SkycoinProject/gomobile@v0.0.0-20190312151609-d3739f865fa6/exp/sensor/android.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 android 6 7 package sensor 8 9 /* 10 #cgo LDFLAGS: -landroid 11 12 #include <stdlib.h> 13 #include <android/sensor.h> 14 15 void GoAndroid_createManager(); 16 void GoAndroid_destroyManager(); 17 int GoAndroid_enableSensor(int, int32_t); 18 void GoAndroid_disableSensor(int); 19 int GoAndroid_readQueue(int n, int32_t* types, int64_t* timestamps, float* vectors); 20 */ 21 import "C" 22 import ( 23 "fmt" 24 "runtime" 25 "sync" 26 "time" 27 "unsafe" 28 ) 29 30 var ( 31 collectingMu sync.Mutex // guards collecting 32 33 // collecting is true if sensor event collecting background 34 // job has already started. 35 collecting bool 36 ) 37 38 // closeSignal destroys the underlying looper and event queue. 39 type closeSignal struct{} 40 41 // readSignal reads up to len(dst) events and mutates n with 42 // the number of returned events. 43 type readSignal struct { 44 dst []Event 45 n *int 46 } 47 48 // enableSignal enables the sensors events on the underlying 49 // event queue for the specified sensor type with the specified 50 // latency criterion. 51 type enableSignal struct { 52 t Type 53 delay time.Duration 54 err *error 55 } 56 57 // disableSignal disables the events on the underlying event queue 58 // from the sensor specified. 59 type disableSignal struct { 60 t Type 61 } 62 63 type inOut struct { 64 in interface{} 65 out chan struct{} 66 } 67 68 var inout = make(chan inOut) 69 70 // init inits the manager and creates a goroutine to proxy the CGO calls. 71 // All actions related to an ALooper needs to be performed from the same 72 // OS thread. The goroutine proxy locks itself to an OS thread and handles the 73 // CGO traffic on the same thread. 74 func init() { 75 go func() { 76 runtime.LockOSThread() 77 C.GoAndroid_createManager() 78 79 for { 80 v := <-inout 81 switch s := v.in.(type) { 82 83 case enableSignal: 84 usecsDelay := s.delay.Nanoseconds() / 1000 85 code := int(C.GoAndroid_enableSensor(typeToInt(s.t), C.int32_t(usecsDelay))) 86 if code != 0 { 87 *s.err = fmt.Errorf("sensor: no default %v sensor on the device", s.t) 88 } 89 case disableSignal: 90 C.GoAndroid_disableSensor(typeToInt(s.t)) 91 case readSignal: 92 n := readEvents(s.dst) 93 *s.n = n 94 case closeSignal: 95 C.GoAndroid_destroyManager() 96 close(v.out) 97 return // we don't need this goroutine anymore 98 } 99 close(v.out) 100 } 101 }() 102 } 103 104 // enable enables the sensor t on sender. A non-nil sender is 105 // required before calling enable. 106 func enable(t Type, delay time.Duration) error { 107 startCollecting() 108 109 var err error 110 done := make(chan struct{}) 111 inout <- inOut{ 112 in: enableSignal{t: t, delay: delay, err: &err}, 113 out: done, 114 } 115 <-done 116 return err 117 } 118 119 func startCollecting() { 120 collectingMu.Lock() 121 defer collectingMu.Unlock() 122 123 if collecting { 124 // already collecting. 125 return 126 } 127 collecting = true 128 129 go func() { 130 ev := make([]Event, 8) 131 var n int 132 for { 133 done := make(chan struct{}) 134 inout <- inOut{ 135 in: readSignal{dst: ev, n: &n}, 136 out: done, 137 } 138 <-done 139 for i := 0; i < n; i++ { 140 sender.Send(ev[i]) 141 } 142 } 143 }() 144 } 145 146 func disable(t Type) error { 147 done := make(chan struct{}) 148 inout <- inOut{ 149 in: disableSignal{t: t}, 150 out: done, 151 } 152 <-done 153 return nil 154 } 155 156 func readEvents(e []Event) int { 157 num := len(e) 158 types := make([]C.int32_t, num) 159 timestamps := make([]C.int64_t, num) 160 vectors := make([]C.float, 3*num) 161 162 n := int(C.GoAndroid_readQueue( 163 C.int(num), 164 (*C.int32_t)(unsafe.Pointer(&types[0])), 165 (*C.int64_t)(unsafe.Pointer(×tamps[0])), 166 (*C.float)(unsafe.Pointer(&vectors[0]))), 167 ) 168 for i := 0; i < n; i++ { 169 e[i] = Event{ 170 Sensor: intToType[int(types[i])], 171 Timestamp: int64(timestamps[i]), 172 Data: []float64{ 173 float64(vectors[i*3]), 174 float64(vectors[i*3+1]), 175 float64(vectors[i*3+2]), 176 }, 177 } 178 } 179 return n 180 } 181 182 // TODO(jbd): Remove destroy? 183 func destroy() error { 184 done := make(chan struct{}) 185 inout <- inOut{ 186 in: closeSignal{}, 187 out: done, 188 } 189 <-done 190 return nil 191 } 192 193 var intToType = map[int]Type{ 194 C.ASENSOR_TYPE_ACCELEROMETER: Accelerometer, 195 C.ASENSOR_TYPE_GYROSCOPE: Gyroscope, 196 C.ASENSOR_TYPE_MAGNETIC_FIELD: Magnetometer, 197 } 198 199 func typeToInt(t Type) C.int { 200 for k, v := range intToType { 201 if v == t { 202 return C.int(k) 203 } 204 } 205 return C.int(-1) 206 }