denko 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build_atmega_avr.yml +2 -1
  3. data/.github/workflows/build_atmega_megaavr.yml +2 -1
  4. data/.github/workflows/build_atsam3x.yml +1 -0
  5. data/.github/workflows/build_atsamd21.yml +2 -1
  6. data/.github/workflows/build_esp32.yml +4 -2
  7. data/.github/workflows/build_esp32c3.yml +4 -3
  8. data/.github/workflows/build_esp32c6.yml +4 -2
  9. data/.github/workflows/build_esp32h2.yml +4 -2
  10. data/.github/workflows/build_esp32s2.yml +4 -2
  11. data/.github/workflows/build_esp32s3.yml +4 -2
  12. data/.github/workflows/build_esp8266.yml +2 -1
  13. data/.github/workflows/build_ra4m1.yml +1 -0
  14. data/.github/workflows/build_rp2040.yml +4 -3
  15. data/.github/workflows/ruby.yml +1 -1
  16. data/CHANGELOG.md +203 -0
  17. data/DEPS_CLI.md +16 -16
  18. data/DEPS_IDE.md +31 -30
  19. data/MICROCONTROLLERS.md +103 -0
  20. data/PERIPHERALS.md +178 -0
  21. data/README.md +28 -21
  22. data/denko.gemspec +6 -1
  23. data/lib/denko/analog_io/ads1118.rb +5 -5
  24. data/lib/denko/analog_io/ads111x.rb +23 -19
  25. data/lib/denko/analog_io/joystick.rb +87 -0
  26. data/lib/denko/analog_io/potentiometer.rb +1 -5
  27. data/lib/denko/analog_io.rb +22 -8
  28. data/lib/denko/behaviors/bus_controller.rb +2 -1
  29. data/lib/denko/behaviors/bus_peripheral.rb +1 -1
  30. data/lib/denko/behaviors/callbacks.rb +18 -16
  31. data/lib/denko/behaviors/component.rb +0 -4
  32. data/lib/denko/behaviors/lifecycle.rb +1 -1
  33. data/lib/denko/behaviors/listener.rb +9 -3
  34. data/lib/denko/behaviors/multi_pin.rb +4 -6
  35. data/lib/denko/behaviors/poller.rb +11 -2
  36. data/lib/denko/behaviors/reader.rb +109 -21
  37. data/lib/denko/behaviors/single_pin.rb +2 -4
  38. data/lib/denko/behaviors/state.rb +18 -13
  39. data/lib/denko/behaviors/threaded.rb +19 -8
  40. data/lib/denko/behaviors.rb +36 -23
  41. data/lib/denko/board/eeprom.rb +1 -1
  42. data/lib/denko/board/i2c.rb +1 -1
  43. data/lib/denko/board/i2c_bit_bang.rb +9 -5
  44. data/lib/denko/board/map.rb +6 -2
  45. data/lib/denko/board/one_wire.rb +3 -3
  46. data/lib/denko/board/spi.rb +30 -30
  47. data/lib/denko/board/spi_bit_bang.rb +8 -11
  48. data/lib/denko/board.rb +6 -3
  49. data/lib/denko/connection/flow_control.rb +1 -1
  50. data/lib/denko/connection/serial.rb +5 -5
  51. data/lib/denko/digital_io/output.rb +12 -4
  52. data/lib/denko/digital_io/pcf8574.rb +114 -0
  53. data/lib/denko/digital_io/rotary_encoder.rb +10 -6
  54. data/lib/denko/digital_io.rb +24 -6
  55. data/lib/denko/display/canvas.rb +350 -157
  56. data/lib/denko/display/font/bmp_5x7.rb +142 -0
  57. data/lib/denko/display/font/bmp_6x8.rb +142 -0
  58. data/lib/denko/display/font/bmp_8x16.rb +141 -0
  59. data/lib/denko/display/font.rb +22 -0
  60. data/lib/denko/display/hd44780.rb +24 -20
  61. data/lib/denko/display/il0373.rb +186 -0
  62. data/lib/denko/display/mono_oled.rb +193 -0
  63. data/lib/denko/display/pcd8544.rb +154 -0
  64. data/lib/denko/display/pixel_common.rb +83 -0
  65. data/lib/denko/display/sh1106.rb +17 -21
  66. data/lib/denko/display/sh1107.rb +10 -0
  67. data/lib/denko/display/spi_common.rb +35 -0
  68. data/lib/denko/display/spi_epaper_common.rb +30 -0
  69. data/lib/denko/display/ssd1306.rb +6 -228
  70. data/lib/denko/display/ssd1680.rb +14 -0
  71. data/lib/denko/display/ssd1681.rb +8 -0
  72. data/lib/denko/display/ssd168x.rb +227 -0
  73. data/lib/denko/display/st7302.rb +207 -0
  74. data/lib/denko/display/st7565.rb +166 -0
  75. data/lib/denko/display.rb +40 -4
  76. data/lib/denko/eeprom/at24c.rb +67 -0
  77. data/lib/denko/eeprom/board.rb +69 -0
  78. data/lib/denko/eeprom.rb +15 -1
  79. data/lib/denko/helpers/engine_check.rb +13 -0
  80. data/lib/denko/{mutex_stub.rb → helpers/mutex_stub.rb} +6 -0
  81. data/lib/denko/helpers.rb +6 -0
  82. data/lib/denko/i2c/bit_bang.rb +1 -0
  83. data/lib/denko/i2c/bus_common.rb +9 -4
  84. data/lib/denko/i2c/peripheral.rb +5 -1
  85. data/lib/denko/i2c.rb +17 -4
  86. data/lib/denko/led/apa102.rb +1 -3
  87. data/lib/denko/led/base.rb +5 -0
  88. data/lib/denko/led/rgb.rb +16 -10
  89. data/lib/denko/led/seven_segment.rb +1 -1
  90. data/lib/denko/led.rb +17 -8
  91. data/lib/denko/motor/{stepper.rb → a3967.rb} +1 -1
  92. data/lib/denko/motor/servo.rb +16 -6
  93. data/lib/denko/motor.rb +16 -3
  94. data/lib/denko/one_wire/bus.rb +20 -16
  95. data/lib/denko/one_wire/bus_enumerator.rb +25 -14
  96. data/lib/denko/one_wire/helper.rb +4 -2
  97. data/lib/denko/one_wire.rb +18 -5
  98. data/lib/denko/pulse_io/buzzer.rb +2 -6
  99. data/lib/denko/pulse_io/ir_output.rb +1 -5
  100. data/lib/denko/pulse_io/pwm_output.rb +56 -31
  101. data/lib/denko/pulse_io.rb +17 -3
  102. data/lib/denko/rtc/ds3231.rb +4 -3
  103. data/lib/denko/rtc.rb +14 -1
  104. data/lib/denko/sensor/aht.rb +16 -20
  105. data/lib/denko/sensor/bme280.rb +23 -36
  106. data/lib/denko/sensor/bmp180.rb +8 -13
  107. data/lib/denko/sensor/dht.rb +17 -7
  108. data/lib/denko/sensor/ds18b20.rb +5 -4
  109. data/lib/denko/sensor/hdc1080.rb +174 -0
  110. data/lib/denko/sensor/htu21d.rb +17 -6
  111. data/lib/denko/sensor/htu31d.rb +6 -5
  112. data/lib/denko/sensor/jsnsr04t.rb +49 -0
  113. data/lib/denko/sensor/qmp6988.rb +14 -30
  114. data/lib/denko/sensor/rcwl9620.rb +1 -0
  115. data/lib/denko/sensor/sht3x.rb +6 -5
  116. data/lib/denko/sensor/sht4x.rb +125 -0
  117. data/lib/denko/sensor/vl53l0x.rb +58 -0
  118. data/lib/denko/sensor.rb +33 -15
  119. data/lib/denko/spi/base_register.rb +11 -7
  120. data/lib/denko/spi/bus_common.rb +12 -15
  121. data/lib/denko/spi/input_register.rb +6 -6
  122. data/lib/denko/spi/output_register.rb +13 -4
  123. data/lib/denko/spi/peripheral.rb +82 -84
  124. data/lib/denko/spi.rb +20 -10
  125. data/lib/denko/uart/bit_bang.rb +2 -27
  126. data/lib/denko/uart/common.rb +33 -0
  127. data/lib/denko/uart/hardware.rb +1 -26
  128. data/lib/denko/uart.rb +16 -2
  129. data/lib/denko/version.rb +1 -1
  130. data/lib/denko.rb +22 -25
  131. data/lib/denko_cli/targets.rb +7 -7
  132. data/lib/denko_cli/targets.txt +19 -20
  133. data/src/lib/Denko.cpp +26 -13
  134. data/src/lib/Denko.h +4 -4
  135. data/src/lib/DenkoDefines.h +7 -26
  136. data/src/lib/DenkoLEDArray.cpp +1 -8
  137. data/src/lib/DenkoSPI.cpp +31 -29
  138. data/src/lib/DenkoSPIBB.cpp +12 -14
  139. data/test/analog_io/input_test.rb +1 -1
  140. data/test/analog_io/potentiometer_test.rb +2 -2
  141. data/test/behaviors/bus_peripheral_test.rb +4 -4
  142. data/test/behaviors/callbacks_test.rb +20 -10
  143. data/test/behaviors/component_test.rb +18 -8
  144. data/test/board/board_test.rb +9 -9
  145. data/test/board/one_wire_test.rb +25 -14
  146. data/test/board/spi_test.rb +31 -15
  147. data/test/digital_io/input_test.rb +2 -2
  148. data/test/display/canvas_test.rb +306 -0
  149. data/test/display/hd44780_test.rb +34 -7
  150. data/test/eeprom/board_test.rb +45 -0
  151. data/test/helpers/mruby_minitest.rb +95 -0
  152. data/test/helpers/mruby_runner.rb +13 -0
  153. data/test/i2c/bus_test.rb +93 -30
  154. data/test/i2c/peripheral_test.rb +2 -2
  155. data/test/led/apa102_test.rb +24 -0
  156. data/test/led/rgb_test.rb +4 -4
  157. data/test/motor/{stepper_test.rb → a3967_test.rb} +2 -2
  158. data/test/one_wire/bus_enumerator_test.rb +1 -1
  159. data/test/one_wire/bus_test.rb +42 -35
  160. data/test/one_wire/peripheral_test.rb +5 -17
  161. data/test/pulse_io/ir_output_test.rb +5 -0
  162. data/test/pulse_io/pwm_output_test.rb +10 -10
  163. data/test/rtc/ds3231_test.rb +3 -2
  164. data/test/sensor/dht_test.rb +11 -11
  165. data/test/spi/bitbang_test.rb +27 -0
  166. data/test/spi/bus_test.rb +19 -29
  167. data/test/spi/input_register_test.rb +2 -2
  168. data/test/spi/{peripheral_multi_pin_test.rb → peripheral_test.rb} +25 -5
  169. data/test/test_helper.rb +44 -124
  170. data/vendor/board-maps/BoardMap.h +264 -0
  171. data/vendor/board-maps/yaml/ALFREDO_NOU3.yml +2 -0
  172. data/vendor/board-maps/yaml/ATD143_S3.yml +1 -0
  173. data/vendor/board-maps/yaml/BHARATPI_A7672S_4G.yml +14 -0
  174. data/vendor/board-maps/yaml/BHARATPI_LORA.yml +14 -0
  175. data/vendor/board-maps/yaml/BHARATPI_NODE_WIFI.yml +14 -0
  176. data/vendor/board-maps/yaml/BPI_LEAF_S3.yml +0 -1
  177. data/vendor/board-maps/yaml/CEZERIO_DEV_ESP32C6.yml +14 -0
  178. data/vendor/board-maps/yaml/CEZERIO_MINI_DEV_ESP32C6.yml +12 -0
  179. data/vendor/board-maps/yaml/CIRCUITART_ZERO_S3.yml +71 -0
  180. data/vendor/board-maps/yaml/CODECELLC3.yml +13 -0
  181. data/vendor/board-maps/yaml/CYOBOT_V2_ESP32S3.yml +7 -0
  182. data/vendor/board-maps/yaml/EDGES3D.yml +25 -0
  183. data/vendor/board-maps/yaml/ESP32C6_DEV.yml +3 -4
  184. data/vendor/board-maps/yaml/ESP32C6_THING_PLUS.yml +0 -1
  185. data/vendor/board-maps/yaml/ESP32H2_DEV.yml +0 -1
  186. data/vendor/board-maps/yaml/ESP32H2_DEVKIT_LIPO.yml +0 -1
  187. data/vendor/board-maps/yaml/ESP32P4_DEV.yml +35 -0
  188. data/vendor/board-maps/yaml/ESP32S2_DEV.yml +0 -1
  189. data/vendor/board-maps/yaml/ESP32S2_DEVKIT_LIPO.yml +0 -1
  190. data/vendor/board-maps/yaml/ESP32S2_DEVKIT_LIPO_USB.yml +0 -1
  191. data/vendor/board-maps/yaml/ESP32_2432S028R.yml +14 -0
  192. data/vendor/board-maps/yaml/FEATHERS3.yml +1 -1
  193. data/vendor/board-maps/yaml/FRI3D_2024_ESP32S3.yml +43 -0
  194. data/vendor/board-maps/yaml/GEEKBLE_ESP32C3.yml +0 -1
  195. data/vendor/board-maps/yaml/GEEKBLE_NANO_ESP32S3.yml +25 -0
  196. data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_E290.yml +41 -0
  197. data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_E_213.yml +41 -0
  198. data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_T190.yml +41 -0
  199. data/vendor/board-maps/yaml/HUIDU_HD_WF2.yml +5 -0
  200. data/vendor/board-maps/yaml/HUIDU_HD_WF4.yml +1 -0
  201. data/vendor/board-maps/yaml/LILYGO_LORA_CC1101.yml +6 -0
  202. data/vendor/board-maps/yaml/LILYGO_LORA_LR1121.yml +6 -0
  203. data/vendor/board-maps/yaml/LILYGO_LORA_SI4432.yml +6 -0
  204. data/vendor/board-maps/yaml/LILYGO_LORA_SX1262.yml +6 -0
  205. data/vendor/board-maps/yaml/LILYGO_LORA_SX1280.yml +6 -0
  206. data/vendor/board-maps/yaml/LOLIN_C3_MINI.yml +0 -1
  207. data/vendor/board-maps/yaml/LOLIN_C3_PICO.yml +1 -2
  208. data/vendor/board-maps/yaml/LoPy.yml +0 -1
  209. data/vendor/board-maps/yaml/LoPy4.yml +0 -1
  210. data/vendor/board-maps/yaml/M5STACK_DINMETER.yml +8 -0
  211. data/vendor/board-maps/yaml/M5STACK_FIRE.yml +1 -1
  212. data/vendor/board-maps/yaml/OMGS3.yml +25 -0
  213. data/vendor/board-maps/yaml/PCBCUPID_GLYPHC3.yml +23 -0
  214. data/vendor/board-maps/yaml/PCBCUPID_GLYPHC6.yml +32 -0
  215. data/vendor/board-maps/yaml/PCBCUPID_GLYPHH2.yml +24 -0
  216. data/vendor/board-maps/yaml/PYCOM_GPY.yml +0 -1
  217. data/vendor/board-maps/yaml/SENSEBOX_MCU_ESP32S2.yml +1 -1
  218. data/vendor/board-maps/yaml/SPARKFUN_ESP32S3_THING_PLUS.yml +13 -0
  219. data/vendor/board-maps/yaml/SPARKLEMOTIONMINI_ESP32.yml +12 -0
  220. data/vendor/board-maps/yaml/SPARKLEMOTIONSTICK_ESP32.yml +11 -0
  221. data/vendor/board-maps/yaml/SPARKLEMOTION_ESP32.yml +12 -0
  222. data/vendor/board-maps/yaml/SQUIXL.yml +7 -0
  223. data/vendor/board-maps/yaml/THINGPULSE_EPULSE_FEATHER_C6.yml +0 -1
  224. data/vendor/board-maps/yaml/T_LORA_PAGER.yml +6 -0
  225. data/vendor/board-maps/yaml/T_WATCH_S3.yml +7 -0
  226. data/vendor/board-maps/yaml/T_WATCH_S3_ULTRA.yml +6 -0
  227. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_146.yml +41 -0
  228. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_147.yml +41 -0
  229. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_169.yml +38 -0
  230. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_185.yml +41 -0
  231. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_RELAY_6CH.yml +41 -0
  232. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_143.yml +7 -0
  233. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_164.yml +7 -0
  234. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_18.yml +38 -0
  235. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_191.yml +7 -0
  236. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_241.yml +7 -0
  237. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_146.yml +41 -0
  238. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_169.yml +38 -0
  239. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_185.yml +41 -0
  240. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_185_BOX.yml +41 -0
  241. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_21.yml +41 -0
  242. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_28.yml +41 -0
  243. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_4.yml +36 -0
  244. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_43.yml +38 -0
  245. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_43B.yml +38 -0
  246. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_5.yml +38 -0
  247. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_5B.yml +38 -0
  248. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_7.yml +38 -0
  249. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_ZERO.yml +36 -0
  250. data/vendor/board-maps/yaml/WIPY3.yml +0 -1
  251. data/vendor/board-maps/yaml/WS_ESP32_S3_MATRIX.yml +38 -0
  252. data/vendor/board-maps/yaml/XIAO_ESP32S3_PLUS.yml +46 -0
  253. data/vendor/board-maps/yaml/YB_ESP32S3_AMP_V2.yml +28 -0
  254. data/vendor/board-maps/yaml/YB_ESP32S3_AMP_V3.yml +28 -0
  255. data/vendor/board-maps/yaml/YB_ESP32S3_ETH.yml +40 -0
  256. data/vendor/board-maps/yaml/mercury.yml +20 -0
  257. metadata +116 -101
  258. data/.vscode/settings.json +0 -5
  259. data/.vscode/tasks.json +0 -20
  260. data/HARDWARE.md +0 -263
  261. data/benchmarks/analog_listen.rb +0 -49
  262. data/benchmarks/digital_write.rb +0 -28
  263. data/benchmarks/i2c_ssd1306_refresh.rb +0 -91
  264. data/examples/advanced/m5_env3.rb +0 -46
  265. data/examples/advanced/rotary_encoder_mac_volume.rb +0 -53
  266. data/examples/advanced/ssd1306_time_temp_rh.rb +0 -43
  267. data/examples/analog_io/ads1100.rb +0 -48
  268. data/examples/analog_io/ads1115.rb +0 -57
  269. data/examples/analog_io/ads1118.rb +0 -65
  270. data/examples/analog_io/dac_loopback.rb +0 -34
  271. data/examples/analog_io/input.rb +0 -56
  272. data/examples/analog_io/input_smoothing.rb +0 -27
  273. data/examples/analog_io/potentiometer.rb +0 -31
  274. data/examples/connection/binary_echo.rb +0 -34
  275. data/examples/connection/tcp.rb +0 -19
  276. data/examples/digital_io/button.rb +0 -17
  277. data/examples/digital_io/relay.rb +0 -17
  278. data/examples/digital_io/rotary_encoder.rb +0 -36
  279. data/examples/display/hd44780.png +0 -0
  280. data/examples/display/hd44780.rb +0 -47
  281. data/examples/display/ssd1306.rb +0 -43
  282. data/examples/display/ssd1306_s2_pico.rb +0 -29
  283. data/examples/eeprom/built_in.rb +0 -32
  284. data/examples/i2c/search.rb +0 -39
  285. data/examples/led/apa102_bounce.rb +0 -32
  286. data/examples/led/apa102_fade.rb +0 -44
  287. data/examples/led/builtin_blink.rb +0 -14
  288. data/examples/led/builtin_fade.rb +0 -19
  289. data/examples/led/rgb_led.rb +0 -31
  290. data/examples/led/seven_segment_char_echo.rb +0 -17
  291. data/examples/led/ws2812_bounce.rb +0 -30
  292. data/examples/led/ws2812_builtin_blink.rb +0 -22
  293. data/examples/led/ws2812_fade.rb +0 -43
  294. data/examples/motor/l298.rb +0 -45
  295. data/examples/motor/servo.rb +0 -17
  296. data/examples/motor/stepper.png +0 -0
  297. data/examples/motor/stepper.rb +0 -43
  298. data/examples/one_wire/search.rb +0 -32
  299. data/examples/pulse_io/buzzer.rb +0 -35
  300. data/examples/pulse_io/ir_output.rb +0 -51
  301. data/examples/pulse_io/pwm_output.rb +0 -30
  302. data/examples/rtc/ds3231.rb +0 -31
  303. data/examples/sensor/aht10.rb +0 -17
  304. data/examples/sensor/aht20.rb +0 -17
  305. data/examples/sensor/bme280.rb +0 -38
  306. data/examples/sensor/bmp180.rb +0 -26
  307. data/examples/sensor/dht.rb +0 -29
  308. data/examples/sensor/ds18b20.rb +0 -57
  309. data/examples/sensor/generic_pir.rb +0 -27
  310. data/examples/sensor/hcsr04.rb +0 -17
  311. data/examples/sensor/htu21d.rb +0 -43
  312. data/examples/sensor/htu31d.rb +0 -33
  313. data/examples/sensor/neat_tph_readings.rb +0 -32
  314. data/examples/sensor/qmp6988.rb +0 -51
  315. data/examples/sensor/rcwl9620.rb +0 -15
  316. data/examples/sensor/sht3x.rb +0 -32
  317. data/examples/spi/bitbang_loopback.rb +0 -46
  318. data/examples/spi/input_register.rb +0 -40
  319. data/examples/spi/output_register.rb +0 -41
  320. data/examples/spi/ssd_through_registers.rb +0 -28
  321. data/examples/spi/two_registers.rb +0 -40
  322. data/examples/uart/bit_bang_demo.rb +0 -25
  323. data/examples/uart/board_passthrough.rb +0 -40
  324. data/examples/uart/hardware_loopback.rb +0 -16
  325. data/lib/denko/eeprom/built_in.rb +0 -72
  326. data/lib/denko/fonts.rb +0 -106
  327. data/test/eeprom/built_in_test.rb +0 -61
  328. data/test/spi/peripheral_single_pin_test.rb +0 -48
  329. data/tutorial/01-led/led.fzz +0 -0
  330. data/tutorial/01-led/led.pdf +0 -0
  331. data/tutorial/01-led/led.rb +0 -73
  332. data/tutorial/02-button/button.fzz +0 -0
  333. data/tutorial/02-button/button.pdf +0 -0
  334. data/tutorial/02-button/button.rb +0 -65
  335. data/tutorial/03-potentiometer/potentiometer.fzz +0 -0
  336. data/tutorial/03-potentiometer/potentiometer.pdf +0 -0
  337. data/tutorial/03-potentiometer/potentiometer.rb +0 -66
  338. data/tutorial/04-pwm_led/pwm_led.fzz +0 -0
  339. data/tutorial/04-pwm_led/pwm_led.pdf +0 -0
  340. data/tutorial/04-pwm_led/pwm_led.rb +0 -64
  341. data/tutorial/05-rgb_led/rgb_led.fzz +0 -0
  342. data/tutorial/05-rgb_led/rgb_led.pdf +0 -0
  343. data/tutorial/05-rgb_led/rgb_led.rb +0 -58
  344. data/tutorial/05-rgb_led/rgb_mapping.rb +0 -76
