Advertisement
Guest User

Untitled

a guest
May 24th, 2017
199
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.07 KB | None | 0 0
  1. package info.benjaminhill.klatbot.piconzero
  2.  
  3. import android.content.Context
  4. import android.hardware.Sensor
  5. import android.hardware.SensorEvent
  6. import android.hardware.SensorEventListener
  7. import android.hardware.SensorManager
  8. import com.google.android.things.pio.Gpio
  9. import com.google.android.things.pio.GpioCallback
  10. import com.google.android.things.pio.PeripheralManagerService
  11. import com.google.android.things.userdriver.UserDriverManager
  12. import com.google.android.things.userdriver.UserSensor
  13. import com.google.android.things.userdriver.UserSensorDriver
  14. import com.google.android.things.userdriver.UserSensorReading
  15. import java.util.concurrent.*
  16. import java.util.concurrent.atomic.AtomicBoolean
  17. import java.util.concurrent.atomic.AtomicLong
  18. import java.util.logging.Logger
  19.  
  20. /** Callback for when the distance changes "enough to care" */
  21. interface SignificantDistanceChangeListener {
  22. fun onDistanceChanged(distanceCm: Float)
  23. }
  24.  
  25. /**
  26. * User Sensor - Ultrasonic range finder
  27. */
  28. class HCSR04(context: Context, val sdcl: SignificantDistanceChangeListener) : UserSensorDriver(), SensorEventListener, AutoCloseable {
  29. private val LOG = Logger.getLogger(this.javaClass.name)
  30. private val gpio = PeripheralManagerService().openGpio("BCM23")
  31. private val distanceReading: BlockingQueue<Float> = ArrayBlockingQueue(1)
  32. // Choreography of each ping
  33. private val scheduler: ScheduledExecutorService = Executors.newScheduledThreadPool(1)
  34. private val userSensor: UserSensor
  35.  
  36. init {
  37. userSensor = UserSensor.Builder()
  38. .setName("HC-SR04 Ultrasonic Distance Sensor")
  39. .setVersion(1)
  40. .setType(Sensor.TYPE_PROXIMITY) // Could this be something more linear like TYPE_LIGHT
  41. .setDriver(this)
  42. .build()
  43. UserDriverManager.getManager().registerSensor(userSensor)
  44.  
  45. val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
  46. LOG.info("ALL Sensors: ${sensorManager.getSensorList(Sensor.TYPE_ALL)}")
  47.  
  48. sensorManager.registerDynamicSensorCallback(object : SensorManager.DynamicSensorCallback() {
  49. override fun onDynamicSensorConnected(sensor: Sensor) {
  50. LOG.info("onDynamicSensorConnected")
  51. if (sensor.type == Sensor.TYPE_PROXIMITY) {
  52. sensorManager.registerListener(
  53. this@HCSR04,
  54. sensor,
  55. SensorManager.SENSOR_DELAY_NORMAL
  56. )
  57. }
  58. }
  59. })
  60.  
  61. }
  62.  
  63. val gpioEdgeCallback = object : GpioCallback() {
  64. // Track the reply rise/fall
  65. private val startMs = AtomicLong()
  66. private val startValid = AtomicBoolean(false)
  67.  
  68. private fun calculate() {
  69. val elapsed = (System.nanoTime() / 1000) - startMs.get()
  70. if (startValid.get() && elapsed > 0) {
  71. distanceReading.put(elapsed * 34000 / 2f)
  72. } else {
  73. LOG.warning("Discarding edge callback ${startMs.get()} ${startValid.get()} $elapsed")
  74. }
  75. startValid.set(false)
  76. }
  77.  
  78. override fun onGpioEdge(gpio: Gpio?): Boolean {
  79. if (gpio != null) {
  80. if (gpio.value) {
  81. startMs.set(System.nanoTime() / 1000)
  82. startValid.set(true)
  83. } else {
  84. calculate()
  85. }
  86. LOG.finer("GPIO input edge: ${System.nanoTime() / 1000} ${gpio.value}")
  87. }
  88. return true
  89. }
  90.  
  91. override fun onGpioError(gpio: Gpio?, error: Int) = LOG.severe("$gpio Error event $error")
  92. }
  93.  
  94. /** Launch a new thread to get the distance, then block until we have a result */
  95. override fun read(): UserSensorReading {
  96. distanceReading.clear()
  97.  
  98. gpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW)
  99. gpio.setActiveType(Gpio.ACTIVE_HIGH)
  100. gpio.value = false
  101.  
  102. scheduler.schedule({ gpio.value = true }, 1, TimeUnit.MICROSECONDS)
  103. scheduler.schedule({ gpio.value = false }, 11, TimeUnit.MICROSECONDS)
  104. scheduler.schedule({
  105. gpio.setDirection(Gpio.DIRECTION_IN)
  106. gpio.setActiveType(Gpio.ACTIVE_HIGH) // redundant?
  107. gpio.setEdgeTriggerType(Gpio.EDGE_BOTH)
  108. gpio.registerGpioCallback(gpioEdgeCallback)
  109. }, 12, TimeUnit.MICROSECONDS)
  110.  
  111. val distanceCm = distanceReading.take()
  112. gpio.unregisterGpioCallback(gpioEdgeCallback)
  113. LOG.info("New distance reading: $distanceCm")
  114. return UserSensorReading(floatArrayOf(distanceCm))
  115. }
  116.  
  117. /** from @SensorEventListener */
  118. override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) = LOG.info("$sensor accuracy change: $accuracy")
  119.  
  120. /**
  121. * from @SensorEventListener
  122. */
  123. override fun onSensorChanged(event: SensorEvent) = sdcl.onDistanceChanged(event.values[0])
  124.  
  125. /** from @AutoCloseable */
  126. override fun close() {
  127. LOG.warning("Closing Sensor HCSR04")
  128. UserDriverManager.getManager().unregisterSensor(userSensor)
  129. gpio.close()
  130. scheduler.shutdownNow()
  131. }
  132. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement