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
@@ -0,0 +1,306 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class CanvasTest < Minitest::Test
|
4
|
+
WIDTH = 32
|
5
|
+
HEIGHT = 32
|
6
|
+
FB_LENGTH = (WIDTH * HEIGHT / 8)
|
7
|
+
|
8
|
+
def subject
|
9
|
+
@subject ||= Denko::Display::Canvas.new(WIDTH, HEIGHT, colors: 2)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_framebuffer_default_state
|
13
|
+
assert_equal 2, subject.framebuffers.length
|
14
|
+
assert_equal subject.framebuffer.object_id, subject.framebuffers.first.object_id
|
15
|
+
assert_equal Array.new(FB_LENGTH) { 0x00 }, subject.framebuffers[0]
|
16
|
+
assert_equal Array.new(FB_LENGTH) { 0x00 }, subject.framebuffers[1]
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_transform_default_state
|
20
|
+
refute subject.instance_variable_get(:@swap_xy)
|
21
|
+
refute subject.instance_variable_get(:@invert_x)
|
22
|
+
refute subject.instance_variable_get(:@invert_y)
|
23
|
+
assert_equal 0, subject.instance_variable_get(:@rotation)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_drawing_default_state
|
27
|
+
assert_equal 1, subject.current_color
|
28
|
+
assert_equal 1, subject.font_scale
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_test_pixels
|
32
|
+
subject.set_pixel x: 0, y: 0, color: 1
|
33
|
+
subject.set_pixel x: 1, y: 1, color: 2
|
34
|
+
subject.set_pixel x: 14, y: 14, color: 1
|
35
|
+
subject.set_pixel x: 15, y: 15, color: 2
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_clear
|
39
|
+
setup_test_pixels
|
40
|
+
empty = Array.new(FB_LENGTH) { 0x00 }
|
41
|
+
|
42
|
+
subject.clear
|
43
|
+
assert_equal empty, subject.framebuffers[0]
|
44
|
+
assert_equal empty, subject.framebuffers[1]
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_fill
|
48
|
+
empty = Array.new(FB_LENGTH) { 0x00 }
|
49
|
+
filled = Array.new(FB_LENGTH) { 0xFF }
|
50
|
+
|
51
|
+
subject.fill
|
52
|
+
assert_equal filled, subject.framebuffers[0]
|
53
|
+
assert_equal empty, subject.framebuffers[1]
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_set_pixel
|
57
|
+
setup_test_pixels
|
58
|
+
|
59
|
+
fb0 = Array.new(FB_LENGTH) { 0 }
|
60
|
+
fb0[0] = 0b00000001
|
61
|
+
fb0[WIDTH+14] = 0b01000000
|
62
|
+
assert_equal fb0, subject.framebuffers[0]
|
63
|
+
|
64
|
+
fb1 = Array.new(FB_LENGTH) { 0 }
|
65
|
+
fb1[1] = 0b00000010
|
66
|
+
fb1[WIDTH+15] = 0b10000000
|
67
|
+
assert_equal fb1, subject.framebuffers[1]
|
68
|
+
|
69
|
+
# Setting a pixel in FB 0 (color: 1) clears corresponding bit in FB 1 (color: 2).
|
70
|
+
subject.set_pixel x: 1, y: 1, color: 1
|
71
|
+
assert_equal 0b00000010, subject.framebuffers[0][1]
|
72
|
+
assert_equal 0b00000000, subject.framebuffers[1][1]
|
73
|
+
|
74
|
+
# Setting a pixel to color: 0 clears it in all FBs.
|
75
|
+
subject.set_pixel x: 0, y: 0, color: 0
|
76
|
+
assert_equal 0b00000000, subject.framebuffers[0][0]
|
77
|
+
assert_equal 0b00000000, subject.framebuffers[1][0]
|
78
|
+
|
79
|
+
subject.set_pixel x: 15, y: 15, color: 0
|
80
|
+
assert_equal 0b00000000, subject.framebuffers[0][WIDTH+15]
|
81
|
+
assert_equal 0b00000000, subject.framebuffers[1][WIDTH+15]
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_current_color
|
85
|
+
subject.current_color = 2
|
86
|
+
subject.set_pixel x: 0, y: 0
|
87
|
+
assert_equal 0b00000000, subject.framebuffers[0][0]
|
88
|
+
assert_equal 0b00000001, subject.framebuffers[1][0]
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_get_pixel
|
92
|
+
setup_test_pixels
|
93
|
+
assert_equal 1, subject.get_pixel(x: 0, y: 0)
|
94
|
+
assert_equal 2, subject.get_pixel(x: 15, y: 15)
|
95
|
+
assert_equal 0, subject.get_pixel(x: 20, y: 20)
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_line_single_pixel
|
99
|
+
subject.line x1: 5, y1: 5, x2: 5, y2: 5
|
100
|
+
|
101
|
+
fb0 = Array.new(FB_LENGTH) { 0 }
|
102
|
+
fb0[5] = 0b00100000
|
103
|
+
|
104
|
+
assert_equal fb0, subject.framebuffers[0]
|
105
|
+
end
|
106
|
+
|
107
|
+
LINE_HORIZONTAL_FB = [0, 0, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
108
|
+
|
109
|
+
def test_line_horizontal
|
110
|
+
subject.line x1: 2, y1: 5, x2: 6, y2: 5
|
111
|
+
assert_equal LINE_HORIZONTAL_FB, subject.framebuffers[0]
|
112
|
+
end
|
113
|
+
|
114
|
+
LINE_VERTICAL_FB = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
115
|
+
|
116
|
+
def test_line_vertical
|
117
|
+
subject.line x1: 10, y1: 2, x2: 10, y2: 6
|
118
|
+
assert_equal LINE_VERTICAL_FB, subject.framebuffers[0]
|
119
|
+
end
|
120
|
+
|
121
|
+
# 45 degree diagonal lines should produce the same result regardless of which is the start point (x1,y1).
|
122
|
+
LINE_45_FB = [0, 0, 0, 0, 0, 32, 64, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
123
|
+
|
124
|
+
def test_line_45
|
125
|
+
subject.line x1: 5, y1: 5, x2: 10, y2: 10
|
126
|
+
assert_equal LINE_45_FB, subject.framebuffers[0]
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_line_45_swapped
|
130
|
+
subject.line x1: 10, y1: 10, x2: 5, y2: 5
|
131
|
+
assert_equal LINE_45_FB, subject.framebuffers[0]
|
132
|
+
end
|
133
|
+
|
134
|
+
# Non 45 degree diagonals are approximated slightly differently, depending on which point is x1,y1.
|
135
|
+
# This behavior might be useful.
|
136
|
+
# +ve gradients tend to "pull" down and to the left.
|
137
|
+
# -ve gradients tend to "pull" up and to the right.
|
138
|
+
LINE_DIAG_POS_FB = [0, 0, 0, 0, 0, 96, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
139
|
+
|
140
|
+
LINE_DIAG_NEG_FB = [0, 0, 0, 0, 0, 32, 64, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
141
|
+
|
142
|
+
def test_line_diagonal
|
143
|
+
# Note: run and rise not equal.
|
144
|
+
subject.line x1: 5, y1: 5, x2: 8, y2: 10
|
145
|
+
assert_equal LINE_DIAG_POS_FB, subject.framebuffers[0]
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_line_diagonal_swapped
|
149
|
+
# Note: run and rise not equal.
|
150
|
+
subject.line x1: 8, y1: 10, x2: 5, y2: 5
|
151
|
+
assert_equal LINE_DIAG_NEG_FB, subject.framebuffers[0]
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_line_knockout
|
155
|
+
inverted_fb = LINE_DIAG_POS_FB.map { |byte| ~byte & 0xFF }
|
156
|
+
|
157
|
+
subject.fill
|
158
|
+
subject.line x1: 5, y1: 5, x2: 8, y2: 10, color: 0
|
159
|
+
assert_equal inverted_fb, subject.framebuffers[0]
|
160
|
+
end
|
161
|
+
|
162
|
+
RECTANGLE_FB = [0, 0, 0, 0, 0, 224, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
163
|
+
|
164
|
+
def test_rectangle1
|
165
|
+
subject.rectangle x1: 5, y1: 5, x2: 19, y2: 14
|
166
|
+
assert_equal RECTANGLE_FB, subject.framebuffers[0]
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_rectangle2
|
170
|
+
# w is x2-x1+1 (15) from previous, since first pixel counts
|
171
|
+
# h ix y2-y1+1 (10) from previous, since first pixel counts
|
172
|
+
subject.rectangle x: 5, y: 5, w: 15, h: 10
|
173
|
+
assert_equal RECTANGLE_FB, subject.framebuffers[0]
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_rectangle3
|
177
|
+
# -ve values should produce the same rectangles
|
178
|
+
subject.rectangle x: 19, y: 14, w: -15, h: -10
|
179
|
+
assert_equal RECTANGLE_FB, subject.framebuffers[0]
|
180
|
+
end
|
181
|
+
|
182
|
+
SQUARES_FB = [0, 0, 0, 0, 0, 224, 224, 96, 96, 96, 96, 96, 96, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 96, 96, 96, 96, 96, 96, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
183
|
+
|
184
|
+
def test_layered_squares
|
185
|
+
subject.square x: 5, y: 5, size: 10, filled: true, color: 1
|
186
|
+
subject.square x: 7, y: 7, size: 6, filled: true, color: 0
|
187
|
+
assert_equal SQUARES_FB, subject.framebuffers[0]
|
188
|
+
end
|
189
|
+
|
190
|
+
PATH_FB = [3, 4, 24, 32, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 64, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 4, 8, 16, 32, 32, 64, 128, 128, 64, 48, 8, 4, 3, 0, 0, 1, 14, 112, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 28, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 56, 64]
|
191
|
+
|
192
|
+
def path_points
|
193
|
+
[ [0,0], [7,10], [15, 16], [23,5], [31, 30] ]
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_path
|
197
|
+
subject.path path_points, color: 2
|
198
|
+
assert_equal PATH_FB, subject.framebuffers[1]
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_path_knockout
|
202
|
+
inverted_fb = PATH_FB.map { |byte| ~byte & 0xFF }
|
203
|
+
|
204
|
+
subject.fill
|
205
|
+
subject.path path_points, color: 0
|
206
|
+
assert_equal inverted_fb, subject.framebuffers[0]
|
207
|
+
end
|
208
|
+
|
209
|
+
TRIANGLE_FB = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 96, 24, 6, 12, 48, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 96, 24, 6, 193, 240, 124, 31, 62, 248, 224, 131, 12, 48, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 96, 24, 6, 129, 224, 120, 31, 7, 1, 0, 0, 0, 0, 3, 15, 62, 240, 192, 3, 12, 48, 192, 0, 0, 0, 0, 0, 128, 224, 152, 134, 129, 128, 152, 158, 159, 159, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 159, 159, 159, 156, 128, 128, 131, 140, 176, 192]
|
210
|
+
|
211
|
+
def triangle_points
|
212
|
+
[
|
213
|
+
[ [1,31], [31,31], [16,1] ],
|
214
|
+
[ [7,28], [25,28], [16,8] ],
|
215
|
+
[ [11,24], [21,24], [16,13] ],
|
216
|
+
]
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_polygon
|
220
|
+
subject.polygon triangle_points[0]
|
221
|
+
subject.polygon triangle_points[1], filled: true
|
222
|
+
subject.polygon triangle_points[2], filled: true, color: 0
|
223
|
+
assert_equal TRIANGLE_FB, subject.framebuffers[0]
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_triangle
|
227
|
+
t = triangle_points
|
228
|
+
subject.triangle x1: t[0][0][0], y1: t[0][0][1], x2: t[0][1][0], y2: t[0][1][1], x3: t[0][2][0], y3: t[0][2][1]
|
229
|
+
subject.triangle x1: t[1][0][0], y1: t[1][0][1], x2: t[1][1][0], y2: t[1][1][1], x3: t[1][2][0], y3: t[1][2][1], filled: true
|
230
|
+
subject.triangle x1: t[2][0][0], y1: t[2][0][1], x2: t[2][1][0], y2: t[2][1][1], x3: t[2][2][0], y3: t[2][2][1], filled: true, color: 0
|
231
|
+
assert_equal TRIANGLE_FB, subject.framebuffers[0]
|
232
|
+
end
|
233
|
+
|
234
|
+
ELLIPSE_CIRCLE_FB = [0, 0, 128, 192, 224, 240, 120, 60, 28, 30, 142, 142, 71, 71, 71, 71, 71, 71, 71, 142, 142, 30, 28, 60, 120, 240, 224, 192, 128, 0, 0, 0, 240, 254, 255, 15, 3, 224, 24, 4, 2, 1, 224, 24, 6, 2, 1, 1, 1, 2, 6, 24, 224, 1, 2, 4, 24, 224, 3, 15, 255, 254, 240, 0, 7, 63, 255, 248, 224, 131, 12, 16, 32, 64, 131, 140, 48, 32, 64, 64, 64, 32, 48, 140, 131, 64, 32, 16, 12, 131, 224, 248, 255, 63, 7, 0, 0, 0, 0, 1, 3, 7, 15, 30, 28, 60, 56, 56, 113, 113, 113, 113, 113, 113, 113, 56, 56, 60, 28, 30, 15, 7, 3, 1, 0, 0, 0, 0]
|
235
|
+
|
236
|
+
def test_ellipse_circle
|
237
|
+
subject.circle x: 15, y: 15, r: 15, filled: true
|
238
|
+
subject.circle x: 15, y: 15, r: 12, filled: true, color: 0
|
239
|
+
subject.ellipse x: 15, y: 15, a: 10, b: 9
|
240
|
+
subject.ellipse x: 15, y: 15, a: 5, b: 7
|
241
|
+
assert_equal ELLIPSE_CIRCLE_FB, subject.framebuffers[0]
|
242
|
+
end
|
243
|
+
|
244
|
+
TEXT_FB = [0, 0, 1, 1, 127, 1, 1, 0, 56, 84, 84, 84, 24, 0, 72, 84, 84, 84, 32, 0, 4, 63, 68, 64, 32, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 223, 223, 31, 223, 223, 255, 255, 127, 127, 127, 255, 255, 255, 127, 127, 127, 255, 255, 127, 31, 127, 255, 255, 255, 255, 255, 31, 255, 255, 255, 255, 255, 255, 255, 240, 255, 255, 255, 248, 245, 245, 245, 252, 255, 246, 245, 245, 245, 251, 255, 255, 248, 247, 247, 251, 255, 255, 255, 250, 255, 255, 255]
|
245
|
+
|
246
|
+
def test_text
|
247
|
+
# Regular text
|
248
|
+
subject.text_cursor = 1,7
|
249
|
+
subject.text "Test!"
|
250
|
+
|
251
|
+
# Fill bottom half
|
252
|
+
subject.rectangle x1: 0, y1: 16, x2: 31, y2: 31, filled: true
|
253
|
+
|
254
|
+
# Knockout text
|
255
|
+
subject.text_cursor = 1,28
|
256
|
+
subject.text "Test!", color: 0
|
257
|
+
assert_equal TEXT_FB, subject.framebuffers[0]
|
258
|
+
end
|
259
|
+
|
260
|
+
ROTATE_FB = [0, 124, 18, 17, 18, 124, 0, 127, 73, 73, 73, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 62, 34, 34, 20, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 40, 68, 68, 124, 68, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 72, 136, 72, 62, 0]
|
261
|
+
|
262
|
+
def test_rotate
|
263
|
+
4.times do
|
264
|
+
subject.text_cursor = 0,7
|
265
|
+
subject.text "A"
|
266
|
+
subject.rotate(90)
|
267
|
+
end
|
268
|
+
subject.text_cursor = 6,7
|
269
|
+
subject.text "B"
|
270
|
+
assert_equal ROTATE_FB, subject.framebuffers[0]
|
271
|
+
end
|
272
|
+
|
273
|
+
REFLECT_FB = [0, 124, 18, 17, 18, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 41, 25, 9, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 144, 144, 144, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
274
|
+
|
275
|
+
def test_reflect
|
276
|
+
# Horizontally flipped, top right
|
277
|
+
subject.reflect(:x)
|
278
|
+
subject.text_cursor = 0,7
|
279
|
+
subject.text "R"
|
280
|
+
subject.reflect(:x)
|
281
|
+
|
282
|
+
# Vertically flipped, bottom left
|
283
|
+
subject.reflect(:y)
|
284
|
+
subject.text_cursor = 0,7
|
285
|
+
subject.text "P"
|
286
|
+
subject.reflect(:y)
|
287
|
+
|
288
|
+
# Restored
|
289
|
+
subject.text_cursor = 0,7
|
290
|
+
subject.text "A"
|
291
|
+
assert_equal REFLECT_FB, subject.framebuffers[0]
|
292
|
+
end
|
293
|
+
|
294
|
+
FONT_8X16_FB = [0, 0, 255, 255, 192, 192, 192, 192, 192, 192, 255, 255, 0, 0, 0, 0, 48, 48, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 63, 63, 0, 0, 0, 0, 0, 0, 63, 63, 0, 0, 0, 0, 48, 48, 63, 63, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 24, 8, 8, 248, 8, 8, 24, 0, 8, 248, 136, 136, 232, 8, 16, 0, 0, 112, 136, 8, 8, 8, 56, 0, 24, 8, 8, 248, 8, 8, 24, 0, 0, 0, 32, 63, 32, 0, 0, 0, 32, 63, 32, 32, 35, 32, 24, 0, 0, 56, 32, 33, 33, 34, 28, 0, 0, 0, 32, 63, 32, 0, 0, 0]
|
295
|
+
|
296
|
+
def test_font
|
297
|
+
subject.text_cursor = 0,31
|
298
|
+
subject.font = :bmp_8x16
|
299
|
+
subject.text "TEST"
|
300
|
+
|
301
|
+
subject.text_cursor = 0,15
|
302
|
+
subject.font = :bmp_6x8
|
303
|
+
subject.font_scale = 2
|
304
|
+
subject.text "Hi!"
|
305
|
+
end
|
306
|
+
end
|
@@ -7,18 +7,45 @@ class HD44780Test < Minitest::Test
|
|
7
7
|
|
8
8
|
def part
|
9
9
|
@part ||= Denko::Display::HD44780.new cols: 16, rows: 2,
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
board: board,
|
11
|
+
pins: {
|
12
|
+
rs: 8, enable: 9,
|
13
|
+
d4: 4, d5: 5, d6: 6, d7: 7
|
14
|
+
}
|
13
15
|
end
|
14
|
-
|
16
|
+
|
15
17
|
def test_pin_validation
|
16
18
|
# Only given one pin out of d0-d3.
|
17
19
|
assert_raises do
|
18
20
|
Denko::Display::HD44780.new board: board, pins: { rs: 12, enable: 11,
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
d4: 5, d5: 4, d6: 3, d7: 2, d3: 1
|
22
|
+
}
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_rw
|
28
|
+
@part = Denko::Display::HD44780.new cols: 16, rows: 2,
|
29
|
+
board: board,
|
30
|
+
pins: {
|
31
|
+
rs: 8, enable: 9, rw: 3,
|
32
|
+
d4: 4, d5: 5, d6: 6, d7: 7
|
33
|
+
}
|
34
|
+
|
35
|
+
assert_equal board.low, @part.rw.state
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def test_backlight
|
40
|
+
@part = Denko::Display::HD44780.new cols: 16, rows: 2,
|
41
|
+
board: board,
|
42
|
+
pins: {
|
43
|
+
rs: 8, enable: 9, backlight: 3,
|
44
|
+
d4: 4, d5: 5, d6: 6, d7: 7
|
45
|
+
}
|
46
|
+
|
47
|
+
assert_equal Denko::LED::Base, @part.backlight.class
|
48
|
+
assert_equal board.high, @part.backlight.state
|
22
49
|
end
|
23
50
|
|
24
51
|
def test_write4
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class BoardMock < Denko::Board
|
4
|
+
# Fake EEPROM
|
5
|
+
def eeprom_stub
|
6
|
+
@eeprom_stub ||= Array.new(eeprom_length){255}
|
7
|
+
end
|
8
|
+
|
9
|
+
def eeprom_read(start_address, length)
|
10
|
+
# Pack it up like a string coming from the board and update.
|
11
|
+
string = eeprom_stub[start_address, length].map{ |x| x.to_s }.join(",")
|
12
|
+
self.update("254:#{start_address}-#{string}\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
def eeprom_write(start_address, bytes)
|
16
|
+
eeprom_stub[start_address, bytes.length] = bytes
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class EEPROMBoardTest < Minitest::Test
|
21
|
+
def board
|
22
|
+
@board ||= BoardMock.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def part
|
26
|
+
@part ||= board.eeprom
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_pin_ee
|
30
|
+
assert_equal part.pin, 254
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_individual_read_write
|
34
|
+
assert_equal 255, part[20]
|
35
|
+
part[20] = 111
|
36
|
+
assert_equal 111, part[20]
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_range_read_write
|
40
|
+
data = [15, 23, 50, 12, 11]
|
41
|
+
index = 11
|
42
|
+
part[index] = data
|
43
|
+
assert_equal data, part[index..(index+data.length-1)]
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Minimal implementation of Minitest for mruby.
|
2
|
+
# Only handles #assert, #refute, and #assert_equal.
|
3
|
+
module Minitest
|
4
|
+
class AssertionError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
class Test
|
8
|
+
@@test_count = 0
|
9
|
+
@@failures = []
|
10
|
+
@@errors = []
|
11
|
+
@@assertions = 0
|
12
|
+
|
13
|
+
def self.run_all_tests
|
14
|
+
@@start_time = Time.now
|
15
|
+
|
16
|
+
test_classes = []
|
17
|
+
ObjectSpace.each_object(Class) do |klass|
|
18
|
+
test_classes << klass if (klass < Minitest::Test && klass != Minitest::Test)
|
19
|
+
end
|
20
|
+
|
21
|
+
test_classes.each { |c| c.run_tests }
|
22
|
+
|
23
|
+
@@finish_time = Time.now
|
24
|
+
|
25
|
+
report_results
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run_tests
|
29
|
+
test_methods = instance_methods.select { |method| method.to_s.start_with?("test_") }
|
30
|
+
|
31
|
+
test_methods.each do |test_method|
|
32
|
+
@@test_count += 1
|
33
|
+
test_instance = new
|
34
|
+
|
35
|
+
begin
|
36
|
+
test_instance.setup if test_instance.respond_to?(:setup)
|
37
|
+
test_instance.send(test_method)
|
38
|
+
print "."
|
39
|
+
rescue => e
|
40
|
+
if e.is_a?(AssertionError)
|
41
|
+
@@failures << "#{self.name}##{test_method}: #{e.message}"
|
42
|
+
print "F"
|
43
|
+
else
|
44
|
+
@@errors << "#{self.name}##{test_method}: #{e.class} - #{e.message}"
|
45
|
+
print "E"
|
46
|
+
end
|
47
|
+
ensure
|
48
|
+
begin
|
49
|
+
test_instance.teardown if test_instance.respond_to?(:teardown)
|
50
|
+
rescue => e
|
51
|
+
@@errors << "#{self.name}##{test_method} (teardown): #{e.class} - #{e.message}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.report_results
|
58
|
+
puts "\n\nFinished in #{(@@finish_time - @@start_time).round(6)}s"
|
59
|
+
|
60
|
+
puts "#{@@test_count} tests, #{@@assertions} assertions, #{@@failures.length} failures, #{@@errors.length} errors"
|
61
|
+
|
62
|
+
unless @@failures.empty?
|
63
|
+
puts "\nFailures:"
|
64
|
+
@@failures.each_with_index do |failure, i|
|
65
|
+
puts "#{i + 1}) #{failure}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
unless @@errors.empty?
|
70
|
+
puts "\nErrors:"
|
71
|
+
@@errors.each_with_index do |error, i|
|
72
|
+
puts "#{i + 1}) #{error}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def assert(condition, message = "Assertion failed")
|
78
|
+
@@assertions += 1
|
79
|
+
raise AssertionError.new(message) unless condition
|
80
|
+
end
|
81
|
+
|
82
|
+
def refute(condition, message = "Refutation failed - expected falsy value")
|
83
|
+
@@assertions += 1
|
84
|
+
raise AssertionError.new(message) if condition
|
85
|
+
end
|
86
|
+
|
87
|
+
def assert_equal(expected, actual, message = nil)
|
88
|
+
@@assertions += 1
|
89
|
+
unless expected == actual
|
90
|
+
msg = message || "Expected #{expected.inspect}, got #{actual.inspect}"
|
91
|
+
raise AssertionError.new(msg)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Stub out require_relative to avoid issues.
|
2
|
+
def require_relative(*args)
|
3
|
+
end
|
4
|
+
|
5
|
+
# Load minimal Minitest clone for mruby.
|
6
|
+
minitest_source = "#{File.dirname(__FILE__)}/mruby_minitest.rb"
|
7
|
+
eval(File.read(minitest_source))
|
8
|
+
|
9
|
+
# Test Display::Canvas.
|
10
|
+
canvas_test = "#{File.dirname(__FILE__)}/../display/canvas_test.rb"
|
11
|
+
eval(File.read(canvas_test))
|
12
|
+
|
13
|
+
Minitest::Test.run_all_tests
|
data/test/i2c/bus_test.rb
CHANGED
@@ -9,74 +9,137 @@ class I2CBusTest < Minitest::Test
|
|
9
9
|
@board ||= BoardMock.new
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
@
|
12
|
+
def bus
|
13
|
+
@bus ||= Denko::I2C::Bus.new(board: board)
|
14
14
|
end
|
15
15
|
|
16
16
|
def peripheral
|
17
|
-
@peripheral ||= I2CPeripheralBase.new(bus:
|
17
|
+
@peripheral ||= I2CPeripheralBase.new(bus: bus, address: 0x30)
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_initialize
|
21
|
-
assert_equal
|
22
|
-
assert_equal 0,
|
23
|
-
refute_nil
|
21
|
+
assert_equal [], bus.found_devices
|
22
|
+
assert_equal 0, bus.i2c_index
|
23
|
+
refute_nil bus.callbacks[:bus_controller]
|
24
24
|
|
25
|
-
|
26
|
-
assert_equal 10,
|
27
|
-
|
28
|
-
part3 = Denko::I2C::Bus.new(board: board, i2c_index: 11)
|
29
|
-
assert_equal 11, part3.i2c_index
|
25
|
+
bus2 = Denko::I2C::Bus.new(board: board, index: 10)
|
26
|
+
assert_equal 10, bus2.i2c_index
|
30
27
|
end
|
31
28
|
|
32
|
-
def
|
29
|
+
def test_search_result_string
|
33
30
|
# Reject 0s created by leading and trailing colons.
|
34
|
-
board.
|
31
|
+
board.inject_component_update(bus, ":48:50:")
|
32
|
+
bus.search
|
33
|
+
assert_equal [0x30, 0x32], bus.found_devices
|
34
|
+
end
|
35
35
|
|
36
|
-
|
37
|
-
board.
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
def test_search_resul_array
|
37
|
+
board.inject_component_update(bus, [0, 0x30, 0x32])
|
38
|
+
bus.search
|
39
|
+
assert_equal [0x30, 0x32], bus.found_devices
|
40
|
+
end
|
41
41
|
|
42
|
-
|
42
|
+
def test_search_result_empty
|
43
|
+
board.inject_component_update(bus, ":")
|
44
|
+
bus.search
|
45
|
+
assert_equal [], bus.found_devices
|
43
46
|
end
|
44
47
|
|
45
48
|
def test_write
|
46
49
|
mock = Minitest::Mock.new.expect :call, nil, [0, 0x30, [0x01, 0x02], 100000, false]
|
50
|
+
|
47
51
|
board.stub(:i2c_write, mock) do
|
48
|
-
|
52
|
+
bus.write 0x30, [0x01, 0x02]
|
49
53
|
end
|
50
54
|
mock.verify
|
51
55
|
end
|
52
56
|
|
53
|
-
def
|
54
|
-
board.
|
57
|
+
def test_read_string
|
58
|
+
board.inject_component_update(bus, "48-255,0,255,0,255,0")
|
59
|
+
mock = Minitest::Mock.new.expect :call, nil, [0, 0x32, 0x03, 6, 100000, false]
|
55
60
|
|
61
|
+
board.stub(:i2c_read, mock) do
|
62
|
+
bus.read 0x32, 0x03, 6
|
63
|
+
end
|
64
|
+
mock.verify
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_read_array
|
68
|
+
board.inject_component_update(bus, [48,255,0,255,0,255,0])
|
56
69
|
mock = Minitest::Mock.new.expect :call, nil, [0, 0x32, 0x03, 6, 100000, false]
|
70
|
+
|
57
71
|
board.stub(:i2c_read, mock) do
|
58
|
-
|
72
|
+
bus.read 0x32, 0x03, 6
|
59
73
|
end
|
60
74
|
mock.verify
|
61
75
|
end
|
62
76
|
|
63
|
-
def
|
64
|
-
board.
|
77
|
+
def test_read_without_register
|
78
|
+
board.inject_component_update(bus, "48-255,127")
|
79
|
+
mock = Minitest::Mock.new.expect :call, nil, [0, 0x30, nil, 2, 100000, false]
|
65
80
|
|
66
|
-
mock = Minitest::Mock.new.expect :call, nil, [0, 0x32, 0x03, 6, 100000, false]
|
67
81
|
board.stub(:i2c_read, mock) do
|
68
|
-
|
82
|
+
bus.read 0x30, nil, 2
|
83
|
+
end
|
84
|
+
mock.verify
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_updates_peripherals_string
|
88
|
+
mock = Minitest::Mock.new.expect :call, nil, [[255, 127]]
|
89
|
+
|
90
|
+
peripheral.stub(:update, mock) do
|
91
|
+
bus.send(:update, "48-255,127")
|
92
|
+
bus.send(:update, "50-128,0")
|
69
93
|
end
|
70
94
|
mock.verify
|
71
95
|
end
|
72
96
|
|
73
|
-
def
|
97
|
+
def test_updates_peripherals_array
|
74
98
|
mock = Minitest::Mock.new.expect :call, nil, [[255, 127]]
|
75
99
|
|
76
100
|
peripheral.stub(:update, mock) do
|
77
|
-
|
78
|
-
|
101
|
+
bus.send(:update, [0x30, 255, 127])
|
102
|
+
bus.send(:update, [0x32, 128, 0])
|
103
|
+
end
|
104
|
+
mock.verify
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_ignores_updates_for_non_matching_addresses
|
108
|
+
# mock should not receive any calls
|
109
|
+
mock = Minitest::Mock.new
|
110
|
+
|
111
|
+
peripheral.stub(:update, mock) do
|
112
|
+
bus.send(:update, "49-255,127")
|
79
113
|
end
|
80
114
|
mock.verify
|
81
115
|
end
|
116
|
+
|
117
|
+
def test_handles_empty_data_gracefully
|
118
|
+
bus.send(:update, "48-")
|
119
|
+
bus.send(:update, "48")
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_handles_malformed_string_data
|
123
|
+
bus.send(:update, "invalid-data")
|
124
|
+
bus.send(:update, "")
|
125
|
+
bus.send(:update, nil)
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_same_address_fails
|
129
|
+
peripheral
|
130
|
+
assert_raises { I2CPeripheralBase.new(bus: bus, address: 0x30) }
|
131
|
+
end
|
132
|
+
|
133
|
+
# Should split up Subcomponents behavior and test there?
|
134
|
+
def test_component_management
|
135
|
+
count = bus.components.length
|
136
|
+
new_peripheral = I2CPeripheralBase.new(bus: bus, address: 0x40)
|
137
|
+
|
138
|
+
assert_equal count+1, bus.components.length
|
139
|
+
assert_includes bus.components, new_peripheral
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_found_devices_not_writable
|
143
|
+
assert_raises { bus.found_devices = nil }
|
144
|
+
end
|
82
145
|
end
|