denko 0.13.0 → 0.13.2

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 (218) 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 +98 -75
  14. data/README.md +48 -59
  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/examples/sensor/aht20.rb +1 -1
  25. data/lib/denko/analog_io/ads1115.rb +61 -0
  26. data/lib/denko/analog_io/ads1118.rb +10 -120
  27. data/lib/denko/analog_io/ads111x.rb +123 -0
  28. data/lib/denko/analog_io/output.rb +2 -1
  29. data/lib/denko/analog_io.rb +2 -0
  30. data/lib/denko/behaviors/bus_peripheral_addressed.rb +1 -1
  31. data/lib/denko/behaviors/component.rb +1 -1
  32. data/lib/denko/behaviors/input_pin.rb +3 -0
  33. data/lib/denko/behaviors/reader.rb +14 -13
  34. data/lib/denko/behaviors/single_pin.rb +1 -3
  35. data/lib/denko/behaviors/state.rb +1 -0
  36. data/lib/denko/behaviors/subcomponents.rb +2 -2
  37. data/lib/denko/board/core.rb +1 -1
  38. data/lib/denko/board/i2c.rb +1 -4
  39. data/lib/denko/board/map.rb +9 -0
  40. data/lib/denko/board/servo.rb +2 -6
  41. data/lib/denko/board.rb +32 -20
  42. data/lib/denko/connection/board_uart.rb +3 -3
  43. data/lib/denko/connection/flow_control.rb +10 -2
  44. data/lib/denko/digital_io/output.rb +1 -1
  45. data/lib/denko/display/hd44780.rb +18 -18
  46. data/lib/denko/led/seven_segment.rb +18 -19
  47. data/lib/denko/message.rb +6 -14
  48. data/lib/denko/one_wire/bus.rb +1 -1
  49. data/lib/denko/one_wire/{bus_enumeration.rb → bus_enumerator.rb} +16 -8
  50. data/lib/denko/one_wire/helper.rb +1 -1
  51. data/lib/denko/one_wire.rb +1 -1
  52. data/lib/denko/pulse_io/ir_transmitter.rb +1 -2
  53. data/lib/denko/sensor/ds18b20.rb +1 -1
  54. data/lib/denko/version.rb +1 -1
  55. data/lib/denko_cli/packages.rb +7 -1
  56. data/lib/denko_cli/targets.rb +8 -5
  57. data/lib/denko_cli/usage.txt +8 -4
  58. data/src/denko_ethernet.ino +15 -23
  59. data/src/denko_serial.ino +3 -14
  60. data/src/denko_wifi.ino +35 -50
  61. data/src/lib/Denko.cpp +23 -6
  62. data/src/lib/Denko.h +6 -16
  63. data/src/lib/DenkoCoreIO.cpp +3 -3
  64. data/src/lib/DenkoDefines.h +62 -16
  65. data/src/lib/DenkoEEPROM.cpp +9 -1
  66. data/src/lib/DenkoI2C.cpp +11 -9
  67. data/src/lib/DenkoLEDArray.cpp +1 -1
  68. data/target.yml +35 -1
  69. data/test/behaviors/reader_test.rb +8 -1
  70. data/test/board/helper_test.rb +0 -4
  71. data/test/display/hd44780_test.rb +10 -0
  72. data/test/led/seven_segment_test.rb +30 -8
  73. data/test/one_wire/bus_enumerator_test.rb +4 -0
  74. data/test/one_wire/helper_test.rb +5 -5
  75. data/test/sensor/ds18b20_test.rb +10 -0
  76. data/test/test_helper.rb +17 -2
  77. data/vendor/board-maps/.gitmodules +3 -0
  78. data/vendor/board-maps/BoardMap.h +40 -12
  79. data/vendor/board-maps/README.md +1 -0
  80. data/vendor/board-maps/lib/header_parser.rb +30 -5
  81. data/vendor/board-maps/run.rb +11 -1
  82. data/vendor/board-maps/yaml/ADAFRUIT_FEATHER_ESP32S3.yml +6 -1
  83. data/vendor/board-maps/yaml/ADAFRUIT_FEATHER_ESP32S3_NOPSRAM.yml +6 -1
  84. data/vendor/board-maps/yaml/ADAFRUIT_FEATHER_ESP32_V2.yml +5 -1
  85. data/vendor/board-maps/yaml/ADAFRUIT_QTPY_ESP32S3_N4R2.yml +20 -0
  86. data/vendor/board-maps/yaml/ADAFRUIT_QTPY_ESP32_PICO.yml +2 -1
  87. data/vendor/board-maps/yaml/ARTRONSHOP_RP2_NANO.yml +32 -0
  88. data/vendor/board-maps/yaml/AVR_CIRCUITPLAY.yml +1 -1
  89. data/vendor/board-maps/yaml/AVR_ESPLORA.yml +1 -1
  90. data/vendor/board-maps/yaml/AVR_INDUSTRIAL101.yml +1 -1
  91. data/vendor/board-maps/yaml/AVR_LEONARDO.yml +1 -1
  92. data/vendor/board-maps/yaml/AVR_LEONARDO_ETH.yml +1 -1
  93. data/vendor/board-maps/yaml/AVR_LILYPAD_USB.yml +1 -1
  94. data/vendor/board-maps/yaml/AVR_LININO_ONE.yml +1 -1
  95. data/vendor/board-maps/yaml/AVR_MICRO.yml +1 -1
  96. data/vendor/board-maps/yaml/AVR_ROBOT_CONTROL.yml +1 -1
  97. data/vendor/board-maps/yaml/AVR_ROBOT_MOTOR.yml +1 -1
  98. data/vendor/board-maps/yaml/AVR_YUN.yml +1 -1
  99. data/vendor/board-maps/yaml/AVR_YUNMINI.yml +1 -1
  100. data/vendor/board-maps/yaml/BPI_LEAF_S3.yml +11 -1
  101. data/vendor/board-maps/yaml/BeeMotionS3.yml +6 -1
  102. data/vendor/board-maps/yaml/Bee_Motion.yml +3 -0
  103. data/vendor/board-maps/yaml/Bee_S3.yml +1 -1
  104. data/vendor/board-maps/yaml/CHALLENGER_2040_WIFI6_BLE_RP2040.yml +42 -0
  105. data/vendor/board-maps/yaml/CYTRON_MAKER_FEATHER_AIOT_S3.yml +4 -1
  106. data/vendor/board-maps/yaml/CoreESP32.yml +5 -1
  107. data/vendor/board-maps/yaml/D1_MINI32.yml +10 -1
  108. data/vendor/board-maps/yaml/DENKY.yml +10 -1
  109. data/vendor/board-maps/yaml/DENKY_PICOV3.yml +10 -1
  110. data/vendor/board-maps/yaml/DENKY_WROOM32.yml +10 -1
  111. data/vendor/board-maps/yaml/DFROBOT_FIREBEETLE_2_ESP32E.yml +6 -1
  112. data/vendor/board-maps/yaml/DPU_ESP32.yml +10 -1
  113. data/vendor/board-maps/yaml/D_Duino_32.yml +9 -1
  114. data/vendor/board-maps/yaml/ESP32S2_DEV.yml +11 -1
  115. data/vendor/board-maps/yaml/ESP32S2_THING_PLUS.yml +11 -1
  116. data/vendor/board-maps/yaml/ESP32S2_USB.yml +11 -1
  117. data/vendor/board-maps/yaml/ESP32_DEV.yml +10 -1
  118. data/vendor/board-maps/yaml/ESP32_DEVKIT_LIPO.yml +10 -1
  119. data/vendor/board-maps/yaml/ESP32_IOT_REDBOARD.yml +10 -1
  120. data/vendor/board-maps/yaml/ESP32_PICO.yml +10 -1
  121. data/vendor/board-maps/yaml/ESP32_S3_BOX.yml +4 -1
  122. data/vendor/board-maps/yaml/ESP32_THING.yml +10 -1
  123. data/vendor/board-maps/yaml/ESP32_THING_PLUS.yml +4 -1
  124. data/vendor/board-maps/yaml/ESP32_THING_PLUS_C.yml +4 -1
  125. data/vendor/board-maps/yaml/ESP32_WROOM_DA.yml +10 -1
  126. data/vendor/board-maps/yaml/ESP32_WROVER_KIT.yml +10 -1
  127. data/vendor/board-maps/yaml/ESPECTRO32.yml +10 -1
  128. data/vendor/board-maps/yaml/ESPea32.yml +10 -1
  129. data/vendor/board-maps/yaml/ESPino32.yml +10 -1
  130. data/vendor/board-maps/yaml/FEATHERS2.yml +11 -1
  131. data/vendor/board-maps/yaml/FEATHERS2NEO.yml +2 -1
  132. data/vendor/board-maps/yaml/FEATHERS3.yml +3 -0
  133. data/vendor/board-maps/yaml/FEATHER_ESP32.yml +5 -1
  134. data/vendor/board-maps/yaml/FRANZININHO_WIFI.yml +11 -1
  135. data/vendor/board-maps/yaml/FRANZININHO_WIFI_MSC.yml +11 -1
  136. data/vendor/board-maps/yaml/FROG_ESP32.yml +10 -1
  137. data/vendor/board-maps/yaml/HEALTHYPI_4.yml +10 -1
  138. data/vendor/board-maps/yaml/HONEYLEMON.yml +10 -1
  139. data/vendor/board-maps/yaml/HORNBILL_ESP32_DEV.yml +10 -1
  140. data/vendor/board-maps/yaml/HORNBILL_ESP32_MINIMA.yml +4 -1
  141. data/vendor/board-maps/yaml/IMBRIOS_LOGSENS_V1P1.yml +5 -1
  142. data/vendor/board-maps/yaml/LILYGO_T_DISPLAY_S3.yml +7 -1
  143. data/vendor/board-maps/yaml/LOLIN32.yml +10 -1
  144. data/vendor/board-maps/yaml/LOLIN32_LITE.yml +10 -1
  145. data/vendor/board-maps/yaml/LOLIN_D32.yml +10 -1
  146. data/vendor/board-maps/yaml/LOLIN_D32_PRO.yml +10 -1
  147. data/vendor/board-maps/yaml/LOLIN_S2_MINI.yml +11 -1
  148. data/vendor/board-maps/yaml/LOLIN_S2_PICO.yml +11 -1
  149. data/vendor/board-maps/yaml/LOLIN_S3.yml +9 -1
  150. data/vendor/board-maps/yaml/LOLIN_S3_MINI.yml +9 -1
  151. data/vendor/board-maps/yaml/LOLIN_S3_PRO.yml +9 -1
  152. data/vendor/board-maps/yaml/LoPy.yml +11 -1
  153. data/vendor/board-maps/yaml/LoPy4.yml +11 -1
  154. data/vendor/board-maps/yaml/MAGTAG29_ESP32S2.yml +11 -1
  155. data/vendor/board-maps/yaml/METRO_ESP32S2.yml +11 -1
  156. data/vendor/board-maps/yaml/MGBOT_IOTIK32A.yml +10 -1
  157. data/vendor/board-maps/yaml/MGBOT_IOTIK32B.yml +10 -1
  158. data/vendor/board-maps/yaml/MH_ET_LIVE_ESP32DEVKIT.yml +10 -1
  159. data/vendor/board-maps/yaml/MH_ET_LIVE_ESP32MINIKIT.yml +10 -1
  160. data/vendor/board-maps/yaml/MICROS2.yml +11 -1
  161. data/vendor/board-maps/yaml/MINIMA.yml +15 -0
  162. data/vendor/board-maps/yaml/NANO32.yml +10 -1
  163. data/vendor/board-maps/yaml/Node32s.yml +10 -1
  164. data/vendor/board-maps/yaml/NodeMCU_32S.yml +10 -1
  165. data/vendor/board-maps/yaml/ONEHORSE_ESP32_DEV.yml +11 -1
  166. data/vendor/board-maps/yaml/PIMORONI_PLASMA2040.yml +29 -0
  167. data/vendor/board-maps/yaml/PORTENTA_C33.yml +28 -0
  168. data/vendor/board-maps/yaml/PROS3.yml +6 -1
  169. data/vendor/board-maps/yaml/PYCOM_GPY.yml +11 -1
  170. data/vendor/board-maps/yaml/Piranha.yml +7 -1
  171. data/vendor/board-maps/yaml/Pocket32.yml +10 -1
  172. data/vendor/board-maps/yaml/QUANTUM.yml +10 -1
  173. data/vendor/board-maps/yaml/REDPILL_ESP32S3.yml +11 -1
  174. data/vendor/board-maps/yaml/RMP.yml +11 -1
  175. data/vendor/board-maps/yaml/SAMD_CIRCUITPLAYGROUND_EXPRESS.yml +0 -1
  176. data/vendor/board-maps/yaml/SAM_DUE.yml +3 -1
  177. data/vendor/board-maps/yaml/SONOFF_DUALR3.yml +10 -1
  178. data/vendor/board-maps/yaml/TAMC_TERMOD_S3.yml +11 -1
  179. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1262.yml +6 -1
  180. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1268.yml +6 -1
  181. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1276.yml +6 -1
  182. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1278.yml +6 -1
  183. data/vendor/board-maps/yaml/TBEAM_USE_RADIO_SX1280.yml +6 -1
  184. data/vendor/board-maps/yaml/TBeam.yml +6 -1
  185. data/vendor/board-maps/yaml/TINYPICO.yml +10 -1
  186. data/vendor/board-maps/yaml/TINYS2.yml +11 -1
  187. data/vendor/board-maps/yaml/TTGO_LoRa32_V1.yml +11 -1
  188. data/vendor/board-maps/yaml/TTGO_LoRa32_V2.yml +11 -1
  189. data/vendor/board-maps/yaml/TTGO_LoRa32_v21new.yml +11 -1
  190. data/vendor/board-maps/yaml/TTGO_T1.yml +10 -1
  191. data/vendor/board-maps/yaml/TTGO_T7_V13_Mini32.yml +10 -1
  192. data/vendor/board-maps/yaml/TTGO_T7_V14_Mini32.yml +10 -1
  193. data/vendor/board-maps/yaml/TWATCH_2020_V1.yml +0 -1
  194. data/vendor/board-maps/yaml/TWATCH_2020_V2.yml +0 -1
  195. data/vendor/board-maps/yaml/TWATCH_2020_V3.yml +0 -1
  196. data/vendor/board-maps/yaml/TWATCH_BASE.yml +0 -1
  197. data/vendor/board-maps/yaml/TWatch.yml +0 -1
  198. data/vendor/board-maps/yaml/UBLOX_NINA_W10.yml +10 -1
  199. data/vendor/board-maps/yaml/UNOWIFIR4.yml +17 -0
  200. data/vendor/board-maps/yaml/WIPY3.yml +11 -1
  201. data/vendor/board-maps/yaml/XIAO_ESP32S3.yml +2 -1
  202. data/vendor/board-maps/yaml/connaxio_espoir.yml +7 -1
  203. data/vendor/board-maps/yaml/esp32vn_iot_uno.yml +10 -1
  204. data/vendor/board-maps/yaml/heltec_wifi_32_lora_V3.yml +11 -1
  205. data/vendor/board-maps/yaml/heltec_wifi_kit_32.yml +11 -1
  206. data/vendor/board-maps/yaml/heltec_wifi_kit_32_V3.yml +11 -1
  207. data/vendor/board-maps/yaml/heltec_wifi_lora_32.yml +10 -1
  208. data/vendor/board-maps/yaml/heltec_wifi_lora_32_V2.yml +10 -1
  209. data/vendor/board-maps/yaml/heltec_wireless_stick.yml +10 -1
  210. data/vendor/board-maps/yaml/heltec_wireless_stick_LITE.yml +10 -1
  211. data/vendor/board-maps/yaml/openkb.yml +11 -1
  212. data/vendor/board-maps/yaml/roboheart_hercules.yml +10 -1
  213. data/vendor/board-maps/yaml/sensesiot_weizen.yml +10 -1
  214. data/vendor/board-maps/yaml/uPesy_WROOM.yml +10 -1
  215. data/vendor/board-maps/yaml/uPesy_WROVER.yml +10 -1
  216. data/vendor/board-maps/yaml/unphone8.yml +11 -1
  217. data/vendor/board-maps/yaml/unphone9.yml +11 -1
  218. metadata +15 -3
