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
@@ -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
@@ -11,15 +11,13 @@ module Denko
11
11
 
12
12
  protected
13
13
 
14
- attr_writer :pin
15
-
16
14
  def convert_pins(options={})
17
15
  raise ArgumentError, 'a pin is required for this component' unless options[:pin]
18
16
  options[:pin] = board.convert_pin(options[:pin])
19
17
  end
20
18
 
21
19
  def initialize_pins(options={})
22
- self.pin = options[:pin]
20
+ @pin = options[:pin]
23
21
  end
24
22
  end
25
23
  end
@@ -2,6 +2,7 @@ module Denko
2
2
  module Behaviors
3
3
  module State
4
4
  def initialize(options={})
5
+ # Component includes State, so no need to call super here.
5
6
  @state_mutex = Mutex.new
6
7
  @state = nil
7
8
  end
@@ -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
data/lib/denko/board.rb CHANGED
@@ -1,42 +1,54 @@
1
1
  # Require all files in board folder relative to this file.
2
- Dir["#{Denko.root}/lib/denko/board/*.rb"].each {|file| require file }
2
+ Dir["#{Denko.root}/lib/denko/board/*.rb"].each { |file| require file }
3
3
 
4
4
  module Denko
5
5
  class Board
6
- attr_reader :board_name, :version, :aux_limit, :eeprom_length
6
+ attr_reader :name, :version, :serial_buffer_size, :aux_limit, :eeprom_length
7
7
  attr_reader :low, :high, :analog_write_high, :analog_read_high
8
8
 
9
- def initialize(io, options={})
10
- # Connect the IO, and get the ACK.
11
- @io = io
12
- ack = io.handshake
13
- @name, @version, @aux_limit, @eeprom_length = ack.split(",")
9
+ def initialize(transport, options={})
10
+ # Shake hands
11
+ @transport = transport
12
+ ack = transport.handshake
14
13
 
15
- # Parse map, version and eeprom_legnth.
16
- @name = nil if @name.empty?
17
- @version = nil if @version.empty?
18
- @eeprom_length = @eeprom_length.to_i
14
+ # Split handshake acknowledgement into separate values.
15
+ @name, @version, @serial_buffer_size, @aux_limit, @eeprom_length, @i2c_limit = ack.split(",")
16
+
17
+ # Tell transport how much serial buffer the board has, for flow control.
18
+ @serial_buffer_size = @serial_buffer_size.to_i
19
+ raise StandardError, "no serial buffer size given in handshake" if @serial_buffer_size < 1
20
+ @transport.remote_buffer_size = @serial_buffer_size
21
+
22
+ # Load board map by name.
23
+ @name = nil if @name.empty?
24
+ load_map(@name)
19
25
 
20
26
  # Leave room for null termination of aux messages.
21
27
  @aux_limit = @aux_limit.to_i - 1
22
28
 
23
- # Load the board map.
24
- @map = load_map(@name)
29
+ # Set I2C transaction size limit. Safe minimum is 32.
30
+ # This makes I2C fail silently if board does not implement.
31
+ @i2c_limit = @i2c_limit.to_i
32
+ @i2c_limit = 32 if @i2c_limit == 0
33
+
34
+ # Remaining settings
35
+ @version = nil if @version.empty?
36
+ @eeprom_length = @eeprom_length.to_i
25
37
 
26
- # Allow the IO to call #update on the board when messages received.
27
- io.add_observer(self)
38
+ # Transport calls #update on board when data is received.
39
+ transport.add_observer(self)
28
40
 
29
41
  # Set digital and analog IO levels.
30
42
  @low = 0
31
43
  @high = 1
32
44
  self.analog_write_resolution = options[:write_bits] || 8
33
- self.analog_read_resolution = options[:read_bits] || 10
45
+ self.analog_read_resolution = options[:read_bits] || 10
34
46
  end
35
47
 
36
48
  def finish_write
