denko 0.13.1 → 0.13.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build_avr.yml +2 -4
  3. data/.github/workflows/build_esp32.yml +2 -3
  4. data/.github/workflows/build_esp8266.yml +2 -3
  5. data/.github/workflows/build_megaavr.yml +2 -4
  6. data/.github/workflows/build_ra4m1.yml +57 -0
  7. data/.github/workflows/build_rp2040.yml +2 -4
  8. data/.github/workflows/build_sam3x.yml +1 -3
  9. data/.github/workflows/build_samd.yml +2 -4
  10. data/CHANGELOG.md +60 -0
  11. data/DEPS_CLI.md +8 -6
  12. data/DEPS_IDE.md +9 -7
  13. data/HARDWARE.md +90 -74
  14. data/README.md +19 -28
  15. data/benchmarks/i2c_ssd1306_refresh.rb +74 -0
  16. data/examples/analog_io/ads1115.rb +57 -0
  17. data/examples/analog_io/ads1118.rb +8 -9
  18. data/examples/analog_io/dac_loopback.rb +6 -4
  19. data/examples/analog_io/input.rb +39 -36
  20. data/examples/connection/tcp.rb +1 -1
  21. data/examples/display/hd44780.rb +3 -3
  22. data/examples/display/ssd1306.rb +1 -1
  23. data/examples/pulse_io/buzzer.rb +40 -0
  24. data/lib/denko/analog_io/ads1115.rb +61 -0
  25. data/lib/denko/analog_io/ads1118.rb +10 -120
  26. data/lib/denko/analog_io/ads111x.rb +123 -0
  27. data/lib/denko/analog_io/output.rb +2 -1
  28. data/lib/denko/analog_io.rb +2 -0
  29. data/lib/denko/behaviors/reader.rb +14 -13
  30. data/lib/denko/behaviors/subcomponents.rb +2 -2
  31. data/lib/denko/board/core.rb +1 -1
  32. data/lib/denko/board/i2c.rb +1 -4
  33. data/lib/denko/board/map.rb +9 -0
  34. data/lib/denko/board/servo.rb +2 -6
  35. data/lib/denko/board.rb +32 -20
  36. data/lib/denko/connection/board_uart.rb +3 -3
  37. data/lib/denko/connection/flow_control.rb +10 -2
  38. data/lib/denko/digital_io/output.rb +1 -1
  39. data/lib/denko/display/hd44780.rb +18 -18
  40. data/lib/denko/led/seven_segment.rb +18 -19
  41. data/lib/denko/message.rb +6 -14
  42. data/lib/denko/pulse_io/ir_transmitter.rb +1 -2
  43. data/lib/denko/version.rb +1 -1
  44. data/lib/denko_cli/packages.rb +7 -1
  45. data/lib/denko_cli/targets.rb +8 -5
  46. data/lib/denko_cli/usage.txt +8 -4
  47. data/src/denko_ethernet.ino +15 -23
  48. data/src/denko_serial.ino +3 -14
  49. data/src/denko_wifi.ino +35 -50
  50. data/src/lib/Denko.cpp +23 -6
  51. data/src/lib/Denko.h +6 -16
  52. data/src/lib/DenkoCoreIO.cpp +3 -3
  53. data/src/lib/DenkoDefines.h +62 -16
  54. data/src/lib/DenkoEEPROM.cpp +9 -1
  55. data/src/lib/DenkoI2C.cpp +11 -9
  56. data/src/lib/DenkoLEDArray.cpp +1 -1
  57. data/target.yml +35 -1
  58. data/test/behaviors/reader_test.rb +8 -1
  59. data/test/board/helper_test.rb +0 -4
  60. data/test/display/hd44780_test.rb +10 -0
  61. data/test/led/seven_segment_test.rb +30 -8
  62. data/test/test_helper.rb +17 -2
  63. data/vendor/board-maps/.gitmodules +3 -0
  64. data/vendor/board-maps/BoardMap.h +40 -12
  65. data/vendor/board-maps/README.md +1 -0
  66. data/vendor/board-maps/lib/header_parser.rb +30 -5
  67. data/vendor/board-maps/run.rb +11 -1
  68. data/vendor/board-maps/yaml/ADAFRUIT_FEATHER_ESP32S3.yml +6 -1
  69. data/vendor/board-maps/yaml/ADAFRUIT_FEATHER_ESP32S3_NOPSRAM.yml +6 -1
  70. data/vendor/board-maps/yaml/ADAFRUIT_FEATHER_ESP32_V2.yml +5 -1
  71. data/vendor/board-maps/yaml/ADAFRUIT_QTPY_ESP32S3_N4R2.yml +20 -0
  72. data/vendor/board-maps/yaml/ADAFRUIT_QTPY_ESP32_PICO.yml +2 -1
  73. data/vendor/board-maps/yaml/ARTRONSHOP_RP2_NANO.yml +32 -0
  74. data/vendor/board-maps/yaml/AVR_CIRCUITPLAY.yml +1 -1
  75. data/vendor/board-maps/yaml/AVR_ESPLORA.yml +1 -1
  76. data/vendor/board-maps/yaml/AVR_INDUSTRIAL101.yml +1 -1
  77. data/vendor/board-maps/yaml/AVR_LEONARDO.yml +1 -1
  78. data/vendor/board-maps/yaml/AVR_LEONARDO_ETH.yml +1 -1
  79. data/vendor/board-maps/yaml/AVR_LILYPAD_USB.yml +1 -1
  80. data/vendor/board-maps/yaml/AVR_LININO_ONE.yml +1 -1
  81. data/vendor/board-maps/yaml/AVR_MICRO.yml +1 -1
  82. data/vendor/board-maps/yaml/AVR_ROBOT_CONTROL.yml +1 -1
  83. data/vendor/board-maps/yaml/AVR_ROBOT_MOTOR.yml +1 -1
  84. data/vendor/board-maps/yaml/AVR_YUN.yml +1 -1
  85. data/vendor/board-maps/yaml/AVR_YUNMINI.yml +1 -1
  86. data/vendor/board-maps/yaml/BPI_LEAF_S3.yml +11 -1
  87. data/vendor/board-maps/yaml/BeeMotionS3.yml +6 -1
  88. data/vendor/board-maps/yaml/Bee_Motion.yml +3 -0
  89. data/vendor/board-maps/yaml/Bee_S3.yml +1 -1
  90. data/vendor/board-maps/yaml/CHALLENGER_2040_WIFI6_BLE_RP2040.yml +42 -0
  91. data/vendor/board-maps/yaml/CYTRON_MAKER_FEATHER_AIOT_S3.yml +4 -1
  92. data/vendor/board-maps/yaml/CoreESP32.yml +5 -1
  93. data/vendor/board-maps/yaml/D1_MINI32.yml +10 -1
  94. data/vendor/board-maps/yaml/DENKY.yml +10 -1
  95. data/vendor/board-maps/yaml/DENKY_PICOV3.yml +10 -1
  96. data/vendor/board-maps/yaml/DENKY_WROOM32.yml +10 -1
  97. data/vendor/board-maps/yaml/DFROBOT_FIREBEETLE_2_ESP32E.yml +6 -1
  98. data/vendor/board-maps/yaml/DPU_ESP32.yml +10 -1
  99. data/vendor/board-maps/yaml/D_Duino_32.yml +9 -1
  100. data/vendor/board-maps/yaml/ESP32S2_DEV.yml +11 -1
  101. data/vendor/board-maps/yaml/ESP32S2_THING_PLUS.yml +11 -1
  102. data/vendor/board-maps/yaml/ESP32S2_USB.yml +11 -1
  103. data/vendor/board-maps/yaml/ESP32_DEV.yml +10 -1
  104. data/vendor/board-maps/yaml/ESP32_DEVKIT_LIPO.yml +10 -1
  105. data/vendor/board-maps/yaml/ESP32_IOT_REDBOARD.yml +10 -1
  106. data/vendor/board-maps/yaml/ESP32_PICO.yml +10 -1
  107. data/vendor/board-maps/yaml/ESP32_S3_BOX.yml +4 -1
  108. data/vendor/board-maps/yaml/ESP32_THING.yml +10 -1
  109. data/vendor/board-maps/yaml/ESP32_THING_PLUS.yml +4 -1
  110. data/vendor/board-maps/yaml/ESP32_THING_PLUS_C.yml +4 -1
  111. data/vendor/board-maps/yaml/ESP32_WROOM_DA.yml +10 -1
  112. data/vendor/board-maps/yaml/ESP32_WROVER_KIT.yml +10 -1
  113. data/vendor/board-maps/yaml/ESPECTRO32.yml +10 -1
  114. data/vendor/board-maps/yaml/ESPea32.yml +10 -1
  115. data/vendor/board-maps/yaml/ESPino32.yml +10 -1
  116. data/vendor/board-maps/yaml/FEATHERS2.yml +11 -1
  117. data/vendor/board-maps/yaml/FEATHERS2NEO.yml +2 -1
  118. data/vendor/board-maps/yaml/FEATHERS3.yml +3 -0
  119. data/vendor/board-maps/yaml/FEATHER_ESP32.yml +5 -1
  120. data/vendor/board-maps/yaml/FRANZININHO_WIFI.yml +11 -1
  121. data/vendor/board-maps/yaml/FRANZININHO_WIFI_MSC.yml +11 -1
  122. data/vendor/board-maps/yaml/FROG_ESP32.yml +10 -1
  123. data/vendor/board-maps/yaml/HEALTHYPI_4.yml +10 -1
  124. data/vendor/board-maps/yaml/HONEYLEMON.yml +10 -1
  125. data/vendor/board-maps/yaml/HORNBILL_ESP32_DEV.yml +10 -1
  126. data/vendor/board-maps/yaml/HORNBILL_ESP32_MINIMA.yml +4 -1
  127. data/vendor/board-maps/yaml/IMBRIOS_LOGSENS_V1P1.yml +5 -1
  128. data/vendor/board-maps/yaml/LILYGO_T_DISPLAY_S3.yml +7 -1
  129. data/vendor/board-maps/yaml/LOLIN32.yml +10 -1
  130. data/vendor/board-maps/yaml/LOLIN32_LITE.yml +10 -1
  131. data/vendor/board-maps/yaml/LOLIN_D32.yml +10 -1
  132. data/vendor/board-maps/yaml/LOLIN_D32_PRO.yml +10 -1
  133. data/vendor/board-maps/yaml/LOLIN_S2_MINI.yml +11 -1
  134. data/vendor/board-maps/yaml/LOLIN_S2_PICO.yml +11 -1
  135. data/vendor/board-maps/yaml/LOLIN_S3.yml +9 -1
  136. data/vendor/board-maps/yaml/LOLIN_S3_MINI.yml +9 -1
  137. data/vendor/board-maps/yaml/LOLIN_S3_PRO.yml +9 -1
  138. data/vendor/board-maps/yaml/LoPy.yml +11 -1
  139. data/vendor/board-maps/yaml/LoPy4.yml +11 -1
  140. data/vendor/board-maps/yaml/MAGTAG29_ESP32S2.yml +11 -1
  141. data/vendor/board-maps/yaml/METRO_ESP32S2.yml +11 -1
  142. data/vendor/board-maps/yaml/MGBOT_IOTIK32A.yml +10 -1
  143. data/vendor/board-maps/yaml/MGBOT_IOTIK32B.yml +10 -1
  144. data/vendor/board-maps/yaml/MH_ET_LIVE_ESP32DEVKIT.yml +10 -1
  145. data/vendor/board-maps/yaml/MH_ET_LIVE_ESP32MINIKIT.yml +10 -1
  146. data/vendor/board-maps/yaml/MICROS2.yml +11 -1
  147. data/vendor/board-maps/yaml/MINIMA.yml +15 -0
  148. data/vendor/board-maps/yaml/NANO32.yml +10 -1
  149. data/vendor/board-maps/yaml/Node32s.yml +10 -1
  150. data/vendor/board-maps/yaml/NodeMCU_32S.yml +10 -1
  151. data/vendor/board-maps/yaml/ONEHORSE_ESP32_DEV.yml +11 -1
  152. data/vendor/board-maps/yaml/PIMORONI_PLASMA2040.yml +29 -0
  153. data/vendor/board-maps/yaml/PORTENTA_C33.yml +28 -0
  154. data/vendor/board-maps/yaml/PROS3.yml +6 -1
  155. data/vendor/board-maps/yaml/PYCOM_GPY.yml +11 -1
  156. data/vendor/board-maps/yaml/Piranha.yml +7 -1
  157. data/vendor/board-maps/yaml/Pocket32.yml +10 -1
  158. data/vendor/board-maps/yaml/QUANTUM.yml +10 -1
  159. data/vendor/board-maps/yaml/REDPILL_ESP32S3.yml +11 -1
  160. data/vendor/board-maps/yaml/RMP.yml +11 -1
  161. data/vendor/board-maps/yaml/SAMD_CIRCUITPLAYGROUND_EXPRESS.yml +0 -1
  162. data/vendor/board-maps/yaml/SAM_DUE.yml +3 -1
  163. data/vendor/board-maps/yaml/SONOFF_DUALR3.yml +10 -1
  164. data/vendor/board-maps/yaml/TAMC_TERMOD_S3.yml +11 -1
  165. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1262.yml +6 -1
  166. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1268.yml +6 -1
  167. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1276.yml +6 -1
  168. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1278.yml +6 -1
  169. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1280.yml +6 -1
  170. data/vendor/board-maps/yaml/TBeam.yml +6 -1
  171. data/vendor/board-maps/yaml/TINYPICO.yml +10 -1
  172. data/vendor/board-maps/yaml/TINYS2.yml +11 -1
  173. data/vendor/board-maps/yaml/TTGO_LoRa32_V1.yml +11 -1
  174. data/vendor/board-maps/yaml/TTGO_LoRa32_V2.yml +11 -1
  175. data/vendor/board-maps/yaml/TTGO_LoRa32_v21new.yml +11 -1
  176. data/vendor/board-maps/yaml/TTGO_T1.yml +10 -1
  177. data/vendor/board-maps/yaml/TTGO_T7_V13_Mini32.yml +10 -1
  178. data/vendor/board-maps/yaml/TTGO_T7_V14_Mini32.yml +10 -1
  179. data/vendor/board-maps/yaml/TWATCH_2020_V1.yml +0 -1
  180. data/vendor/board-maps/yaml/TWATCH_2020_V2.yml +0 -1
  181. data/vendor/board-maps/yaml/TWATCH_2020_V3.yml +0 -1
  182. data/vendor/board-maps/yaml/TWATCH_BASE.yml +0 -1
  183. data/vendor/board-maps/yaml/TWatch.yml +0 -1
  184. data/vendor/board-maps/yaml/UBLOX_NINA_W10.yml +10 -1
  185. data/vendor/board-maps/yaml/UNOWIFIR4.yml +17 -0
  186. data/vendor/board-maps/yaml/WIPY3.yml +11 -1
  187. data/vendor/board-maps/yaml/XIAO_ESP32S3.yml +2 -1
  188. data/vendor/board-maps/yaml/connaxio_espoir.yml +7 -1
  189. data/vendor/board-maps/yaml/esp32vn_iot_uno.yml +10 -1
  190. data/vendor/board-maps/yaml/heltec_wifi_32_lora_V3.yml +11 -1
  191. data/vendor/board-maps/yaml/heltec_wifi_kit_32.yml +11 -1
  192. data/vendor/board-maps/yaml/heltec_wifi_kit_32_V3.yml +11 -1
  193. data/vendor/board-maps/yaml/heltec_wifi_lora_32.yml +10 -1
  194. data/vendor/board-maps/yaml/heltec_wifi_lora_32_V2.yml +10 -1
  195. data/vendor/board-maps/yaml/heltec_wireless_stick.yml +10 -1
  196. data/vendor/board-maps/yaml/heltec_wireless_stick_LITE.yml +10 -1
  197. data/vendor/board-maps/yaml/openkb.yml +11 -1
  198. data/vendor/board-maps/yaml/roboheart_hercules.yml +10 -1
  199. data/vendor/board-maps/yaml/sensesiot_weizen.yml +10 -1
  200. data/vendor/board-maps/yaml/uPesy_WROOM.yml +10 -1
  201. data/vendor/board-maps/yaml/uPesy_WROVER.yml +10 -1
  202. data/vendor/board-maps/yaml/unphone8.yml +11 -1
  203. data/vendor/board-maps/yaml/unphone9.yml +11 -1
  204. metadata +14 -2
@@ -1,52 +1,55 @@
1
1
  #
2
- # This is an example of how to use the sensor class
3
- # You must register data callbacks and have the main thread
4
- # sleep or in someway keep running or your program
5
- # will exit before any callbacks can be called
2
+ # This example shows how to use your board's analog-to-digital-converter(ADC) pins,
3
+ # through the AnalogIO::Input class. ADC inputs can be connected to sensors
4
+ # which produce a variable output voltage, such as light dependent resistors,
5
+ # or a simple temperature sensor like the TMP36.
6
6
  #
7
7
  require 'bundler/setup'
8
8
  require 'denko'
9
9
 
10
10
  board = Denko::Board.new(Denko::Connection::Serial.new)
11
- sensor = Denko::AnalogIO::Sensor.new(pin: 'A0', board: board)
12
-
13
- # Single read with block as callback. Blocks main thread.
14
- # Callback fires only once then is removed automatically.
15
- sensor.read { |value| puts "#{Time.now} Single read: #{value}" }
16
-
17
- # Poll the sensor every 1 second with block as callback. Does not block main thread.
18
- # Callback fires every time data is received until #stop is called.
19
- sensor.poll(1) { |value| puts "#{Time.now} Polling: #{value}" }
20
- sleep 5
21
-
22
- # Stop polling. Automatically removes the callback from the #poll block.
23
- sensor.stop
24
-
25
- # Continuous listen with block as callback. Fires every time data is received until #stop is called.
26
- sensor.listen { |value| puts "#{Time.now} Listening: #{value}" }
11
+ input = Denko::AnalogIO::Input.new(pin: :A0, board: board)
12
+
13
+ # Single read that blocks the main thread. When a value is received, the given
14
+ # code block runs only once, and then the main thread continues.
15
+ input.read { |value| puts "#{Time.now} Single read #1: #{value}" }
16
+
17
+ # Read (poll) the input every half second. This happens in a separate thread,
18
+ # so sleep the main thread for a while to get some values.
19
+ # Given code block is added as a callback, and runs every time a value is received.
20
+ input.poll(0.5) { |value| puts "#{Time.now} Polling: #{value}" }
21
+ sleep 3
22
+
23
+ # Stop polling. Automatically removes the #poll callback.
24
+ input.stop
25
+
26
+ # Listening is similar to polling. The board reads the input and sends the value
27
+ # every time interval, except it's keeping time. We only send the initial command,
28
+ # not one for each read. Smaller intervals like 32 milliseconds are possible.
29
+ # Powers of 2 from 1 to 128 are supported for listener intervals.
30
+ input.listen(32) { |value| puts "#{Time.now} Listening: #{value}" }
27
31
  sleep 0.5