@@ -1,29 +1,32 @@
1
1
  module Denko
2
2
  module Behaviors
3
3
  module Callbacks
4
+ include Lifecycle
4
5
  include State
5
6
 
6
- def callback_mutex
7
- @callback_mutex ||= Denko.cruby? ? Denko::MutexStub.new : Mutex.new
8
- @callback_mutex
7
+ after_initialize do
8
+ @callback_mutex = Denko.gil? ? Denko::MutexStub.new : Mutex.new
9
+ callbacks
9
10
  end
10
11
 
11
12
  def callbacks
12
- callback_mutex.synchronize { @callbacks ||= {} }
13
+ @callbacks ||= {}
13
14
  end
14
15
 
15
16
  def add_callback(key=:persistent, &block)
16
- callback_mutex.synchronize do
17
- @callbacks ||= {}
18
- @callbacks[key] ||= []
19
- @callbacks[key] << block
20
- end
17
+ @callback_mutex.lock
18
+ @callbacks ||= {}
19
+ @callbacks[key] ||= []
20
+ @callbacks[key] << block
21
+ @callback_mutex.unlock
22
+ @callbacks
21
23
  end
22
24
 
23
25
  def remove_callback(key=nil)
24
- callback_mutex.synchronize do
25
- (@callbacks && key) ? @callbacks.delete(key) : @callbacks = {}
26
- end
26
+ @callback_mutex.lock
27
+ (@callbacks && key) ? @callbacks.delete(key) : @callbacks = {}
28
+ @callback_mutex.unlock
29
+ @callbacks
27
30
  end
28
31
 
29
32
  alias :on_data :add_callback
@@ -44,10 +47,8 @@ module Denko
44
47
  return nil
45
48
  end
46
49
 
47
- callback_mutex.synchronize do
48
- break unless @callbacks
49
- break if @callbacks.empty?
50
-
50
+ @callback_mutex.lock
51
+ if @callbacks && !@callbacks.empty?
51
52
  @callbacks.each_value do |array|
52
53
  array.each do |callback|
53
54
  callback.call(filtered_data)
@@ -56,6 +57,7 @@ module Denko
56
57
  # Remove one-time callbacks added by #read.
57
58
  @callbacks.delete(:read)
58
59
  end
60
+ @callback_mutex.unlock
59
61
 
60
62
  update_state(filtered_data)
61
63
  end
@@ -20,10 +20,6 @@ module Denko
20
20
  board.micro_delay(duration)
21
21
  end
22
22
 
23
- def board_is_register?
24
- @board_is_register ||= board.class.ancestors.include?(SPI::BaseRegister)
25
- end
26
-
27
23
  protected
28
24
 
29
25
  def initialize_board
@@ -34,7 +34,7 @@ module Denko
34
34
  # Need to check civars in ancestors too.
35
35
  klasses = self.class.ancestors
36
36
  # If running "after" reverse hierarchy so they run top-down.
37
- klasses = klasses.reverse if method_sym.match? /after/
37
+ klasses = klasses.reverse if method_sym.to_s.start_with? "after"
38
38
 
39
39
  blocks = []
40
40
  klasses.each do |klass|
@@ -2,20 +2,26 @@ module Denko
2
2
  module Behaviors
3
3
  module Listener
4
4
  include Callbacks
5
-
5
+
6
6
  attr_reader :divider
7
7
 
8
+ #
9
+ # These delegate to #_listen and #_stop_listener,
10
+ # which should be defined in the including class.
11
+ #
8
12
  def listen(divider=nil, &block)
9
- @divider = divider || @listener
13
+ @divider = divider
10
14
  stop
11
15
  add_callback(:listen, &block) if block_given?
12
16
  _listen(@divider)
17
+ @listening = true
13
18
  end
14
19
 
15
20
  def stop
16
- super if defined?(super)
21
+ begin; super; rescue NoMethodError; end
17
22
  _stop_listener
18
23
  remove_callbacks :listen
24
+ @listening = false
19
25
  end
20
26
  end
21
27
  end
@@ -24,8 +24,10 @@ module Denko
24
24
  end
25
25
 
26
26
  def convert_pins(options={})
27
- self.pins = {}
28
- params[:pins].each { |key,pin| self.pins[key] = board.convert_pin(pin) }
27
+ @pins = {}
28
+ params[:pins].each do |key,pin|
29
+ self.pins[key] = pin ? board.convert_pin(pin) : nil
30
+ end
29
31
  pin_array = pins.values