37
- sleep 0.001 while @io.writing?
49
+ sleep 0.001 while @transport.writing?
38
50
  write "\n91\n"
39
- sleep 0.001 while @io.writing?
51
+ sleep 0.001 while @transport.writing?
40
52
  end
41
53
 
42
54
  def analog_write_resolution=(value)
@@ -64,7 +76,7 @@ module Denko
64
76
  alias :adc_high :analog_read_high
65
77
 
66
78
  def write(msg)
67
- @io.write(msg)
79
+ @transport.write(msg)
68
80
  end
69
81
 
70
82
  #
@@ -78,7 +90,7 @@ module Denko
78
90
  # signal is read by the TxRx, telling it to resume transmisison.
79
91
  #
80
92
  def write_and_halt(msg)
81
- @io.write(msg, true)
93
+ @transport.write(msg, true)
82
94
  end
83
95
 
84
96
  #
@@ -1,11 +1,11 @@
1
1
  module Denko
2
2
  module Connection
3
3
  class BoardUART < Base
4
- BAUD = 115200
4
+ DEFAULT_BAUD = 115200
5
5
 
6
- def initialize(uart, options={})
6
+ def initialize(uart, baud: DEFAULT_BAUD)
7
7
  @uart = uart
8
- @uart.start(options[:baud] || BAUD)
8
+ @uart.start(baud)
9
9
  end
10
10
 
11
11
  def baud
@@ -1,11 +1,19 @@
1
1
  module Denko
2
2
  module Connection
3
3
  module FlowControl
4
- BOARD_BUFFER = 63
5
4
  SLEEP_TIME = 0.001
6
5
 
6
+ # Let Board object tell us the remote buffer size after parsing handshake.
7
+ def remote_buffer_size=(size)
8
+ @transit_mutex.synchronize { @remote_buffer_size = size }
9
+ end
10
+
7
11
  def initialize(*args)
8
12
  super(*args)
13
+ # Start with minimum known buffer size. Board will update after handshake.
14
+ # WARNING: If not updated, and ack threshold on the board is > minimum,
15
+ # FlowControl will stop sending data, and appear to hang. Fix this.
16
+ @remote_buffer_size = 63
9
17
  reset_flow_control
10
18
  tx_resume
11
19
  end
@@ -93,7 +101,7 @@ module Denko
93
101
  # Keep transit mutex as short as possible, by only reserving bytes, and writing outside.
94
102
  def reserve_bytes(length)
95
103
  @transit_mutex.synchronize do
96
- available = BOARD_BUFFER - @transit_bytes
104
+ available = @remote_buffer_size - @transit_bytes
97
105
  reserved = (length > available) ? available : length
98
106
  @transit_bytes += reserved
99
107
  reserved
@@ -16,7 +16,7 @@ module Denko
16
16
  end
17
17
 
18
18
  def digital_write(value)
19
- board.digital_write(pin, value)
19
+ @board.digital_write(@pin, value)
20
20
  self.state = value
21
21
  end
22
22
 
@@ -63,7 +63,7 @@ module Denko
63
63
  end
64
64
 
65
65
  def after_initialize(options={})
66
- super(options) if defined?(super)
66
+ super(options)
67
67
 
68
68
  # Default to 16x2 display if no options given.
69
69
  @columns = options[:columns] || 16
@@ -212,7 +212,7 @@ module Denko
212
212
  send(byte, board.low)
213
213
  end
214
214
 
215
- def write(byte);
215
+ def write(byte)
216
216
  send(byte, board.high)
217
217
  end
218
218
 
@@ -229,27 +229,27 @@ module Denko
229
229
  end
230
230
 
231
231
  def write4(bits)
232
- d4.write bits[4]
233
- d5.write bits[5]
234
- d6.write bits[6]
235
- d7.write bits[7]
232
+ d4.write bits[4].to_i
233
+ d5.write bits[5].to_i
234
+ d6.write bits[6].to_i
235
+ d7.write bits[7].to_i
236
236
  pulse_enable
