denko 0.14.0 → 0.15.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/build_atmega_avr.yml +2 -1
- data/.github/workflows/build_atmega_megaavr.yml +2 -1
- data/.github/workflows/build_atsam3x.yml +1 -0
- data/.github/workflows/build_atsamd21.yml +2 -1
- data/.github/workflows/build_esp32.yml +4 -2
- data/.github/workflows/build_esp32c3.yml +4 -3
- data/.github/workflows/build_esp32c6.yml +4 -2
- data/.github/workflows/build_esp32h2.yml +4 -2
- data/.github/workflows/build_esp32s2.yml +4 -2
- data/.github/workflows/build_esp32s3.yml +4 -2
- data/.github/workflows/build_esp8266.yml +2 -1
- data/.github/workflows/build_ra4m1.yml +1 -0
- data/.github/workflows/build_rp2040.yml +4 -3
- data/.github/workflows/ruby.yml +1 -1
- data/CHANGELOG.md +203 -0
- data/DEPS_CLI.md +16 -16
- data/DEPS_IDE.md +31 -30
- data/MICROCONTROLLERS.md +103 -0
- data/PERIPHERALS.md +178 -0
- data/README.md +28 -21
- data/denko.gemspec +6 -1
- data/lib/denko/analog_io/ads1118.rb +5 -5
- data/lib/denko/analog_io/ads111x.rb +23 -19
- data/lib/denko/analog_io/joystick.rb +87 -0
- data/lib/denko/analog_io/potentiometer.rb +1 -5
- data/lib/denko/analog_io.rb +22 -8
- data/lib/denko/behaviors/bus_controller.rb +2 -1
- data/lib/denko/behaviors/bus_peripheral.rb +1 -1
- data/lib/denko/behaviors/callbacks.rb +18 -16
- data/lib/denko/behaviors/component.rb +0 -4
- data/lib/denko/behaviors/lifecycle.rb +1 -1
- data/lib/denko/behaviors/listener.rb +9 -3
- data/lib/denko/behaviors/multi_pin.rb +4 -6
- data/lib/denko/behaviors/poller.rb +11 -2
- data/lib/denko/behaviors/reader.rb +109 -21
- data/lib/denko/behaviors/single_pin.rb +2 -4
- data/lib/denko/behaviors/state.rb +18 -13
- data/lib/denko/behaviors/threaded.rb +19 -8
- data/lib/denko/behaviors.rb +36 -23
- data/lib/denko/board/eeprom.rb +1 -1
- data/lib/denko/board/i2c.rb +1 -1
- data/lib/denko/board/i2c_bit_bang.rb +9 -5
- data/lib/denko/board/map.rb +6 -2
- data/lib/denko/board/one_wire.rb +3 -3
- data/lib/denko/board/spi.rb +30 -30
- data/lib/denko/board/spi_bit_bang.rb +8 -11
- data/lib/denko/board.rb +6 -3
- data/lib/denko/connection/flow_control.rb +1 -1
- data/lib/denko/connection/serial.rb +5 -5
- data/lib/denko/digital_io/output.rb +12 -4
- data/lib/denko/digital_io/pcf8574.rb +114 -0
- data/lib/denko/digital_io/rotary_encoder.rb +10 -6
- data/lib/denko/digital_io.rb +24 -6
- data/lib/denko/display/canvas.rb +350 -157
- data/lib/denko/display/font/bmp_5x7.rb +142 -0
- data/lib/denko/display/font/bmp_6x8.rb +142 -0
- data/lib/denko/display/font/bmp_8x16.rb +141 -0
- data/lib/denko/display/font.rb +22 -0
- data/lib/denko/display/hd44780.rb +24 -20
- data/lib/denko/display/il0373.rb +186 -0
- data/lib/denko/display/mono_oled.rb +193 -0
- data/lib/denko/display/pcd8544.rb +154 -0
- data/lib/denko/display/pixel_common.rb +83 -0
- data/lib/denko/display/sh1106.rb +17 -21
- data/lib/denko/display/sh1107.rb +10 -0
- data/lib/denko/display/spi_common.rb +35 -0
- data/lib/denko/display/spi_epaper_common.rb +30 -0
- data/lib/denko/display/ssd1306.rb +6 -228
- data/lib/denko/display/ssd1680.rb +14 -0
- data/lib/denko/display/ssd1681.rb +8 -0
- data/lib/denko/display/ssd168x.rb +227 -0
- data/lib/denko/display/st7302.rb +207 -0
- data/lib/denko/display/st7565.rb +166 -0
- data/lib/denko/display.rb +40 -4
- data/lib/denko/eeprom/at24c.rb +67 -0
- data/lib/denko/eeprom/board.rb +69 -0
- data/lib/denko/eeprom.rb +15 -1
- data/lib/denko/helpers/engine_check.rb +13 -0
- data/lib/denko/{mutex_stub.rb → helpers/mutex_stub.rb} +6 -0
- data/lib/denko/helpers.rb +6 -0
- data/lib/denko/i2c/bit_bang.rb +1 -0
- data/lib/denko/i2c/bus_common.rb +9 -4
- data/lib/denko/i2c/peripheral.rb +5 -1
- data/lib/denko/i2c.rb +17 -4
- data/lib/denko/led/apa102.rb +1 -3
- data/lib/denko/led/base.rb +5 -0
- data/lib/denko/led/rgb.rb +16 -10
- data/lib/denko/led/seven_segment.rb +1 -1
- data/lib/denko/led.rb +17 -8
- data/lib/denko/motor/{stepper.rb → a3967.rb} +1 -1
- data/lib/denko/motor/servo.rb +16 -6
- data/lib/denko/motor.rb +16 -3
- data/lib/denko/one_wire/bus.rb +20 -16
- data/lib/denko/one_wire/bus_enumerator.rb +25 -14
- data/lib/denko/one_wire/helper.rb +4 -2
- data/lib/denko/one_wire.rb +18 -5
- data/lib/denko/pulse_io/buzzer.rb +2 -6
- data/lib/denko/pulse_io/ir_output.rb +1 -5
- data/lib/denko/pulse_io/pwm_output.rb +56 -31
- data/lib/denko/pulse_io.rb +17 -3
- data/lib/denko/rtc/ds3231.rb +4 -3
- data/lib/denko/rtc.rb +14 -1
- data/lib/denko/sensor/aht.rb +16 -20
- data/lib/denko/sensor/bme280.rb +23 -36
- data/lib/denko/sensor/bmp180.rb +8 -13
- data/lib/denko/sensor/dht.rb +17 -7
- data/lib/denko/sensor/ds18b20.rb +5 -4
- data/lib/denko/sensor/hdc1080.rb +174 -0
- data/lib/denko/sensor/htu21d.rb +17 -6
- data/lib/denko/sensor/htu31d.rb +6 -5
- data/lib/denko/sensor/jsnsr04t.rb +49 -0
- data/lib/denko/sensor/qmp6988.rb +14 -30
- data/lib/denko/sensor/rcwl9620.rb +1 -0
- data/lib/denko/sensor/sht3x.rb +6 -5
- data/lib/denko/sensor/sht4x.rb +125 -0
- data/lib/denko/sensor/vl53l0x.rb +58 -0
- data/lib/denko/sensor.rb +33 -15
- data/lib/denko/spi/base_register.rb +11 -7
- data/lib/denko/spi/bus_common.rb +12 -15
- data/lib/denko/spi/input_register.rb +6 -6
- data/lib/denko/spi/output_register.rb +13 -4
- data/lib/denko/spi/peripheral.rb +82 -84
- data/lib/denko/spi.rb +20 -10
- data/lib/denko/uart/bit_bang.rb +2 -27
- data/lib/denko/uart/common.rb +33 -0
- data/lib/denko/uart/hardware.rb +1 -26
- data/lib/denko/uart.rb +16 -2
- data/lib/denko/version.rb +1 -1
- data/lib/denko.rb +22 -25
- data/lib/denko_cli/targets.rb +7 -7
- data/lib/denko_cli/targets.txt +19 -20
- data/src/lib/Denko.cpp +26 -13
- data/src/lib/Denko.h +4 -4
- data/src/lib/DenkoDefines.h +7 -26
- data/src/lib/DenkoLEDArray.cpp +1 -8
- data/src/lib/DenkoSPI.cpp +31 -29
- data/src/lib/DenkoSPIBB.cpp +12 -14
- data/test/analog_io/input_test.rb +1 -1
- data/test/analog_io/potentiometer_test.rb +2 -2
- data/test/behaviors/bus_peripheral_test.rb +4 -4
- data/test/behaviors/callbacks_test.rb +20 -10
- data/test/behaviors/component_test.rb +18 -8
- data/test/board/board_test.rb +9 -9
- data/test/board/one_wire_test.rb +25 -14
- data/test/board/spi_test.rb +31 -15
- data/test/digital_io/input_test.rb +2 -2
- data/test/display/canvas_test.rb +306 -0
- data/test/display/hd44780_test.rb +34 -7
- data/test/eeprom/board_test.rb +45 -0
- data/test/helpers/mruby_minitest.rb +95 -0
- data/test/helpers/mruby_runner.rb +13 -0
- data/test/i2c/bus_test.rb +93 -30
- data/test/i2c/peripheral_test.rb +2 -2
- data/test/led/apa102_test.rb +24 -0
- data/test/led/rgb_test.rb +4 -4
- data/test/motor/{stepper_test.rb → a3967_test.rb} +2 -2
- data/test/one_wire/bus_enumerator_test.rb +1 -1
- data/test/one_wire/bus_test.rb +42 -35
- data/test/one_wire/peripheral_test.rb +5 -17
- data/test/pulse_io/ir_output_test.rb +5 -0
- data/test/pulse_io/pwm_output_test.rb +10 -10
- data/test/rtc/ds3231_test.rb +3 -2
- data/test/sensor/dht_test.rb +11 -11
- data/test/spi/bitbang_test.rb +27 -0
- data/test/spi/bus_test.rb +19 -29
- data/test/spi/input_register_test.rb +2 -2
- data/test/spi/{peripheral_multi_pin_test.rb → peripheral_test.rb} +25 -5
- data/test/test_helper.rb +44 -124
- data/vendor/board-maps/BoardMap.h +264 -0
- data/vendor/board-maps/yaml/ALFREDO_NOU3.yml +2 -0
- data/vendor/board-maps/yaml/ATD143_S3.yml +1 -0
- data/vendor/board-maps/yaml/BHARATPI_A7672S_4G.yml +14 -0
- data/vendor/board-maps/yaml/BHARATPI_LORA.yml +14 -0
- data/vendor/board-maps/yaml/BHARATPI_NODE_WIFI.yml +14 -0
- data/vendor/board-maps/yaml/BPI_LEAF_S3.yml +0 -1
- data/vendor/board-maps/yaml/CEZERIO_DEV_ESP32C6.yml +14 -0
- data/vendor/board-maps/yaml/CEZERIO_MINI_DEV_ESP32C6.yml +12 -0
- data/vendor/board-maps/yaml/CIRCUITART_ZERO_S3.yml +71 -0
- data/vendor/board-maps/yaml/CODECELLC3.yml +13 -0
- data/vendor/board-maps/yaml/CYOBOT_V2_ESP32S3.yml +7 -0
- data/vendor/board-maps/yaml/EDGES3D.yml +25 -0
- data/vendor/board-maps/yaml/ESP32C6_DEV.yml +3 -4
- data/vendor/board-maps/yaml/ESP32C6_THING_PLUS.yml +0 -1
- data/vendor/board-maps/yaml/ESP32H2_DEV.yml +0 -1
- data/vendor/board-maps/yaml/ESP32H2_DEVKIT_LIPO.yml +0 -1
- data/vendor/board-maps/yaml/ESP32P4_DEV.yml +35 -0
- data/vendor/board-maps/yaml/ESP32S2_DEV.yml +0 -1
- data/vendor/board-maps/yaml/ESP32S2_DEVKIT_LIPO.yml +0 -1
- data/vendor/board-maps/yaml/ESP32S2_DEVKIT_LIPO_USB.yml +0 -1
- data/vendor/board-maps/yaml/ESP32_2432S028R.yml +14 -0
- data/vendor/board-maps/yaml/FEATHERS3.yml +1 -1
- data/vendor/board-maps/yaml/FRI3D_2024_ESP32S3.yml +43 -0
- data/vendor/board-maps/yaml/GEEKBLE_ESP32C3.yml +0 -1
- data/vendor/board-maps/yaml/GEEKBLE_NANO_ESP32S3.yml +25 -0
- data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_E290.yml +41 -0
- data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_E_213.yml +41 -0
- data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_T190.yml +41 -0
- data/vendor/board-maps/yaml/HUIDU_HD_WF2.yml +5 -0
- data/vendor/board-maps/yaml/HUIDU_HD_WF4.yml +1 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_CC1101.yml +6 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_LR1121.yml +6 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_SI4432.yml +6 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_SX1262.yml +6 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_SX1280.yml +6 -0
- data/vendor/board-maps/yaml/LOLIN_C3_MINI.yml +0 -1
- data/vendor/board-maps/yaml/LOLIN_C3_PICO.yml +1 -2
- data/vendor/board-maps/yaml/LoPy.yml +0 -1
- data/vendor/board-maps/yaml/LoPy4.yml +0 -1
- data/vendor/board-maps/yaml/M5STACK_DINMETER.yml +8 -0
- data/vendor/board-maps/yaml/M5STACK_FIRE.yml +1 -1
- data/vendor/board-maps/yaml/OMGS3.yml +25 -0
- data/vendor/board-maps/yaml/PCBCUPID_GLYPHC3.yml +23 -0
- data/vendor/board-maps/yaml/PCBCUPID_GLYPHC6.yml +32 -0
- data/vendor/board-maps/yaml/PCBCUPID_GLYPHH2.yml +24 -0
- data/vendor/board-maps/yaml/PYCOM_GPY.yml +0 -1
- data/vendor/board-maps/yaml/SENSEBOX_MCU_ESP32S2.yml +1 -1
- data/vendor/board-maps/yaml/SPARKFUN_ESP32S3_THING_PLUS.yml +13 -0
- data/vendor/board-maps/yaml/SPARKLEMOTIONMINI_ESP32.yml +12 -0
- data/vendor/board-maps/yaml/SPARKLEMOTIONSTICK_ESP32.yml +11 -0
- data/vendor/board-maps/yaml/SPARKLEMOTION_ESP32.yml +12 -0
- data/vendor/board-maps/yaml/SQUIXL.yml +7 -0
- data/vendor/board-maps/yaml/THINGPULSE_EPULSE_FEATHER_C6.yml +0 -1
- data/vendor/board-maps/yaml/T_LORA_PAGER.yml +6 -0
- data/vendor/board-maps/yaml/T_WATCH_S3.yml +7 -0
- data/vendor/board-maps/yaml/T_WATCH_S3_ULTRA.yml +6 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_146.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_147.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_169.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_185.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_RELAY_6CH.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_143.yml +7 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_164.yml +7 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_18.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_191.yml +7 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_241.yml +7 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_146.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_169.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_185.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_185_BOX.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_21.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_28.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_4.yml +36 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_43.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_43B.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_5.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_5B.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_7.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_ZERO.yml +36 -0
- data/vendor/board-maps/yaml/WIPY3.yml +0 -1
- data/vendor/board-maps/yaml/WS_ESP32_S3_MATRIX.yml +38 -0
- data/vendor/board-maps/yaml/XIAO_ESP32S3_PLUS.yml +46 -0
- data/vendor/board-maps/yaml/YB_ESP32S3_AMP_V2.yml +28 -0
- data/vendor/board-maps/yaml/YB_ESP32S3_AMP_V3.yml +28 -0
- data/vendor/board-maps/yaml/YB_ESP32S3_ETH.yml +40 -0
- data/vendor/board-maps/yaml/mercury.yml +20 -0
- metadata +116 -101
- data/.vscode/settings.json +0 -5
- data/.vscode/tasks.json +0 -20
- data/HARDWARE.md +0 -263
- data/benchmarks/analog_listen.rb +0 -49
- data/benchmarks/digital_write.rb +0 -28
- data/benchmarks/i2c_ssd1306_refresh.rb +0 -91
- data/examples/advanced/m5_env3.rb +0 -46
- data/examples/advanced/rotary_encoder_mac_volume.rb +0 -53
- data/examples/advanced/ssd1306_time_temp_rh.rb +0 -43
- data/examples/analog_io/ads1100.rb +0 -48
- data/examples/analog_io/ads1115.rb +0 -57
- data/examples/analog_io/ads1118.rb +0 -65
- data/examples/analog_io/dac_loopback.rb +0 -34
- data/examples/analog_io/input.rb +0 -56
- data/examples/analog_io/input_smoothing.rb +0 -27
- data/examples/analog_io/potentiometer.rb +0 -31
- data/examples/connection/binary_echo.rb +0 -34
- data/examples/connection/tcp.rb +0 -19
- data/examples/digital_io/button.rb +0 -17
- data/examples/digital_io/relay.rb +0 -17
- data/examples/digital_io/rotary_encoder.rb +0 -36
- data/examples/display/hd44780.png +0 -0
- data/examples/display/hd44780.rb +0 -47
- data/examples/display/ssd1306.rb +0 -43
- data/examples/display/ssd1306_s2_pico.rb +0 -29
- data/examples/eeprom/built_in.rb +0 -32
- data/examples/i2c/search.rb +0 -39
- data/examples/led/apa102_bounce.rb +0 -32
- data/examples/led/apa102_fade.rb +0 -44
- data/examples/led/builtin_blink.rb +0 -14
- data/examples/led/builtin_fade.rb +0 -19
- data/examples/led/rgb_led.rb +0 -31
- data/examples/led/seven_segment_char_echo.rb +0 -17
- data/examples/led/ws2812_bounce.rb +0 -30
- data/examples/led/ws2812_builtin_blink.rb +0 -22
- data/examples/led/ws2812_fade.rb +0 -43
- data/examples/motor/l298.rb +0 -45
- data/examples/motor/servo.rb +0 -17
- data/examples/motor/stepper.png +0 -0
- data/examples/motor/stepper.rb +0 -43
- data/examples/one_wire/search.rb +0 -32
- data/examples/pulse_io/buzzer.rb +0 -35
- data/examples/pulse_io/ir_output.rb +0 -51
- data/examples/pulse_io/pwm_output.rb +0 -30
- data/examples/rtc/ds3231.rb +0 -31
- data/examples/sensor/aht10.rb +0 -17
- data/examples/sensor/aht20.rb +0 -17
- data/examples/sensor/bme280.rb +0 -38
- data/examples/sensor/bmp180.rb +0 -26
- data/examples/sensor/dht.rb +0 -29
- data/examples/sensor/ds18b20.rb +0 -57
- data/examples/sensor/generic_pir.rb +0 -27
- data/examples/sensor/hcsr04.rb +0 -17
- data/examples/sensor/htu21d.rb +0 -43
- data/examples/sensor/htu31d.rb +0 -33
- data/examples/sensor/neat_tph_readings.rb +0 -32
- data/examples/sensor/qmp6988.rb +0 -51
- data/examples/sensor/rcwl9620.rb +0 -15
- data/examples/sensor/sht3x.rb +0 -32
- data/examples/spi/bitbang_loopback.rb +0 -46
- data/examples/spi/input_register.rb +0 -40
- data/examples/spi/output_register.rb +0 -41
- data/examples/spi/ssd_through_registers.rb +0 -28
- data/examples/spi/two_registers.rb +0 -40
- data/examples/uart/bit_bang_demo.rb +0 -25
- data/examples/uart/board_passthrough.rb +0 -40
- data/examples/uart/hardware_loopback.rb +0 -16
- data/lib/denko/eeprom/built_in.rb +0 -72
- data/lib/denko/fonts.rb +0 -106
- data/test/eeprom/built_in_test.rb +0 -61
- data/test/spi/peripheral_single_pin_test.rb +0 -48
- data/tutorial/01-led/led.fzz +0 -0
- data/tutorial/01-led/led.pdf +0 -0
- data/tutorial/01-led/led.rb +0 -73
- data/tutorial/02-button/button.fzz +0 -0
- data/tutorial/02-button/button.pdf +0 -0
- data/tutorial/02-button/button.rb +0 -65
- data/tutorial/03-potentiometer/potentiometer.fzz +0 -0
- data/tutorial/03-potentiometer/potentiometer.pdf +0 -0
- data/tutorial/03-potentiometer/potentiometer.rb +0 -66
- data/tutorial/04-pwm_led/pwm_led.fzz +0 -0
- data/tutorial/04-pwm_led/pwm_led.pdf +0 -0
- data/tutorial/04-pwm_led/pwm_led.rb +0 -64
- data/tutorial/05-rgb_led/rgb_led.fzz +0 -0
- data/tutorial/05-rgb_led/rgb_led.pdf +0 -0
- data/tutorial/05-rgb_led/rgb_led.rb +0 -58
- data/tutorial/05-rgb_led/rgb_mapping.rb +0 -76
@@ -1,29 +1,32 @@
|
|
1
1
|
module Denko
|
2
2
|
module Behaviors
|
3
3
|
module Callbacks
|
4
|
+
include Lifecycle
|
4
5
|
include State
|
5
6
|
|
6
|
-
|
7
|
-
@callback_mutex
|
8
|
-
|
7
|
+
after_initialize do
|
8
|
+
@callback_mutex = Denko.gil? ? Denko::MutexStub.new : Mutex.new
|
9
|
+
callbacks
|
9
10
|
end
|
10
11
|
|
11
12
|
def callbacks
|
12
|
-
|
13
|
+
@callbacks ||= {}
|
13
14
|
end
|
14
15
|
|
15
16
|
def add_callback(key=:persistent, &block)
|
16
|
-
callback_mutex.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
@callback_mutex.lock
|
18
|
+
@callbacks ||= {}
|
19
|
+
@callbacks[key] ||= []
|
20
|
+
@callbacks[key] << block
|
21
|
+
@callback_mutex.unlock
|
22
|
+
@callbacks
|
21
23
|
end
|
22
24
|
|
23
25
|
def remove_callback(key=nil)
|
24
|
-
callback_mutex.
|
25
|
-
|
26
|
-
|
26
|
+
@callback_mutex.lock
|
27
|
+
(@callbacks && key) ? @callbacks.delete(key) : @callbacks = {}
|
28
|
+
@callback_mutex.unlock
|
29
|
+
@callbacks
|
27
30
|
end
|
28
31
|
|
29
32
|
alias :on_data :add_callback
|
@@ -44,10 +47,8 @@ module Denko
|
|
44
47
|
return nil
|
45
48
|
end
|
46
49
|
|
47
|
-
callback_mutex.
|
48
|
-
|
49
|
-
break if @callbacks.empty?
|
50
|
-
|
50
|
+
@callback_mutex.lock
|
51
|
+
if @callbacks && !@callbacks.empty?
|
51
52
|
@callbacks.each_value do |array|
|
52
53
|
array.each do |callback|
|
53
54
|
callback.call(filtered_data)
|
@@ -56,6 +57,7 @@ module Denko
|
|
56
57
|
# Remove one-time callbacks added by #read.
|
57
58
|
@callbacks.delete(:read)
|
58
59
|
end
|
60
|
+
@callback_mutex.unlock
|
59
61
|
|
60
62
|
update_state(filtered_data)
|
61
63
|
end
|
@@ -34,7 +34,7 @@ module Denko
|
|
34
34
|
# Need to check civars in ancestors too.
|
35
35
|
klasses = self.class.ancestors
|
36
36
|
# If running "after" reverse hierarchy so they run top-down.
|
37
|
-
klasses = klasses.reverse if method_sym.
|
37
|
+
klasses = klasses.reverse if method_sym.to_s.start_with? "after"
|
38
38
|
|
39
39
|
blocks = []
|
40
40
|
klasses.each do |klass|
|
@@ -2,20 +2,26 @@ module Denko
|
|
2
2
|
module Behaviors
|
3
3
|
module Listener
|
4
4
|
include Callbacks
|
5
|
-
|
5
|
+
|
6
6
|
attr_reader :divider
|
7
7
|
|
8
|
+
#
|
9
|
+
# These delegate to #_listen and #_stop_listener,
|
10
|
+
# which should be defined in the including class.
|
11
|
+
#
|
8
12
|
def listen(divider=nil, &block)
|
9
|
-
@divider = divider
|
13
|
+
@divider = divider
|
10
14
|
stop
|
11
15
|
add_callback(:listen, &block) if block_given?
|
12
16
|
_listen(@divider)
|
17
|
+
@listening = true
|
13
18
|
end
|
14
19
|
|
15
20
|
def stop
|
16
|
-
super
|
21
|
+
begin; super; rescue NoMethodError; end
|
17
22
|
_stop_listener
|
18
23
|
remove_callbacks :listen
|
24
|
+
@listening = false
|
19
25
|
end
|
20
26
|
end
|
21
27
|
end
|
@@ -24,8 +24,10 @@ module Denko
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def convert_pins(options={})
|
27
|
-
|
28
|
-
params[:pins].each
|
27
|
+
@pins = {}
|
28
|
+
params[:pins].each do |key,pin|
|
29
|
+
self.pins[key] = pin ? board.convert_pin(pin) : nil
|
30
|
+
end
|
29
31
|
pin_array = pins.values
|
30
32
|
raise ArgumentError, "duplicate pins in: #{pins.inspect}" unless pin_array == pin_array.uniq
|
31
33
|
end
|
@@ -67,10 +69,6 @@ module Denko
|
|
67
69
|
def require_pins(*array)
|
68
70
|
[array].flatten.each { |name| require_pin(name) }
|
69
71
|
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
attr_writer :pins, :proxies
|
74
72
|
end
|
75
73
|
end
|
76
74
|
end
|
@@ -3,8 +3,10 @@ module Denko
|
|
3
3
|
module Poller
|
4
4
|
include Reader
|
5
5
|
include Threaded
|
6
|
-
|
6
|
+
|
7
7
|
def poll_using(method, interval, *args, &block)
|
8
|
+
mruby_thread_check
|
9
|
+
|
8
10
|
unless [Integer, Float].include? interval.class
|
9
11
|
raise ArgumentError, "wrong interval given to #poll : #{interval.inspect}"
|
10
12
|
end
|
@@ -13,7 +15,14 @@ module Denko
|
|
13
15
|
add_callback(:poll, &block) if block_given?
|
14
16
|
|
15
17
|
threaded_loop do
|
18
|
+
# Lock, THEN wait for other normal reads to finish.
|
19
|
+
@reader_mutex.lock
|
20
|
+
sleep 0.001 while read_busy?
|
21
|
+
@reading_normally = true
|
22
|
+
|
16
23
|
method.call(*args)
|
24
|
+
@reader_mutex.unlock
|
25
|
+
|
17
26
|
sleep interval
|
18
27
|
end
|
19
28
|
end
|
@@ -23,7 +32,7 @@ module Denko
|
|
23
32
|
end
|
24
33
|
|
25
34
|
def stop
|
26
|
-
super
|
35
|
+
begin; super; rescue NoMethodError; end
|
27
36
|
remove_callbacks :poll
|
28
37
|
end
|
29
38
|
end
|
@@ -1,49 +1,137 @@
|
|
1
1
|
module Denko
|
2
2
|
module Behaviors
|
3
3
|
module Reader
|
4
|
+
include Lifecycle
|
4
5
|
include Callbacks
|
5
6
|
|
6
7
|
#
|
7
|
-
#
|
8
|
-
#
|
8
|
+
# DO NOT REPLACE with MutexStub on CRuby!
|
9
|
+
# Even with GIL, misordered readings possible with multiple threads.
|
10
|
+
#
|
11
|
+
after_initialize do
|
12
|
+
# mruby doesn't have Thread or Mutex, so only stub there.
|
13
|
+
@reader_mutex = Denko.mruby? ? Denko::MutexStub.new : Mutex.new
|
14
|
+
end
|
15
|
+
|
16
|
+
READ_WAIT_TIME = 0.001
|
17
|
+
#
|
18
|
+
# Override #update to allow "raw reads" or "normal reads":
|
19
|
+
#
|
20
|
+
# - Normal reads perform normal #update behavior, passing through
|
21
|
+
# #pre_callback_filter, running all callbacks and returning filtered_data.
|
22
|
+
# Use normal for anything that updates the state of a component, and handle
|
23
|
+
# that in in #pre_callback_filter and #update_state.
|
24
|
+
# May or may not block calling thread, depending on platform.
|
25
|
+
#
|
26
|
+
# - Raw reads bypass #pre_callback_filter, callbacks, and return
|
27
|
+
# raw data. Use raw for reading things like sensor config/serial etc.
|
28
|
+
# DOES NOT take block callbacks from the use. ALWAYS handle the return value.
|
29
|
+
# ALWAYS blocks the calling thread.
|
30
|
+
#
|
31
|
+
def update(data)
|
32
|
+
if @reading_raw
|
33
|
+
@callback_mutex.lock
|
34
|
+
@callbacks[:read_raw].each { |c| c.call(data) }
|
35
|
+
@callbacks.delete(:read_raw)
|
36
|
+
@callback_mutex.unlock
|
37
|
+
@reading_raw = false
|
38
|
+
data
|
39
|
+
else
|
40
|
+
return_value = super(data)
|
41
|
+
@reading_normally = false
|
42
|
+
return_value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Delegates to #_read. Data passes through #pre_callback_filter, runs all
|
48
|
+
# callbacks, and @state is set. BLOCKS calling thread.
|
9
49
|
#
|
10
50
|
def read(*args, **kwargs, &block)
|
11
51
|
read_using(self.method(:_read), *args, **kwargs, &block)
|
12
52
|
end
|
13
53
|
|
54
|
+
#
|
55
|
+
# Delegates to #_read. Data passes through #pre_callback_filter, runs all
|
56
|
+
# callbacks, and @state is set. DOES NOT BLOCK calling thread.
|
57
|
+
#
|
58
|
+
def read_nb(*args, **kwargs, &block)
|
59
|
+
@reader_mutex.lock
|
60
|
+
sleep READ_WAIT_TIME while read_busy?
|
61
|
+
@reading_normally = true
|
62
|
+
_read(*args, **kwargs, &block)
|
63
|
+
@reader_mutex.unlock
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# NEVER call this directly. Use #read_nb instead.
|
68
|
+
#
|
69
|
+
# Define #_read in including class to get data which updates the
|
70
|
+
# peripheral state. See #read_using comments for more info.
|
71
|
+
#
|
72
|
+
def _read
|
73
|
+
raise NotImplementedError.new("#{self.class.name}#_read is not defined.")
|
74
|
+
end
|
75
|
+
|
14
76
|
#
|
15
77
|
# Take a proc/lambda/method as the first agrument and use it to read.
|
16
78
|
# Arguments are passed through, allowing dynamic read methods to be defined.
|
17
79
|
# Eg. send commands (in args) to a bus, then wait for data read back.
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
80
|
+
#
|
81
|
+
# Data is received when the board/bus calls #update on us. If a read was
|
82
|
+
# started by this method, the data will pass through #pre_callback_filter,
|
83
|
+
# trigger all callbacks, and set @state. Use this for reading the state
|
84
|
+
# of peripherals, like digital pin level, enviro sensor reading etc.
|
22
85
|
#
|
23
86
|
def read_using(reader, *args, **kwargs, &block)
|
24
|
-
|
87
|
+
# Lock, THEN wait for other normal reads to finish.
|
88
|
+
@reader_mutex.lock
|
89
|
+
sleep READ_WAIT_TIME while read_busy?
|
90
|
+
@reading_normally = true
|
25
91
|
|
92
|
+
# One-time callbacks.
|
26
93
|
return_value = nil
|
27
|
-
add_callback(:read)
|
28
|
-
|
29
|
-
|
30
|
-
|
94
|
+
add_callback(:read) { |filtered_data| return_value = filtered_data }
|
95
|
+
add_callback(:read, &block) if block_given?
|
96
|
+
|
31
97
|
reader.call(*args, **kwargs)
|
32
|
-
|
98
|
+
@reader_mutex.unlock
|
33
99
|
|
100
|
+
# Wait for #update to remove the :read callbacks (return_value is set).
|
101
|
+
sleep READ_WAIT_TIME while callbacks[:read]
|
34
102
|
return_value
|
35
103
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
104
|
+
|
105
|
+
#
|
106
|
+
# Similar to #read_using, but does not trigger #pre_callback_filter,
|
107
|
+
# or run any callbacks except :read_raw. BLOCKS calling thread.
|
108
|
+
# Use for things like sensor status, config etc.
|
109
|
+
#
|
110
|
+
def read_raw(reader, *args, **kwargs)
|
111
|
+
# Can't guarantee read order.
|
112
|
+
raise StandardError, "#read_raw unavailable while listening" if @listening
|
113
|
+
|
114
|
+
# Lock, THEN wait for any normal read to finish.
|
115
|
+
@reader_mutex.lock
|
116
|
+
sleep READ_WAIT_TIME while read_busy?
|
117
|
+
@reading_raw = true
|
118
|
+
|
119
|
+
# Special :read_raw one-time callback.
|
120
|
+
return_value = nil
|
121
|
+
add_callback(:read_raw) { |bytes| return_value = bytes }
|
122
|
+
|
123
|
+
# Call reader, but block and keep the lock until :read_raw callback gets run.
|
124
|
+
reader.call(*args, **kwargs)
|
125
|
+
sleep READ_WAIT_TIME while callbacks[:read_raw]
|
126
|
+
@reader_mutex.unlock
|
127
|
+
|
128
|
+
return_value
|
42
129
|
end
|
43
130
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
131
|
+
def read_busy?
|
132
|
+
# mruby gets stuck waiting somewhere, but doesn't have threads
|
133
|
+
# so it can never really be busy.
|
134
|
+
!Denko.mruby? && (@reading_normally || @reading_raw)
|
47
135
|
end
|
48
136
|
end
|
49
137
|
end
|
@@ -3,13 +3,11 @@ module Denko
|
|
3
3
|
module SinglePin
|
4
4
|
include Component
|
5
5
|
attr_reader :pin, :mode
|
6
|
-
|
7
|
-
def mode=(mode)
|
6
|
+
|
7
|
+
def mode=(mode)
|
8
8
|
board.set_pin_mode(pin, mode)
|
9
9
|
@mode = mode
|
10
10
|
end
|
11
|
-
|
12
|
-
protected
|
13
11
|
|
14
12
|
def convert_pins(options={})
|
15
13
|
raise ArgumentError, 'a pin is required for this component' unless options[:pin]
|
@@ -3,24 +3,29 @@ module Denko
|
|
3
3
|
module State
|
4
4
|
include Lifecycle
|
5
5
|
|
6
|
-
# Force state initialization.
|
6
|
+
# Force state and mutex initialization.
|
7
7
|
after_initialize do
|
8
|
+
@state_mutex = Denko.gil? ? Denko::MutexStub.new : Mutex.new
|
8
9
|
state
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
# mruby optimization. Bypass state_mutex for simple states.
|
13
|
+
if Denko.mruby?
|
14
|
+
attr_accessor :state
|
15
|
+
else
|
16
|
+
def state
|
17
|
+
@state_mutex.lock
|
18
|
+
value = @state
|
19
|
+
@state_mutex.unlock
|
20
|
+
value
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
def state=(value)
|
24
|
+
@state_mutex.lock
|
25
|
+
@state = value
|
26
|
+
@state_mutex.unlock
|
27
|
+
@state
|
28
|
+
end
|
24
29
|
end
|
25
30
|
|
26
31
|
def update_state(value)
|
@@ -11,39 +11,50 @@ module Denko
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
def mruby_thread_check
|
15
|
+
if Denko.mruby?
|
16
|
+
raise NotImplementedError, "threads unavailable in mruby "
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
14
20
|
def self.included(base)
|
15
21
|
base.extend ClassMethods
|
16
22
|
end
|
17
23
|
|
18
24
|
def threaded(&block)
|
25
|
+
mruby_thread_check
|
19
26
|
stop_thread
|
20
27
|
enable_interrupts unless interrupts_enabled
|
21
28
|
@thread = Thread.new(&block)
|
22
29
|
end
|
23
30
|
|
24
31
|
def threaded_loop(&block)
|
32
|
+
mruby_thread_check
|
25
33
|
threaded do
|
26
34
|
loop(&block)
|
27
35
|
end
|
28
36
|
end
|
29
37
|
|
30
38
|
def stop_thread
|
39
|
+
mruby_thread_check
|
31
40
|
@thread.kill if @thread
|
32
41
|
end
|
33
42
|
|
34
43
|
def stop
|
35
|
-
stop_thread
|
36
|
-
super
|
44
|
+
stop_thread unless Denko.mruby?
|
45
|
+
begin; super; rescue NoMethodError; end
|
37
46
|
end
|
38
47
|
|
39
48
|
def enable_interrupts
|
40
|
-
|
41
|
-
|
42
|
-
|
49
|
+
unless Denko.mruby?
|
50
|
+
interrupts = self.class.class_eval('@@interrupts') rescue []
|
51
|
+
interrupts.each do |method_name|
|
52
|
+
standard_method = self.method(method_name)
|
43
53
|
|
44
|
-
|
45
|
-
|
46
|
-
|
54
|
+
singleton_class.send(:define_method, method_name) do |*args|
|
55
|
+
stop_thread unless (Thread.current == @thread)
|
56
|
+
standard_method.call(*args)
|
57
|
+
end
|
47
58
|
end
|
48
59
|
end
|
49
60
|
|
data/lib/denko/behaviors.rb
CHANGED
@@ -1,27 +1,40 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
# Represent files to be autoloaded in CRuby as an Array.
|
2
|
+
# This allows Mruby::Build to parse and preload them instead.
|
3
|
+
BEHAVIORS_FILES = [
|
4
|
+
# Pin and component setup stuff
|
5
|
+
[:Lifecycle, "lifecycle"],
|
6
|
+
[:State, "state"],
|
7
|
+
[:Component, "component"],
|
8
|
+
[:SinglePin, "single_pin"],
|
9
|
+
[:InputPin, "input_pin"],
|
10
|
+
[:OutputPin, "output_pin"],
|
11
|
+
[:MultiPin, "multi_pin"],
|
12
|
+
|
13
|
+
# Subcomponent stuff
|
14
|
+
[:Subcomponents, "subcomponents"],
|
15
|
+
[:BusController, "bus_controller"],
|
16
|
+
[:BusControllerAddressed, "bus_controller_addressed"],
|
17
|
+
[:BusPeripheral, "bus_peripheral"],
|
18
|
+
[:BusPeripheralAddressed, "bus_peripheral_addressed"],
|
19
|
+
[:BoardProxy, "board_proxy"],
|
11
20
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
21
|
+
# Async stuff
|
22
|
+
[:Threaded, "threaded"],
|
23
|
+
[:Callbacks, "callbacks"],
|
24
|
+
[:Reader, "reader"],
|
25
|
+
[:Poller, "poller"],
|
26
|
+
[:Listener, "listener"],
|
27
|
+
]
|
19
28
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
29
|
+
module Denko
|
30
|
+
module Behaviors
|
31
|
+
BEHAVIORS_FILES.each do |file|
|
32
|
+
file_path = "#{__dir__}/behaviors/#{file[1]}"
|
33
|
+
if file[0]
|
34
|
+
autoload file[0], file_path
|
35
|
+
else
|
36
|
+
require file_path
|
37
|
+
end
|
38
|
+
end
|
26
39
|
end
|
27
40
|
end
|
data/lib/denko/board/eeprom.rb
CHANGED
@@ -11,7 +11,7 @@ module Denko
|
|
11
11
|
# CMD = 8
|
12
12
|
def eeprom_write(address, bytes)
|
13
13
|
address = pack :uint16, address
|
14
|
-
bytes
|
14
|
+
bytes = pack :uint8, bytes
|
15
15
|
write Message.encode command: 8,
|
16
16
|
value: bytes.length,
|
17
17
|
aux_message: address + bytes
|
data/lib/denko/board/i2c.rb
CHANGED
@@ -26,7 +26,7 @@ module Denko
|
|
26
26
|
|
27
27
|
# CMD = 34
|
28
28
|
def i2c_write(i2c_index, address, bytes, frequency=100000, repeated_start=false)
|
29
|
-
bytes = [bytes] unless bytes.class == Array
|
29
|
+
bytes = [bytes].flatten unless bytes.class == Array
|
30
30
|
raise ArgumentError, "I2C write must be 1..#{i2c_limit} bytes long" if (bytes.length > i2c_limit || bytes.length < 1)
|
31
31
|
|
32
32
|
# Use top bit of address to select stop condition (1), or repated start (0).
|
@@ -1,5 +1,9 @@
|
|
1
1
|
module Denko
|
2
2
|
class Board
|
3
|
+
def i2c_bb_setup(scl, sda)
|
4
|
+
# Stub method. Other implementations may call this.
|
5
|
+
end
|
6
|
+
|
3
7
|
# CMD = 30
|
4
8
|
def i2c_bb_search(scl, sda)
|
5
9
|
write Message.encode command: 30,
|
@@ -9,15 +13,15 @@ module Denko
|
|
9
13
|
|
10
14
|
# CMD = 31
|
11
15
|
def i2c_bb_write(scl, sda, address, bytes, repeated_start=false)
|
12
|
-
bytes = [bytes] unless bytes.class == Array
|
13
|
-
|
16
|
+
bytes = [bytes].flatten unless bytes.class == Array
|
17
|
+
|
14
18
|
# Use top bit of address to select stop condition (1), or repated start (0).
|
15
19
|
send_stop = repeated_start ? 0 : 1
|
16
|
-
|
20
|
+
|
17
21
|
write Message.encode command: 31,
|
18
22
|
pin: scl,
|
19
23
|
value: sda,
|
20
|
-
aux_message: pack(:uint8, 0x00) +
|
24
|
+
aux_message: pack(:uint8, 0x00) +
|
21
25
|
pack(:uint8, address | (send_stop << 7)) +
|
22
26
|
pack(:uint8, bytes.length) +
|
23
27
|
pack(:uint8, bytes)
|
@@ -40,7 +44,7 @@ module Denko
|
|
40
44
|
write Message.encode command: 32,
|
41
45
|
pin: scl,
|
42
46
|
value: sda,
|
43
|
-
aux_message: pack(:uint8, 0x00) +
|
47
|
+
aux_message: pack(:uint8, 0x00) +
|
44
48
|
pack(:uint8, address | (send_stop << 7)) +
|
45
49
|
pack(:uint8, read_length) +
|
46
50
|
register_packed
|
data/lib/denko/board/map.rb
CHANGED
@@ -5,7 +5,7 @@ module Denko
|
|
5
5
|
MAPS_FOLDER = File.join(Denko.root, "vendor/board-maps/yaml")
|
6
6
|
|
7
7
|
attr_reader :map
|
8
|
-
|
8
|
+
|
9
9
|
def substitute_zero_pins
|
10
10
|
["SDA", "SCL", "MOSI", "MISO", "SCK", "SS"].each do |name|
|
11
11
|
symbol = name.to_sym
|
@@ -25,7 +25,7 @@ module Denko
|
|
25
25
|
rescue
|
26
26
|
raise StandardError, "error loading board map from file for board name: '#{board_name}'"
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def convert_pin(pin)
|
30
30
|
# Convert non numerical strings to symbols.
|
31
31
|
pin = pin.to_sym if (pin.class == String) && !(pin.match (/\A\d+\.*\d*/))
|
@@ -50,6 +50,10 @@ module Denko
|
|
50
50
|
rescue
|
51
51
|
raise ArgumentError, "error in pin: #{pin.inspect}"
|
52
52
|
end
|
53
|
+
|
54
|
+
def pin_is_pwm?(pin)
|
55
|
+
false
|
56
|
+
end
|
53
57
|
end
|
54
58
|
end
|
55
59
|
end
|
data/lib/denko/board/one_wire.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Denko
|
2
2
|
class Board
|
3
|
-
def one_wire_reset(pin,
|
3
|
+
def one_wire_reset(pin, read_presence=false)
|
4
4
|
write Message.encode command: 41,
|
5
5
|
pin: pin,
|
6
|
-
value:
|
6
|
+
value: read_presence ? 1 : 0
|
7
7
|
end
|
8
8
|
|
9
9
|
def one_wire_search(pin, branch_mask)
|
@@ -12,7 +12,7 @@ module Denko
|
|
12
12
|
aux_message: pack(:uint64, branch_mask, max: 8)
|
13
13
|
end
|
14
14
|
|
15
|
-
def one_wire_write(pin, parasite_power,
|
15
|
+
def one_wire_write(pin, parasite_power, data)
|
16
16
|
bytes = pack :uint8, data, min: 1, max: 127 # Should be 128 with 0 = 1.
|
17
17
|
|
18
18
|
# Set high bit of length if the bus must drive high after write.
|