30
32
  raise ArgumentError, "duplicate pins in: #{pins.inspect}" unless pin_array == pin_array.uniq
31
33
  end
@@ -67,10 +69,6 @@ module Denko
67
69
  def require_pins(*array)
68
70
  [array].flatten.each { |name| require_pin(name) }
69
71
  end
70
-
71
- private
72
-
73
- attr_writer :pins, :proxies
74
72
  end
75
73
  end
76
74
  end
@@ -3,8 +3,10 @@ module Denko
3
3
  module Poller
4
4
  include Reader
5
5
  include Threaded
6
-
6
+
7
7
  def poll_using(method, interval, *args, &block)
8
+ mruby_thread_check
9
+
8
10
  unless [Integer, Float].include? interval.class
9
11
  raise ArgumentError, "wrong interval given to #poll : #{interval.inspect}"
10
12
  end
@@ -13,7 +15,14 @@ module Denko
13
15
  add_callback(:poll, &block) if block_given?
14
16
 
15
17
  threaded_loop do
18
+ # Lock, THEN wait for other normal reads to finish.
19
+ @reader_mutex.lock
20
+ sleep 0.001 while read_busy?
21
+ @reading_normally = true
22
+
16
23
  method.call(*args)
24
+ @reader_mutex.unlock
25
+
17
26
  sleep interval
18
27
  end
19
28
  end
@@ -23,7 +32,7 @@ module Denko
23
32
  end
24
33
 
25
34
  def stop
26
- super if defined?(super)
35
+ begin; super; rescue NoMethodError; end
27
36
  remove_callbacks :poll
28
37
  end
29
38
  end