237
- d4.write bits[0]
238
- d5.write bits[1]
239
- d6.write bits[2]
240
- d7.write bits[3]
237
+ d4.write bits[0].to_i
238
+ d5.write bits[1].to_i
239
+ d6.write bits[2].to_i
240
+ d7.write bits[3].to_i
241
241
  pulse_enable
242
242
  end
243
243
 
244
244
  def write8(bits)
245
- d0.write bits[0]
246
- d1.write bits[1]
247
- d2.write bits[2]
248
- d3.write bits[3]
249
- d4.write bits[4]
250
- d5.write bits[5]
251
- d6.write bits[6]
252
- d7.write bits[7]
245
+ d0.write bits[0].to_i
246
+ d1.write bits[1].to_i
247
+ d2.write bits[2].to_i
248
+ d3.write bits[3].to_i
249
+ d4.write bits[4].to_i
250
+ d5.write bits[5].to_i
251
+ d6.write bits[6].to_i
252
+ d7.write bits[7].to_i
253
253
  pulse_enable
254
254
  end
255
255
 
@@ -3,6 +3,9 @@ module Denko
3
3
  class SevenSegment
4
4
  include Behaviors::MultiPin
5
5
 
6
+ ALL_OFF = [0,0,0,0,0,0,0]
7
+ BLANK = " "
8
+
6
9
  def initialize_pins(options={})
7
10
  [:a, :b, :c, :d, :e, :f, :g].each do |symbol|
8
11
  proxy_pin(symbol, DigitalIO::Output)
@@ -20,28 +23,30 @@ module Denko
20
23
  attr_reader :segments
21
24
 
22
25
  def clear
23
- segments.each do |pin|
24
- pin.low if cathode
25
- pin.high if anode
26
- end
26
+ write(BLANK)
27
27
  end
28
28
 
29
- def display(char)
30
- char = char.to_s
31
- return scroll(char) if char.length > 1
32
- off; write(char); on
29
+ def display(string)
30
+ on unless on?
31
+ string = string.to_s.upcase
32
+ (string.length > 1) ? scroll(string) : write(string)
33
33
  end
34
34
 
35
35
  def on
36
36
  anode.high if anode
37
37
  cathode.low if cathode
38
+ @on = true
38
39
  end
39
40
 
40
41
  def off
41
42
  anode.low if anode
42
43
  cathode.high if cathode
44
+ @on = false
43
45
  end
44
46
 