28
32
 
29
- # Stop listening. Automatically removes the callback from the #listen block.
30
- sensor.stop
31
-
32
- # Add a persistent callback.
33
- sensor.on_data { |value| puts "#{Time.now} Persistent callback: #{value}" }
33
+ # Stop listening. Automatically removes the #listen callback.
34
+ input.stop
34
35
 
35
- # Add a callback with a custom key.
36
- sensor.on_data(:test) { |value| puts "#{Time.now} Keyed callback: #{value}"}
36
+ # This adds a persistent callback, which runs no matter how a read happens.
37
+ # It will not be removed by #stop.
38
+ input.on_data { |value| puts "#{Time.now} Persistent callback: #{value}" }
37
39
 
38
- # Single read again. Block given fires only once. Callbacks added with #on_data fire also.
39
- sensor.read { |value| puts "#{Time.now} Single read again: #{value}" }
40
+ # This is a persistent callback with a custom key.
41
+ input.on_data(:test) { |value| puts "#{Time.now} Keyed callback: #{value}"}
40
42
 
41
- # Continuous listen. Block fires each time. Callbacks added with #on_data continue to fire.
42
- sensor.listen { |value| puts "#{Time.now } Listening again: #{value}" }
43
- sleep 0.5
43
+ # If we do a single read, the two persistent callbacks, and the block given, should run once each.
44
+ input.read { |value| puts "#{Time.now} Single read #2: #{value}" }
44
45
 
