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(&timestamps[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  }