@@ -14,12 +14,12 @@ bus = Denko::SPI::Bus.new(board: board)
14
14
  # bus = Denko::SPI::BitBang.new(board: board, pins: SPI_BIT_BANG_PINS)
15
15
 
16
16
  # Connect chip select/enable pin of the ADS1118 to pin 9.
17
- ads1118 = Denko::AnalogIO::ADS1118.new(bus: bus, pin: 9)
17
+ ads = Denko::AnalogIO::ADS1118.new(bus: bus, pin: 9)
18
18
 
19
19
  # Helper method so readings look nice.
20
20
  def print_reading(name, raw, voltage)
21
21
  print "#{Time.now.strftime '%Y-%m-%d %H:%M:%S'} - "
22
- print "#{name.rjust(12, " ")} | "
22
+ print "#{name.rjust(18, " ")} | "
23
23
  print "Raw: #{raw.to_s.rjust(6, " ")} | "
24
24
  print "Voltage: "
25
25
  print ("%.10f" % voltage).rjust(13, " ")
@@ -30,7 +30,7 @@ end
30
30
  # Read the ADS1118 internal temperature sensor.
31
31
  # This always uses the 128 SPS mode, and there is no polling method for it.
32
32
  #
33
- temperature = ads1118.temperature_read
33
+ temperature = ads.temperature_read
34
34
  puts "ADS1118 Temperature: #{temperature} \xC2\xB0C"