45
- # Stop listening. Automatically removes the callback from the #listen block.
46
- sensor.stop
46
+ # If we listen, the two persistent callbacks, and the block given should run many times.
47
+ input.listen(8) { |value| puts "#{Time.now } Listening again: #{value}" }
48
+ sleep 0.125
49
+ input.stop
47
50
 
48
51
  # Remove callbacks keyed with :test.
49
- sensor.remove_callbacks(:test)
52
+ input.remove_callbacks(:test)
50
53
 
51
54
  # Remove all callbacks.
52
- sensor.remove_callbacks
55
+ input.remove_callbacks
@@ -11,7 +11,7 @@ connection = Denko::Connection::TCP.new("192.168.0.77", 3466)
11
11
  # connection = Denko::Connection::TCP.new("192.168.1.2", 3466)
12
12
  #
13
13
  board = Denko::Board.new(connection)
14
- led = Denko::Led.new(pin: 13, board: board)
14
+ led = Denko::LED.new(board: board, pin: :LED_BUILTIN)
15
15
 
16
16
  [:on, :off].cycle do |switch|
17
17
  led.send(switch)
@@ -6,9 +6,9 @@ require 'denko'
6
6
 
7
7
  board = Denko::Board.new(Denko::Connection::Serial.new)
8
8
  lcd = Denko::Display::HD44780.new board: board,
9
- pins: { rs: 8, enable: 9, d4: 4, d5: 5, d6: 6, d7: 7 },
10
- cols: 16,
11
- rows: 2
9
+ pins: { rs: 8, enable: 9, d4: 4, d5: 5, d6: 6, d7: 7 },
10
+ cols: 16,
11
+ rows: 2
12
12
 
13
13
  # Bitmap for a custom character. 5 bits wide x 8 high.
14
14
  # Useful for generating these: https://omerk.github.io/lcdchargen/
