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