35
35
  puts
36
36
 
@@ -41,7 +41,7 @@ puts
41
41
  #
42
42
  # Note: This is the only way to use continuous mode. Subcomponents always use one-shot.
43
43
  #
44
- ads1118.read([0b10000001, 0b10001011]) do |reading|
44
+ ads.read([0b10000001, 0b10001011]) do |reading|
45
45
  voltage = reading * 0.0001875
46
46
  print_reading("Direct", reading, voltage)
47
47
  end
@@ -49,26 +49,25 @@ end
49
49
  #
50
50
  # Or use its BoardProxy interface, adding subcomponents as if it were a Board.
51
51
  # The key adc: can substitute for board: when intializing AnalogIO::Input.
52
- #
53
52
  # Gain and sample rate bitmasks can be found in the datasheet.
54
53
  #
55
54
  # Input on pin 0, with pin 1 as differential negative input, and 6.144 V full range.
56
- diff_input = Denko::AnalogIO::Input.new(adc: ads1118, pin: 0, negative_pin: 1, gain: 0b000)
55
+ diff_input = Denko::AnalogIO::Input.new(adc: ads, pin: 0, negative_pin: 1, gain: 0b000)
57
56
 
58
57
  # Input on pin 2 with no negative input (single ended), and 1.024V full range.