@@ -21,7 +21,7 @@ board = Denko::Board.new(Denko::Connection::Serial.new)
21
21
  # Only give the SDA pin of the I2C bus. SCL (clock) pin must be
22
22
  # connected for it to work, but we don't need to control it.
23
23
  #
24
- bus = Denko::I2C::Bus.new(board: board, pin: 'A4')
24
+ bus = Denko::I2C::Bus.new(board: board, pin: :SDA)
25
25
  oled = Denko::Display::SSD1306.new(bus: bus, rotate: true)
26
26
  canvas = oled.canvas
27
27
 
@@ -7,6 +7,7 @@ require 'denko'
7
7
  board = Denko::Board.new(Denko::Connection::Serial.new)
8
8
  buzzer = Denko::PulseIO::Buzzer.new(board: board, pin: 9)
9
9
 
10
+ =begin
10
11
  C4 = 262
11
12
  D4 = 294
12
13
  E4 = 330
@@ -28,3 +29,42 @@ end
28
29
 
29
30
  buzzer.stop
30
31
  board.finish_write
32
+ =end
33
+
34
+
35
+
36
+ AS3 = 233
37
+ BN3 = 257
38
+ DS4 = 311
39
+ FN4 = 349
40
+ FS4 = 370
41
+ GS4 = 415
42
+
43
+ notes = [
44
+ [AS3, 1], [AS3, 1], [AS3, 1], [AS3, 1],
45
+ [AS3, 0.75], [BN3, 0.75], [DS4, 0.5], [AS3, 1], [AS3, 0.5], [nil, 0.5],
46
+ [AS3, 0.75], [BN3, 0.75], [DS4, 0.5], [AS3, 1], [AS3, 0.5], [nil, 0.5],
47
+ [AS3, 0.75], [BN3, 0.75], [DS4, 0.5], [FN4, 1], [FN4, 0.5], [nil, 0.5],
48
+ [GS4, 0.75], [FS4, 0.75], [FN4, 0.5], [DS4, 1], [DS4, 0.5], [nil, 0.5],
49
+ [GS4, 0.75], [FS4, 0.75], [FN4, 0.5], [DS4, 1], [DS4, 0.5], [nil, 0.5],
50
+ [AS3, 0.75], [BN3, 0.75], [DS4, 0.5], [AS3, 1], [AS3, 0.5], [nil, 0.5],
51
+ [AS3, 0.75], [BN3, 0.75], [DS4, 0.5], [AS3, 1], [AS3, 0.5], [nil, 0.5],
52
+ ]
53
+
54
+ bpm = 135
55
+ beat_time = 60.to_f / bpm
56
+
57
+ notes.each do |note|
58
+ if note[0]
59
+ buzzer.tone(note[0])
60
+ sleep(note[1] * beat_time)
61
+ else
62
+ buzzer.stop
63
+ sleep((note[1] * beat_time))
64
+ end
65
+ buzzer.stop
66
+ buzzer.micro_delay(5)
67
+ end
68
+
69
+ buzzer.stop
70
+ board.finish_write
@@ -0,0 +1,61 @@
1
+ module Denko
2
+ module AnalogIO
3
+ class ADS1115
4
+ include I2C::Peripheral
5
+ include ADS111X
6
+
7
+ # Config register values on startup. MSB-first.
8
+ # Matches datasheet, except MSB bit 7 unset to avoid conversion start.
9
+ # Same as: [0x05, 0x83] or [5, 131]
10
+ CONFIG_STARTUP = [0b00000101, 0b10000011]
11
+
12
+ # Base config bytes to mask settings into. Not same as startup config.
13
+ # MSB bits 0 and 7 set to enable single-shot mode.
14
+ # LSB bits 0 and 1 set to disable comparator.
15
+ BASE_MSB = 0b10000001
16
+ BASE_LSB = 0b00000011
17
+
18
+ # Register addresses.
19
+ CONFIG_ADDRESS = 0b01
20
+ CONVERSION_ADDRESS = 0b00
21
+
22
+ def before_initialize(options={})
23
+ @i2c_address = 0x48
24
+ @i2c_frequency = 400_000
25
+ super(options)
26
+ end
27
+
28
+ def after_initialize(options={})
29
+ super(options)
30
+
31
+ # Mutex and variables for BoardProxy behavior.
32
+ @mutex = Mutex.new
33
+ @active_pin = nil
34
+ @active_gain = nil
35
+
36
+ # Set register bytes to default and write to device.
37
+ @config_register = CONFIG_STARTUP.dup
38
+ i2c_write [CONFIG_ADDRESS] + @config_register
39
+
40
+ # Enable BoardProxy callbacks.
41
+ enable_proxy
42
+ end
43
+
44
+ def _read(config)
45
+ # Write config register to start reading.
46
+ i2c_write [CONFIG_ADDRESS] + config
47
+
48
+ # Sleep the right amount of time for conversion, based on sample rate bits.
49
+ sleep WAIT_TIMES[config[1] >> 5]
50
+
51
+ # Read the result, triggering callbacks.
52
+ i2c_read(CONVERSION_ADDRESS, 2)
53
+ end
54
+
55
+ # Readings are 2 bytes big-endian.
56
+ def pre_callback_filter(bytes)
57
+ bytes.pack("C*").unpack("s>")[0]
58
+ end
59
+ end
60
+ end
61
+ end
@@ -2,55 +2,18 @@ module Denko
2
2
  module AnalogIO
3
3
  class ADS1118
4
4
  include SPI::Peripheral
5
- include Behaviors::Reader
6
- include Behaviors::Threaded
5
+ include ADS111X
7
6
 
