denko 0.13.0 → 0.13.2

Sign up to get free protection for your applications and to get access to all the features.
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