darwin_armx.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. //go:build darwin && (arm || arm64)
  5. package sensor
  6. /*
  7. #cgo CFLAGS: -x objective-c
  8. #cgo LDFLAGS: -framework CoreMotion
  9. #import <stdlib.h>
  10. void GoIOS_createManager();
  11. void GoIOS_startAccelerometer(float interval);
  12. void GoIOS_stopAccelerometer();
  13. void GoIOS_readAccelerometer(int64_t* timestamp, float* vector);
  14. void GoIOS_startGyro(float interval);
  15. void GoIOS_stopGyro();
  16. void GoIOS_readGyro(int64_t* timestamp, float* vector);
  17. void GoIOS_startMagneto(float interval);
  18. void GoIOS_stopMagneto();
  19. void GoIOS_readMagneto(int64_t* timestamp, float* vector);
  20. void GoIOS_destroyManager();
  21. */
  22. import "C"
  23. import (
  24. "fmt"
  25. "sync"
  26. "time"
  27. "unsafe"
  28. )
  29. var channels struct {
  30. sync.Mutex
  31. done [nTypes]chan struct{}
  32. }
  33. func init() {
  34. C.GoIOS_createManager()
  35. }
  36. // minDelay is the minimum delay allowed.
  37. //
  38. // From Event Handling Guide for iOS:
  39. //
  40. // "You can set the reporting interval to be as small as 10
  41. // milliseconds (ms), which corresponds to a 100 Hz update rate,
  42. // but most app operate sufficiently with a larger interval."
  43. //
  44. // There is no need to poll more frequently than once every 10ms.
  45. //
  46. // https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/motion_event_basics/motion_event_basics.html
  47. const minDelay = 10 * time.Millisecond
  48. // enable enables the sensor t on sender. A non-nil sender is
  49. // required before calling enable.
  50. func enable(t Type, delay time.Duration) error {
  51. channels.Lock()
  52. defer channels.Unlock()
  53. if channels.done[t] != nil {
  54. return fmt.Errorf("sensor: cannot enable; %v sensor is already enabled", t)
  55. }
  56. channels.done[t] = make(chan struct{})
  57. if delay < minDelay {
  58. delay = minDelay
  59. }
  60. interval := C.float(float64(delay) / float64(time.Second))
  61. switch t {
  62. case Accelerometer:
  63. C.GoIOS_startAccelerometer(interval)
  64. case Gyroscope:
  65. C.GoIOS_startGyro(interval)
  66. case Magnetometer:
  67. C.GoIOS_startMagneto(interval)
  68. }
  69. go pollSensor(t, delay, channels.done[t])
  70. return nil
  71. }
  72. func disable(t Type) error {
  73. channels.Lock()
  74. defer channels.Unlock()
  75. if channels.done[t] == nil {
  76. return fmt.Errorf("sensor: cannot disable; %v sensor is not enabled", t)
  77. }
  78. close(channels.done[t])
  79. channels.done[t] = nil
  80. switch t {
  81. case Accelerometer:
  82. C.GoIOS_stopAccelerometer()
  83. case Gyroscope:
  84. C.GoIOS_stopGyro()
  85. case Magnetometer:
  86. C.GoIOS_stopMagneto()
  87. }
  88. return nil
  89. }
  90. func pollSensor(t Type, d time.Duration, done chan struct{}) {
  91. var lastTimestamp int64
  92. var timestamp C.int64_t
  93. var ev [3]C.float
  94. for {
  95. select {
  96. case <-done:
  97. return
  98. default:
  99. tp := (*C.int64_t)(unsafe.Pointer(&timestamp))
  100. vp := (*C.float)(unsafe.Pointer(&ev[0]))
  101. switch t {
  102. case Accelerometer:
  103. C.GoIOS_readAccelerometer(tp, vp)
  104. case Gyroscope:
  105. C.GoIOS_readGyro(tp, vp)
  106. case Magnetometer:
  107. C.GoIOS_readMagneto(tp, vp)
  108. }
  109. ts := int64(timestamp)
  110. if ts > lastTimestamp {
  111. // TODO(jbd): Do we need to convert the values to another unit?
  112. // How does iOS units compare to the Android units.
  113. sender.Send(Event{
  114. Sensor: t,
  115. Timestamp: ts,
  116. Data: []float64{float64(ev[0]), float64(ev[1]), float64(ev[2])},
  117. })
  118. lastTimestamp = ts
  119. time.Sleep(d / 2)
  120. }
  121. }
  122. }
  123. }
  124. // TODO(jbd): Remove destroy?
  125. func destroy() error {
  126. C.GoIOS_destroyManager()
  127. return nil
  128. }