@@ -1,49 +1,137 @@
1
1
  module Denko
2
2
  module Behaviors
3
3
  module Reader
4
+ include Lifecycle
4
5
  include Callbacks
5
6
 
6
7
  #
7
- # Defalt behavior for #read is to delegate to #_read.
8
- # Define #_read in including classes.
8
+ # DO NOT REPLACE with MutexStub on CRuby!
9
+ # Even with GIL, misordered readings possible with multiple threads.
10
+ #
11
+ after_initialize do
12
+ # mruby doesn't have Thread or Mutex, so only stub there.
13
+ @reader_mutex = Denko.mruby? ? Denko::MutexStub.new : Mutex.new
14
+ end
15
+
16
+ READ_WAIT_TIME = 0.001
17
+ #
18
+ # Override #update to allow "raw reads" or "normal reads":
19
+ #
20
+ # - Normal reads perform normal #update behavior, passing through
21
+ # #pre_callback_filter, running all callbacks and returning filtered_data.
22
+ # Use normal for anything that updates the state of a component, and handle
23
+ # that in in #pre_callback_filter and #update_state.
24
+ # May or may not block calling thread, depending on platform.
25
+ #
26
+ # - Raw reads bypass #pre_callback_filter, callbacks, and return
27
+ # raw data. Use raw for reading things like sensor config/serial etc.
28
+ # DOES NOT take block callbacks from the use. ALWAYS handle the return value.
29
+ # ALWAYS blocks the calling thread.
30
+ #
31
+ def update(data)
32
+ if @reading_raw
33
+ @callback_mutex.lock
34
+ @callbacks[:read_raw].each { |c| c.call(data) }
35
+ @callbacks.delete(:read_raw)
36
+ @callback_mutex.unlock
37
+ @reading_raw = false
38
+ data
39
+ else
40
+ return_value = super(data)
41
+ @reading_normally = false
42
+ return_value
43
+ end
44
+ end
45
+
46
+ #
47
+ # Delegates to #_read. Data passes through #pre_callback_filter, runs all
48
+ # callbacks, and @state is set. BLOCKS calling thread.
9
49
  #
10
50
  def read(*args, **kwargs, &block)
11
51
  read_using(self.method(:_read), *args, **kwargs, &block)
12
52
  end
13
53
 
54
+ #
55
+ # Delegates to #_read. Data passes through #pre_callback_filter, runs all
56
+ # callbacks, and @state is set. DOES NOT BLOCK calling thread.
57
+ #
58
+ def read_nb(*args, **kwargs, &block)
59
+ @reader_mutex.lock
60
+ sleep READ_WAIT_TIME while read_busy?
61
+ @reading_normally = true
62
+ _read(*args, **kwargs, &block)
63
+ @reader_mutex.unlock
64
+ end
65
+
66
+ #
67
+ # NEVER call this directly. Use #read_nb instead.
68
+ #
69
+ # Define #_read in including class to get data which updates the
70
+ # peripheral state. See #read_using comments for more info.
71
+ #
72
+ def _read
73
+ raise NotImplementedError.new("#{self.class.name}#_read is not defined.")
74
+ end
75
+
14
76
  #
15
77
  # Take a proc/lambda/method as the first agrument and use it to read.
16
78
  # Arguments are passed through, allowing dynamic read methods to be defined.
17
79
  # Eg. send commands (in args) to a bus, then wait for data read back.
18
- #
19
- # Block given is added as a one-time callback in the :read key, and
20
- # the curent thread waits until data is received. Returns the result of
21
- # calling #pre_callback_filter with the data.
80
+ #
81
+ # Data is received when the board/bus calls #update on us. If a read was
82
+ # started by this method, the data will pass through #pre_callback_filter,
83
+ # trigger all callbacks, and set @state. Use this for reading the state
84
+ # of peripherals, like digital pin level, enviro sensor reading etc.
22
85
  #
23
86
  def read_using(reader, *args, **kwargs, &block)
24
- add_callback(:read, &block) if block_given?
87
+ # Lock, THEN wait for other normal reads to finish.
88
+ @reader_mutex.lock
89
+ sleep READ_WAIT_TIME while read_busy?
90
+ @reading_normally = true
25
91
 
92
+ # One-time callbacks.
26
93
  return_value = nil
27
- add_callback(:read) do |filtered_data|
28
- return_value = filtered_data
29
- end
30
-
94
+ add_callback(:read) { |filtered_data| return_value = filtered_data }
95
+ add_callback(:read, &block) if block_given?
96
+
31
97
  reader.call(*args, **kwargs)
32
- wait_for_read
98
+ @reader_mutex.unlock
33
99
 
100
+ # Wait for #update to remove the :read callbacks (return_value is set).
101
+ sleep READ_WAIT_TIME while callbacks[:read]
34
102
  return_value
35
103
  end
36
-
37
- def wait_for_read
38
- loop do
39
- break if !callbacks[:read]
40
- sleep 0.001
41
- end
104
+
105
+ #
106
+ # Similar to #read_using, but does not trigger #pre_callback_filter,
107
+ # or run any callbacks except :read_raw. BLOCKS calling thread.
108
+ # Use for things like sensor status, config etc.
109
+ #
110
+ def read_raw(reader, *args, **kwargs)
111
+ # Can't guarantee read order.
112
+ raise StandardError, "#read_raw unavailable while listening" if @listening
113
+
114
+ # Lock, THEN wait for any normal read to finish.
115
+ @reader_mutex.lock
116
+ sleep READ_WAIT_TIME while read_busy?
117
+ @reading_raw = true
118
+
119
+ # Special :read_raw one-time callback.
120
+ return_value = nil
121
+ add_callback(:read_raw) { |bytes| return_value = bytes }
122
+
123
+ # Call reader, but block and keep the lock until :read_raw callback gets run.
124
+ reader.call(*args, **kwargs)
125
+ sleep READ_WAIT_TIME while callbacks[:read_raw]
126
+ @reader_mutex.unlock
127
+
128
+ return_value
42
129
  end
