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
@@ -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],