59
58
  # Ths one uses a 8 SPS rate, essentially 16x oversampling compared to the default 128.
60
- single_input = Denko::AnalogIO::Input.new(adc: ads1118, pin: 2, gain: 0b011, sample_rate: 0b000)
59
+ single_input = Denko::AnalogIO::Input.new(adc: ads, pin: 2, gain: 0b011, sample_rate: 0b000)
61
60
 
62
61
  # Poll the differential input every second.
63
62
  diff_input.poll(1) do |reading|
64
63
  voltage = reading * diff_input.volts_per_bit
65
- print_reading("Differential", reading, voltage)
64
+ print_reading("Differential A1-A0", reading, voltage)
66
65
  end
67
66
 
68
67
  # Poll the single ended input every 2 seconds.
69
68
  single_input.poll(2) do |reading|
70
69
  voltage = reading * single_input.volts_per_bit
71
- print_reading("Single", reading, voltage)
70
+ print_reading("Single A2-GN", reading, voltage)
72
71
  end
73
72
 
74
73
  sleep
@@ -5,13 +5,15 @@ require 'bundler/setup'
5
5
  require 'denko'
6
6
 
7
7
  #
8
- # For the Arduino Zero: 'DAC0' = 'A0' = GPIO14.
9
- # For the ESP32 V1: 'DAC0' = GPIO25, 'DAC1' = GPIO26, `ADC1_4` = 32
8
+ # Arduino Zero: :DAC0 is :A0 is GPIO14
9
+ # Arduino UNO R4: :DAC is :A0 is GPIO14
10
+ # ESP32 V1: :DAC0 is GPIO25, :DAC1 is GPIO26, :A4 is GPIO32
11
+ # ESP32-S2: :DAC0 is GPIO17, :DAC1 is GPIO18, :A4 is GPIO5
10
12
  #