8
- PGA_SETTINGS = [ # Bitmask Full scale voltage
9
- 0.0001875, # 0b000 6.144 V
10
- 0.000125, # 0b001 4.095 V
11
- 0.0000625, # 0b010 2.048 V (default)
12
- 0.00003125, # 0b011 1.024 V
13
- 0.000015625, # 0b100 0.512 V
14
- 0.0000078125, # 0b101 0.256 V
15
- 0.0000078125, # 0b110 0.256 V
16
- 0.0000078125, # 0b111 0.256 V
17
- ]
18
- PGA_RANGE = (0..7).to_a
19
-
20
- # Sample rate bitmask maps to sample time in seconds.
21
- SAMPLE_TIMES = [ # Bitmask
22
- 0.125, # 0b000
23
- 0.0625, # 0b001
24
- 0.03125, # 0b010
25
- 0.015625, # 0b011
26
- 0.0078125, # 0b100 (default)
27
- 0.004, # 0b101
28
- 0.002105263, # 0b110
29
- 0.00116279, # 0b111
30
- ]
31
- SAMPLE_RATE_RANGE = (0..7).to_a
32
-
33
- # Wait times need to be slightly longer than the actual sample times.
34
- WAIT_TIMES = SAMPLE_TIMES.map { |time| time + 0.0005 }
35
-
36
- # Mux bits map to array of form [positive input, negative input].
37
- MUX_SETTINGS = {
38
- 0b000 => [0, 1],
39
- 0b001 => [0, 3],
40
- 0b010 => [1, 3],
41
- 0b011 => [2, 3],
42
- 0b100 => [0, nil],
43
- 0b101 => [1, nil],
44
- 0b110 => [2, nil],
45
- 0b111 => [3, nil],
46
- }
47
-
48
- # Config register values on startup.
49
- CONFIG_DEFAULT = [0x05, 0x8B]
7
+ # Config register values on startup. MSB-first.
8
+ # Matches datasheet. Same as: [0x05, 0x8B] or [5, 139]
9
+ CONFIG_STARTUP = [0b00000101, 0b10001011]
50
10
 
51
11
  # Base config bytes to mask settings into. Not same as default.
12
+ # MSB bits 0 and 7 set to enable single-shot mode.
13
+ # LSB bit 3 set to enable pullup resistor on MISO pin.
14
+ # LSB bit 1 set to flag valid data in the NOP bits.
52
15
  BASE_MSB = 0b10000001
53
- BASE_LSB = 0b00001011
16
+ BASE_LSB = 0b00001010
54
17
 
55
18
  def after_initialize(options={})
56
19
  super(options)
@@ -64,7 +27,7 @@ module Denko
64
27
  @active_gain = nil
65
28
 
66
29
  # Set register bytes to default and write to device.
67
- @config_register = CONFIG_DEFAULT.dup
30
+ @config_register = CONFIG_STARTUP.dup
68
31
  spi_write(@config_register)
69
32
 
70
33
  # Enable BoardProxy callbacks.
@@ -82,7 +45,7 @@ module Denko
82
45
  spi_read(2)
83
46
  end
84
47
 
85
- # Pack the 2 bytes back into a string, then unpack as big-endian int16.
48
+ # Pack the 2 bytes back into a string, then unpack as big-endian signed int16.
86
49
  def pre_callback_filter(message)
87
50
  bytes = message.split(",").map { |b| b.to_i }
88
51
  bytes.pack("C*").unpack("s>")[0]
@@ -104,79 +67,6 @@ module Denko
104
67
  block.call(temperature) if block_given?
105
68
  return temperature
106
69
  end
107
-
108
- #
109
- # BoardProxy behavior so AnalogIO classes can use this as a Board.
110
- #
111
- include Behaviors::BoardProxy
112
-
113
- # Mimic Board#update, but inside a callback, wrapped by #update.
114
- def enable_proxy
115
- self.add_callback(:board_proxy) do |value|
116
- components.each do |component|
117
- if @active_pin == component.pin
118
- component.volts_per_bit = PGA_SETTINGS[@active_gain]
119
- component.update(value)
120
- end
121
- end
122
- end
123
- end
124
-
125
- def analog_read(pin, negative_pin=nil, gain=nil, sample_rate=nil)
126
- # Wrap in mutex so calls and callbacks are atomic.
127
- @mutex.synchronize do
128
- # Default gain and sample rate.
129
- gain ||= 0b010
130
- sample_rate ||= 0b100
131
-
132
- # Set these for callbacks.
133
- @active_pin = pin
134
- @active_gain = gain
135
-
136
- # Set gain in upper config register.
137
- raise ArgumentError "wrong gain: #{gain.inspect} given for ADS1118" unless PGA_RANGE.include?(gain)
138
- @config_register[0] = BASE_MSB | (gain << 1)
139
-
140
- # Set mux bits in upper config register.
141
- mux_bits = pins_to_mux_bits(pin, negative_pin)
142
- @config_register[0] = @config_register[0] | (mux_bits << 4)
143
-
144
- # Set sample rate in lower config_register.
145
- raise ArgumentError "wrong sample_rate: #{sample_rate.inspect} given for ADS1118" unless SAMPLE_RATE_RANGE.include?(gain)
146
- @config_register[1] = BASE_LSB | (sample_rate << 5)
147
-
148
- read(@config_register)
149
- end
150
- end
151
-
152
- def pins_to_mux_bits(pin, negative_pin)
153
- # Pin 1 is negative input. Only pin 0 can be read.
154
- if negative_pin == 1
155
- raise ArgumentError, "given pin: #{pin.inspect} cannot be used when pin 1 is negative input, only 0" unless pin == 0
156
- return 0b000
157
- end
158
-
159
- # Pin 3 is negative input. Pins 0..2 can be read.
160
- if negative_pin == 3
161
- raise ArgumentError, "given pin: #{pin.inspect} cannot be used when pin 3 is negative input, only 0..2" unless [0,1,2].include? pin
162
- return 0b001 + pin
163
- end
164
-
165
- # No negative input. Any pin from 0 to 3 can be read.
166
- unless negative_pin
167
- raise ArgumentError, "given pin: #{pin.inspect} is out of range 0..3" unless [0,1,2,3].include? pin
168
- return (0b100 + pin)
169
- end
170
-
171
- raise ArgumentError, "only pins 1 and 3 can be used as negative input"
172
- end
173
-
174
- def analog_listen(pin, divider=nil)
175
- raise StandardError, "ADS1118 does not implement #listen for subcomponents. Use #read or #poll instead"
176
- end
177
-
178
- def stop_listener(pin)
179
- end
180
70
  end