43
130
 
44
- def _read
45
- raise NotImplementedError
46
- .new("#{self.class.name}#_read is not defined.")
131
+ def read_busy?
132
+ # mruby gets stuck waiting somewhere, but doesn't have threads
133
+ # so it can never really be busy.
134
+ !Denko.mruby? && (@reading_normally || @reading_raw)
47
135
  end
48
136
  end
49
137
  end
@@ -3,13 +3,11 @@ module Denko
3
3
  module SinglePin
4
4
  include Component
5
5
  attr_reader :pin, :mode
6
-
7
- def mode=(mode)
6
+
7
+ def mode=(mode)
8
8
  board.set_pin_mode(pin, mode)
9
9
  @mode = mode
10
10
  end
11
-
12
- protected
13
11
 
14
12
  def convert_pins(options={})
15
13
  raise ArgumentError, 'a pin is required for this component' unless options[:pin]
@@ -3,24 +3,29 @@ module Denko
3
3
  module State
4
4
  include Lifecycle
5
5
 
6
- # Force state initialization.
6
+ # Force state and mutex initialization.
7
7
  after_initialize do
8
+ @state_mutex = Denko.gil? ? Denko::MutexStub.new : Mutex.new
8
9
  state
9
10
  end
10
11
 
11
- def state_mutex
12
- @state_mutex ||= Denko.cruby? ? Denko::MutexStub.new : Mutex.new
13
- @state_mutex
14
- end
15
-
16
- def state
17
- state_mutex.synchronize { @state }
18
- end
19
-
20
- protected
12
+ # mruby optimization. Bypass state_mutex for simple states.
13
+ if Denko.mruby?
14
+ attr_accessor :state
15
+ else
16
+ def state
17
+ @state_mutex.lock
18
+ value = @state
19
+ @state_mutex.unlock
20
+ value
21
+ end
21
22
 
22
- def state=(value)
23
- state_mutex.synchronize { @state = value }
23
+ def state=(value)
24
+ @state_mutex.lock
25
+ @state = value
26
+ @state_mutex.unlock
27
+ @state
28
+ end
24
29
  end
25
30
 
26
31
  def update_state(value)
@@ -11,39 +11,50 @@ module Denko
11
11
  end
12
12
  end
13
13
 
14
+ def mruby_thread_check
15
+ if Denko.mruby?
16
+ raise NotImplementedError, "threads unavailable in mruby "
17
+ end
18
+ end
19
+
14
20
  def self.included(base)
15
21
  base.extend ClassMethods
16
22
  end
17
23
 
18
24
  def threaded(&block)
25
+ mruby_thread_check
19
26
  stop_thread
20
27
  enable_interrupts unless interrupts_enabled
21
28
  @thread = Thread.new(&block)
22
29
  end
23
30
 
24
31
  def threaded_loop(&block)
32
+ mruby_thread_check
25
33
  threaded do
26
34
  loop(&block)
27
35
  end
28
36
  end
29
37
 
30
38
  def stop_thread
39
+ mruby_thread_check
31
40
  @thread.kill if @thread
32
41
  end
33
42
 
34
43
  def stop
35
- stop_thread
36
- super if defined?(super)
44
+ stop_thread unless Denko.mruby?
45
+ begin; super; rescue NoMethodError; end
37
46
  end
38
47
 
39
48
  def enable_interrupts
40
- interrupts = self.class.class_eval('@@interrupts') rescue []
41
- interrupts.each do |method_name|
42
- standard_method = self.method(method_name)
49
+ unless Denko.mruby?
50
+ interrupts = self.class.class_eval('@@interrupts') rescue []
51
+ interrupts.each do |method_name|
52
+ standard_method = self.method(method_name)
43
53
 
44
- singleton_class.send(:define_method, method_name) do |*args|
45
- stop_thread unless (Thread.current == @thread)
46
- standard_method.call(*args)
54
+ singleton_class.send(:define_method, method_name) do |*args|
55
+ stop_thread unless (Thread.current == @thread)
56
+ standard_method.call(*args)
57
+ end
47
58
  end
48
59
  end
49
60
 
@@ -1,27 +1,40 @@
1
- module Denko
2
- module Behaviors
3
- # Pin and component setup stuff
4
- autoload :Lifecycle, "#{__dir__}/behaviors/lifecycle"
5
- autoload :State, "#{__dir__}/behaviors/state"
6
- autoload :Component, "#{__dir__}/behaviors/component"
7
- autoload :SinglePin, "#{__dir__}/behaviors/single_pin"
8
- autoload :InputPin, "#{__dir__}/behaviors/input_pin"
9
- autoload :OutputPin, "#{__dir__}/behaviors/output_pin"
10
- autoload :MultiPin, "#{__dir__}/behaviors/multi_pin"
1
+ # Represent files to be autoloaded in CRuby as an Array.
2
+ # This allows Mruby::Build to parse and preload them instead.
3
+ BEHAVIORS_FILES = [
4
+ # Pin and component setup stuff
5
+ [:Lifecycle, "lifecycle"],
6
+ [:State, "state"],
7
+ [:Component, "component"],
8
+ [:SinglePin, "single_pin"],
9
+ [:InputPin, "input_pin"],
10
+ [:OutputPin, "output_pin"],
11
+ [:MultiPin, "multi_pin"],
12
+
13
+ # Subcomponent stuff
14
+ [:Subcomponents, "subcomponents"],
15
+ [:BusController, "bus_controller"],
16
+ [:BusControllerAddressed, "bus_controller_addressed"],
17
+ [:BusPeripheral, "bus_peripheral"],
18
+ [:BusPeripheralAddressed, "bus_peripheral_addressed"],
19
+ [:BoardProxy, "board_proxy"],
11
20
 
12
- # Subcomponent stuff
13
- autoload :Subcomponents, "#{__dir__}/behaviors/subcomponents"
14
- autoload :BusController, "#{__dir__}/behaviors/bus_controller"
15
- autoload :BusControllerAddressed, "#{__dir__}/behaviors/bus_controller_addressed"
16
- autoload :BusPeripheral, "#{__dir__}/behaviors/bus_peripheral"
17
- autoload :BusPeripheralAddressed, "#{__dir__}/behaviors/bus_peripheral_addressed"
18
- autoload :BoardProxy, "#{__dir__}/behaviors/board_proxy"
21
+ # Async stuff
22
+ [:Threaded, "threaded"],
23
+ [:Callbacks, "callbacks"],
24
+ [:Reader, "reader"],
25
+ [:Poller, "poller"],
26
+ [:Listener, "listener"],
27
+ ]
19
28
 
