darwin_armx.go 3.4 KB

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