181
71
  end
182
72
  end
@@ -0,0 +1,123 @@
1
+ module Denko
2
+ module AnalogIO
3
+ module ADS111X
4
+ #
5
+ # Functionality shared among the ADS111X class of ADC converters.
6
+ #
7
+ include Behaviors::Reader
8
+
9
+ PGA_SETTINGS = [ # Bitmask Full scale voltage
10
+ 0.0001875, # 0b000 6.144 V
11
+ 0.000125, # 0b001 4.095 V
12
+ 0.0000625, # 0b010 2.048 V (default)
13
+ 0.00003125, # 0b011 1.024 V
14
+ 0.000015625, # 0b100 0.512 V
15
+ 0.0000078125, # 0b101 0.256 V
16
+ 0.0000078125, # 0b110 0.256 V
17
+ 0.0000078125, # 0b111 0.256 V
18
+ ]
19
+ PGA_RANGE = (0..7).to_a
20
+
21
+ # Sample rate bitmask maps to sample time in seconds.
22
+ SAMPLE_TIMES = [ # Bitmask
23
+ 0.125, # 0b000
24
+ 0.0625, # 0b001
25
+ 0.03125, # 0b010
26
+ 0.015625, # 0b011
27
+ 0.0078125, # 0b100 (default)
28
+ 0.004, # 0b101
29
+ 0.002105263, # 0b110
30
+ 0.00116279, # 0b111
31
+ ]
32
+ SAMPLE_RATE_RANGE = (0..7).to_a
33
+
34
+ # Wait times need to be slightly longer than the actual sample times.
35
+ WAIT_TIMES = SAMPLE_TIMES.map { |time| time + 0.0005 }
36
+
37
+ # Mux bits map to array of form [positive input, negative input].
38
+ MUX_SETTINGS = {
39
+ 0b000 => [0, 1],
40
+ 0b001 => [0, 3],
41
+ 0b010 => [1, 3],
42
+ 0b011 => [2, 3],
43
+ 0b100 => [0, nil],
44
+ 0b101 => [1, nil],
45
+ 0b110 => [2, nil],
46
+ 0b111 => [3, nil],
47
+ }
48
+
49
+ #
50
+ # BoardProxy behavior so AnalogIO classes can use this as a Board.
51
+ #
52
+ include Behaviors::BoardProxy
53
+
54
+ # Mimic Board#update, but inside a callback, wrapped by #update.
55
+ def enable_proxy
56
+ self.add_callback(:board_proxy) do |value|
57
+ components.each do |component|
58
+ if @active_pin == component.pin
59
+ component.volts_per_bit = PGA_SETTINGS[@active_gain]
60
+ component.update(value)
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ def analog_read(pin, negative_pin=nil, gain=nil, sample_rate=nil)
67
+ # Wrap in mutex so calls and callbacks are atomic.
68
+ @mutex.synchronize do
69
+ # Default gain and sample rate.
70
+ gain ||= 0b010
71
+ sample_rate ||= 0b100
72
+
73
+ # Set these for callbacks.
74
+ @active_pin = pin
75
+ @active_gain = gain
76
+
77
+ # Set gain in upper config register.
78
+ raise ArgumentError "wrong gain: #{gain.inspect} given for ADS111X" unless PGA_RANGE.include?(gain)
79
+ @config_register[0] = self.class::BASE_MSB | (gain << 1)
80
+
81
+ # Set mux bits in upper config register.
82
+ mux_bits = pins_to_mux_bits(pin, negative_pin)
83
+ @config_register[0] = @config_register[0] | (mux_bits << 4)
84
+
85
+ # Set sample rate in lower config_register.
86
+ raise ArgumentError "wrong sample_rate: #{sample_rate.inspect} given for ADS111X" unless SAMPLE_RATE_RANGE.include?(gain)
87
+ @config_register[1] = self.class::BASE_LSB | (sample_rate << 5)
88
+
89
+ read(@config_register)
90
+ end
91
+ end
92
+
93
+ def pins_to_mux_bits(pin, negative_pin)
94
+ # Pin 1 is negative input. Only pin 0 can be read.
95
+ if negative_pin == 1
96
+ raise ArgumentError, "given pin: #{pin.inspect} cannot be used when pin 1 is negative input, only 0" unless pin == 0
97
+ return 0b000
98
+ end
99
+
100
+ # Pin 3 is negative input. Pins 0..2 can be read.
101
+ if negative_pin == 3
102
+ raise ArgumentError, "given pin: #{pin.inspect} cannot be used when pin 3 is negative input, only 0..2" unless [0,1,2].include? pin
103
+ return 0b001 + pin
104
+ end
105
+
106
+ # No negative input. Any pin from 0 to 3 can be read.
107
+ unless negative_pin
108
+ raise ArgumentError, "given pin: #{pin.inspect} is out of range 0..3" unless [0,1,2,3].include? pin
109
+ return (0b100 + pin)
110
+ end
111
+
112
+ raise ArgumentError, "only pins 1 and 3 can be used as negative input"
113
+ end
114
+
115
+ def analog_listen(pin, divider=nil)
116
+ raise StandardError, "ADS111X does not implement #listen for subcomponents. Use #read or #poll instead"
117
+ end
118
+
119
+ def stop_listener(pin)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -13,7 +13,8 @@ module Denko
13
13
  end
