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