11
13
  # Connect DAC_PIN TO ADC_PIN with a jumper to test.
12
14
  #
13
- DAC_PIN = 'DAC0'
14
- ADC_PIN = 'A5'
15
+ DAC_PIN = :DAC0
16
+ ADC_PIN = :A4
15
17
 
16
18
  board = Denko::Board.new(Denko::Connection::Serial.new)
17
19
  dac = Denko::AnalogIO::Output.new(pin: DAC_PIN, board: board)
@@ -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
@@ -5,7 +5,7 @@ require 'bundler/setup'
5
5
  require 'denko'
6
6
 
7
7
  board = Denko::Board.new(Denko::Connection::Serial.new)
8
- bus = Denko::I2C::Bus.new(board: board, pin: :SDA0)
8
+ bus = Denko::I2C::Bus.new(board: board, pin: :SDA)
9
9
  aht20 = Denko::Sensor::AHT20.new(bus: bus)
10
10
 
11
11
  aht20.poll(2) do |reading|
@@ -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
@@ -4,7 +4,7 @@ module Denko
4
4
  include Denko::Behaviors::BusPeripheral
5
5
 
6
6
  def before_initialize(options={})
7
- # Aallow @address override in options, even if peripheral sets default.
7
+ # Allow @address override in options, even if peripheral sets a default.
8
8
  @address = options[:address] if options[:address]
9
9
 
10
10
  raise ArgumentError, "missing address for #{self}. Try Bus#search first" unless @address
@@ -33,7 +33,7 @@ module Denko
33
33
  board.remove_component(self)
34
34
  end
35
35
 
36
- # Setup::Base only requires a board.
36
+ # Behaviors::Component only requires a board.
37
37
  # Include modules from Setup or override this to use pins.
38
38
  #
39
39
  def before_initialize(options={}); end
@@ -12,9 +12,12 @@ module Denko
12
12
  def initialize_pins(options={})
13
13
  super(options)
14
14
 
15
+ # Assume input direction, and look for pull mode in options.
15
16
  initial_mode = :input
16
17
  initial_mode = :input_pullup if options[:pullup]
17
18
  initial_mode = :input_pulldown if options[:pulldown]
19
+
20
+ # If user was explicit about mode, just use that.
18
21
  initial_mode = options[:mode] if options[:mode]
19
22
 
20
23
  self.mode = initial_mode