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