14
14
 
15
15
  def write(value)
16
- board.dac_write(pin, @state = value)
16
+ @board.dac_write(@pin, value)
17
+ self.state = value
17
18
  end
18
19
  end
19
20
  end
@@ -4,6 +4,8 @@ module Denko
4
4
  autoload :Output, "#{__dir__}/analog_io/output"
5
5
  autoload :Potentiometer, "#{__dir__}/analog_io/potentiometer"
6
6
  autoload :Sensor, "#{__dir__}/analog_io/sensor"
7
+ autoload :ADS111X, "#{__dir__}/analog_io/ads111x"
8
+ autoload :ADS1115, "#{__dir__}/analog_io/ads1115"
7
9
  autoload :ADS1118, "#{__dir__}/analog_io/ads1118"
8
10
  end
9
11
  end
@@ -12,28 +12,29 @@ module Denko
12
12
  end
13
13
 
14
14
  #
15
- # Delegate reading to another method that sends a command to the board.
16
- # Accepts blocks as one-time callbacks stored in the :read key.
17
- # Blocks until a value is recieved from the board.
18
- # Returns the value after #pre_callback_filter runs on it.
15
+ # Take a proc/lambda/method as the first agrument and use it to read.
16
+ # Arguments are passed through, allowing dynamic read methods to be defined.
17
+ # 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.
19
22
  #
20
- # Give procs as methods to build more complex functionality for buses.
21
- #
22
- def read_using(method, *args, **kwargs, &block)
23
+ def read_using(reader, *args, **kwargs, &block)
23
24
  add_callback(:read, &block) if block_given?
24
25
 
25
- value = nil
26
+ return_value = nil
26
27
  add_callback(:read) do |filtered_data|
27
- value = filtered_data
28
+ return_value = filtered_data
28
29
  end
29
30
 
30
- method.call(*args, **kwargs)
31
- block_until_read
31
+ reader.call(*args, **kwargs)
32
+ wait_for_read
32
33
 
33
- value
34
+ return_value
34
35
  end
35
36
 
36
- def block_until_read
37
+ def wait_for_read
37
38
  loop do
38
39
  break if !callbacks[:read]
39
40
  sleep 0.001
@@ -10,8 +10,6 @@ module Denko
10
10
  end
11
11
 
12
12
  def add_component(component)
13
- components << component
14
-
15
13
  if component.respond_to?(:pin) && component.pin.class == Integer
16
14
  unless single_pin_components[component.pin]
17
15
  single_pin_components[component.pin] = component
@@ -20,6 +18,8 @@ module Denko
20
18
  "already in use by: #{single_pin_components[component.pin]}"
21
19
  end
22
20
  end
21
+
22
+ components << component
23
23
  end
24
24
 
25
25
  def remove_component(component)
@@ -119,7 +119,7 @@ module Denko
119
119
  # CMD = 95
120
120
  def set_register_divider(value)
121
121
  unless DIVIDERS.include?(value)
122
- raise ArgumentError, "error in divider: #{options[:divider]}. Should be one of: #{DIVIDERS.inspect}"
122
+ raise ArgumentError, "error in divider: #{value}. Should be one of: #{DIVIDERS.inspect}"
123
123
  end
124
124
  write Message.encode(command: 95, value: value)
125
125
  end
@@ -7,10 +7,7 @@ module Denko
7
7
  3400000 => 0x03,
8
8
  }
9
9
 
10
- # Might make this bigger based on board maps later, but stick with the lowest limit of the AVR boards for now.
11
- def i2c_limit
12
- 32
13
- end
10
+ attr_reader :i2c_limit
14
11
 
15
12
  def i2c_convert_frequency(freq)
16
13
  # Default to 100 kHz.
@@ -6,10 +6,19 @@ module Denko
6
6
 
7
7
  attr_reader :map
8
8
 
9
+ def substitute_zero_pins
10
+ ["SDA", "SCL", "MOSI", "MISO", "SCK", "SS"].each do |name|
11
+ symbol = name.to_sym
12
+ zero_symbol = (name + "0").to_sym
13
+ @map[symbol] = @map[zero_symbol] if (@map[zero_symbol] && !@map[symbol])
14
+ end
15
+ end
16
+
9
17
  def load_map(board_name)
10
18
  if board_name
11
19
  map_path = File.join(MAPS_FOLDER, "#{board_name}.yml")
12
20
  @map = YAML.load_file(map_path)
21
+ substitute_zero_pins
13
22
  else
14
23
  @map = nil
15
24
  end
@@ -1,15 +1,11 @@
1
1
  module Denko
2
2
  class Board
3
3
  # CMD = 10
4
- def servo_toggle(pin, value=:off, options={})
5
- options[:min] ||= 544
6
- options[:max] ||= 2400
7
- aux = pack :uint16, [options[:min], options[:max]]
8
-
4
+ def servo_toggle(pin, value=:off, min: 544, max: 2400)
9
5
  write Message.encode command: 10,
10
6
  pin: pin,
11
7
  value: (value == :off) ? 0 : 1,
12
- aux_message: aux
8
+ aux_message: pack(:uint16, [min, max])
13
9
  end
14
10
 
15
11
  # CMD = 11