20
- # Async stuff
21
- autoload :Threaded, "#{__dir__}/behaviors/threaded"
22
- autoload :Callbacks, "#{__dir__}/behaviors/callbacks"
23
- autoload :Reader, "#{__dir__}/behaviors/reader"
24
- autoload :Poller, "#{__dir__}/behaviors/poller"
25
- autoload :Listener, "#{__dir__}/behaviors/listener"
29
+ module Denko
30
+ module Behaviors
31
+ BEHAVIORS_FILES.each do |file|
32
+ file_path = "#{__dir__}/behaviors/#{file[1]}"
33
+ if file[0]
34
+ autoload file[0], file_path
35
+ else
36
+ require file_path
37
+ end
38
+ end
26
39
  end
27
40
  end
@@ -11,7 +11,7 @@ module Denko
11
11
  # CMD = 8
12
12
  def eeprom_write(address, bytes)
13
13
  address = pack :uint16, address
14
- bytes = pack :uint8, bytes, min: 1, max: 128
14
+ bytes = pack :uint8, bytes
15
15
  write Message.encode command: 8,
16
16
  value: bytes.length,
17
17
  aux_message: address + bytes
@@ -26,7 +26,7 @@ module Denko
26
26
 
27
27
  # CMD = 34
28
28
  def i2c_write(i2c_index, address, bytes, frequency=100000, repeated_start=false)
29
- bytes = [bytes] unless bytes.class == Array
29
+ bytes = [bytes].flatten unless bytes.class == Array
30
30
  raise ArgumentError, "I2C write must be 1..#{i2c_limit} bytes long" if (bytes.length > i2c_limit || bytes.length < 1)
31
31
 
32
32
  # Use top bit of address to select stop condition (1), or repated start (0).
@@ -1,5 +1,9 @@
1
1
  module Denko
2
2
  class Board
3
+ def i2c_bb_setup(scl, sda)
4
+ # Stub method. Other implementations may call this.
5
+ end
6
+
3
7
  # CMD = 30
4
8
  def i2c_bb_search(scl, sda)
5
9
  write Message.encode command: 30,
@@ -9,15 +13,15 @@ module Denko
9
13
 
10
14
  # CMD = 31
11
15
  def i2c_bb_write(scl, sda, address, bytes, repeated_start=false)
12
- bytes = [bytes] unless bytes.class == Array
13
-
16
+ bytes = [bytes].flatten unless bytes.class == Array
17
+
14
18
  # Use top bit of address to select stop condition (1), or repated start (0).
15
19
  send_stop = repeated_start ? 0 : 1
16
-
20
+
17
21
  write Message.encode command: 31,
18
22
  pin: scl,
19
23
  value: sda,
20
- aux_message: pack(:uint8, 0x00) +
24
+ aux_message: pack(:uint8, 0x00) +
21
25
  pack(:uint8, address | (send_stop << 7)) +
22
26
  pack(:uint8, bytes.length) +
23
27
  pack(:uint8, bytes)
@@ -40,7 +44,7 @@ module Denko
40
44
  write Message.encode command: 32,
41
45
  pin: scl,
42
46
  value: sda,
43
- aux_message: pack(:uint8, 0x00) +
47
+ aux_message: pack(:uint8, 0x00) +
44
48
  pack(:uint8, address | (send_stop << 7)) +
45
49
  pack(:uint8, read_length) +
46
50
  register_packed
@@ -5,7 +5,7 @@ module Denko
5
5
  MAPS_FOLDER = File.join(Denko.root, "vendor/board-maps/yaml")
6
6
 
7
7
  attr_reader :map
8
-
8
+
9
9
  def substitute_zero_pins
10
10
  ["SDA", "SCL", "MOSI", "MISO", "SCK", "SS"].each do |name|
11
11
  symbol = name.to_sym
@@ -25,7 +25,7 @@ module Denko
25
25
  rescue
26
26
  raise StandardError, "error loading board map from file for board name: '#{board_name}'"
27
27
  end
28
-
28
+
29
29
  def convert_pin(pin)
30
30
  # Convert non numerical strings to symbols.
31
31
  pin = pin.to_sym if (pin.class == String) && !(pin.match (/\A\d+\.*\d*/))
@@ -50,6 +50,10 @@ module Denko
50
50
  rescue
51
51
  raise ArgumentError, "error in pin: #{pin.inspect}"
52
52
  end
53
+
54
+ def pin_is_pwm?(pin)
55
+ false
56
+ end
53
57
  end
54
58
  end
55
59
  end
@@ -1,9 +1,9 @@
1
1
  module Denko
2
2
  class Board
3
- def one_wire_reset(pin, value=0)
3
+ def one_wire_reset(pin, read_presence=false)
4
4
  write Message.encode command: 41,
5
5
  pin: pin,
6
- value: value
6
+ value: read_presence ? 1 : 0
7
7
  end
8
8
 
9
9
  def one_wire_search(pin, branch_mask)
@@ -12,7 +12,7 @@ module Denko
12
12
  aux_message: pack(:uint64, branch_mask, max: 8)
13
13
  end
14
14
 
15
- def one_wire_write(pin, parasite_power, *data)
15
+ def one_wire_write(pin, parasite_power, data)
16
16
  bytes = pack :uint8, data, min: 1, max: 127 # Should be 128 with 0 = 1.
17
17
 
18
18
  # Set high bit of length if the bus must drive high after write.