47
+ def on?; @on; end
48
+ def off?; !@on; end
49
+
45
50
  CHARACTERS = {
46
51
  '0' => [1,1,1,1,1,1,0],
47
52
  '1' => [0,1,1,0,0,0,0],
@@ -87,22 +92,16 @@ module Denko
87
92
  private
88
93
 
89
94
  def write(char)
90
- bits = CHARACTERS[char.to_s.upcase]
91
- unless bits
92
- clear
93
- else
94
- bits.each_with_index do |bit, index|
95
- if anode
96
- bit == 0 ? bit = 1 : bit = 0
97
- end
98
- segments[index].write(bit) unless (segments[index].state == bit)
99
- end
95
+ bits = CHARACTERS[char] || ALL_OFF
96
+ bits.each_with_index do |bit, index|
97
+ bit = 1^bit if anode
98
+ segments[index].write(bit) unless (segments[index].state == bit)
100
99
  end
101
100
  end
102
101
 
103
102
  def scroll(string)
104
103
  string.chars.each do |char|
105
- display(char)
104
+ write(char)
106
105
  sleep(0.5)
107
106
  end
108
107
  end
data/lib/denko/message.rb CHANGED
@@ -57,7 +57,7 @@ module Denko
57
57
  message = "#{command}#{message}\n"
58
58
  end
59
59
 
60
- def self.pack(type, data, options={})
60
+ def self.pack(type, data, min: nil, max: nil)
61
61
  # Always pack as little endian.
62
62
  template = case type
63
63
  when :uint64 then 'Q<*'
@@ -70,20 +70,12 @@ module Denko
70
70
  # Can pass a single integer to get packed if we always [] then flatten.
71
71
  str = [data].flatten.pack(template)
72
72
 
73
- # Pad right with null bytes if asked.
74
- if options[:pad] && options[:pad] > str.length
75
- (options[:pad] - str.length).times do
76
- str = str + "\x00"
77
- end
78
- end
79
-
80
- if options[:min] && str.length < options[:min]
81
- raise ArgumentError, "too few bytes given (expected at least #{options[:min]})"
73
+ # Enforce min and max.
74
+ if min && str.length < min
75
+ raise ArgumentError, "too few bytes given (expected at least #{min})"
82
76
  end
83
-
84
- # Max should probably always be set to avoid overruning aux message RAM.
85
- if options[:max] && str.length > options[:max]
86
- raise ArgumentError, "too many bytes given (expected at most #{options[:max]})"
77
+ if max && str.length > max
78
+ raise ArgumentError, "too many bytes given (expected at most #{max})"
87
79
  end
88
80
 
89
81
  str
@@ -4,7 +4,7 @@ module Denko
4
4
  include Behaviors::SinglePin
5
5
  include Behaviors::BusControllerAddressed
6
6
  include Behaviors::Reader
7
- include BusEnumeration
7
+ include BusEnumerator
8
8
  include Constants
9
9
 
10
10
  attr_reader :parasite_power
@@ -1,6 +1,8 @@
1
1
  module Denko
2
2
  module OneWire
3
- module BusEnumeration
3
+ module BusEnumerator
4
+ include Constants
5
+
4
6
  def _search(branch_mask)
5
7
  reset
6
8
  write(SEARCH_ROM)
@@ -42,12 +44,12 @@ module Denko
42
44
  def parse_search_result(result)
43
45
  address, complement = split_search_result(result)
44
46
 
45
- raise "CRC error during OneWire search" unless Helper.crc_check(address)
46
-
47
47
  if (address & complement) > 0
48
48
  raise "OneWire device not connected or disconnected during search"
49
49
  end
50
50
 
51
+ raise "CRC error during OneWire search" unless Helper.crc(address)
52
+
51
53
  # Gives 0 at every discrepancy we didn't write 1 for on this search.
52
54
  new_discrepancies = address ^ complement
53
55
 
@@ -73,12 +75,18 @@ module Denko
73
75
  [address, complement]
74
76
  end
75
77
 
76
- # Set FAMILY_CODE in peripheral class to get it identified during search.
78
+ #
79
+ # Set FAMILY_CODE in peripheral class, and add the class to this array
80
+ # for the class to be identified during search.
81
+ #
82
+ PERIPHERAL_CLASSES = [
83
+ Sensor::DS18B20,
84
+ ]
85
+
77
86
  def family_lookup(family_code)
78
- OneWire.constants.each do |const|
79
- obj = OneWire.const_get(const)
80
- if (obj.is_a? Class) && (obj.const_defined? "FAMILY_CODE")
81
- return obj if obj::FAMILY_CODE == family_code
87
+ PERIPHERAL_CLASSES.each do |klass|
88
+ if (klass.const_defined? "FAMILY_CODE")
89
+ return klass if klass::FAMILY_CODE == family_code
82
90
  end
83
91
  end
84
92
  return nil
@@ -5,7 +5,7 @@ module Denko
5
5
  [address].pack('Q<').split("").map(&:ord)
6
6
  end
7
7
 
8
- def self.crc_check(data)
8
+ def self.crc(data)
9
9
  calculated, received = self.calculate_crc(data)
10
10
  calculated == received
11
11
  end
@@ -2,7 +2,7 @@ module Denko
2
2
  module OneWire
3
3
  autoload :Constants, "#{__dir__}/one_wire/constants"
4
4
  autoload :Helper, "#{__dir__}/one_wire/helper"
5
- autoload :BusEnumeration, "#{__dir__}/one_wire/bus_enumeration"
5
+ autoload :BusEnumerator, "#{__dir__}/one_wire/bus_enumerator"
6
6
  autoload :Bus, "#{__dir__}/one_wire/bus"
7
7
  autoload :Peripheral, "#{__dir__}/one_wire/peripheral"
8
8
  end
@@ -3,7 +3,7 @@ module Denko
3
3
  class IRTransmitter
4
4
  include Behaviors::OutputPin
5
5
 
6
- def emit(pulses=[], options={})
6
+ def emit(pulses=[], frequency: 38)
7
7
  if pulses.length > 256 || pulses.length < 1
8
8
  raise ArgumentError, 'wrong number of IR pulses (expected 1 to 256)'
9
9
  end
@@ -14,7 +14,6 @@ module Denko
14
14
  raise ArgumentError, 'pulse too long (max 65535 ms)' if pulse > 65535
15
15
  end
16
16
 
17
- frequency = options[:frequency] || 38
18
17
  board.infrared_emit(pin, frequency, pulses)
19
18
  end
20
19
  end
@@ -47,7 +47,7 @@ module Denko
47
47
  end
48
48
 
49
49
  def pre_callback_filter(bytes)
50
- return { crc_error: true } unless Helper.crc_check(bytes)
50
+ return { crc_error: true } unless OneWire::Helper.crc(bytes)
51
51
  @resolution = decode_resolution(bytes)
52
52
 
53
53
  decode_temperature(bytes).merge(raw: bytes)
data/lib/denko/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Denko
2
- VERSION = "0.13.0"
2
+ VERSION = "0.13.2"
3
3
  end
@@ -12,10 +12,16 @@ PACKAGES = {
12
12
  "Denko.cpp",
13
13
  "DenkoCoreIO.cpp",
14
14
  "DenkoPulseInput.cpp",
15
- "DenkoEEPROM.cpp",
16
15
  "../../vendor/board-maps/BoardMap.h",
17
16
  ]
18
17
  },
18
+ eeprom: {
19
+ description: "Built-in EEPROM support",
20
+ directive: "DENKO_EEPROM",
21
+ files: [
22
+ "DenkoEEPROM.cpp",
23
+ ]
24
+ },
19
25
  one_wire: {
20
26
  description: "OneWire bus support",
21
27
  directive: "DENKO_ONE_WIRE",
@@ -11,14 +11,17 @@ class DenkoCLI::Generator
11
11
  mega168: [:core, :one_wire, :tone, :i2c, :spi, :servo],
12
12
 
13
13
  # Other ATmega chips do everything.
14
- # Add bit bang serial for 328p / UNO since ith as no extra hardware UART.
14
+ # Add bit bang serial for 328p / UNO since it has no extra hardware UART.
15
15
  mega: STANDARD_PACKAGES + [:uart_bb],
16
16
 
17
- # No tone or IR support on SAM3X / Due.
18
- sam3x: STANDARD_PACKAGES - [:tone, :ir_out],
17
+ # No tone, infrared or EEPROM on SAM3X / Due.
18
+ sam3x: STANDARD_PACKAGES - [:tone, :ir_out, :eeprom],
19
19
 
20
- # SAMD includes all standard packages.
21
- samd: STANDARD_PACKAGES,
20
+ # No EEPROM on SAMD / Zero.
21
+ samd: STANDARD_PACKAGES - [:eeprom],
22
+
23
+ # No IR out and WS2812 on the UNO R4. WS2812 compiles but doesn't work.
24
+ ra4m1: STANDARD_PACKAGES - [:ir_out, :led_array],
22
25
 
23
26
  # ESP8266 + ESP32 use a different IR library.
24
27
  esp8266: STANDARD_PACKAGES - [:ir_out] + [:ir_out_esp],