denko 0.13.6 → 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_avr.yml → build_atmega_avr.yml} +19 -18
- data/.github/workflows/{build_megaavr.yml → build_atmega_megaavr.yml} +19 -18
- data/.github/workflows/{build_sam3x.yml → build_atsam3x.yml} +18 -17
- data/.github/workflows/{build_samd.yml → build_atsamd21.yml} +19 -18
- data/.github/workflows/build_esp32.yml +19 -18
- data/.github/workflows/build_esp32c3.yml +58 -0
- data/.github/workflows/build_esp32c6.yml +59 -0
- data/.github/workflows/build_esp32h2.yml +58 -0
- data/.github/workflows/build_esp32s2.yml +59 -0
- data/.github/workflows/build_esp32s3.yml +59 -0
- data/.github/workflows/build_esp8266.yml +16 -15
- data/.github/workflows/build_ra4m1.yml +17 -16
- data/.github/workflows/build_rp2040.yml +19 -17
- data/.github/workflows/ruby.yml +20 -20
- data/CHANGELOG.md +398 -11
- data/DEPS_CLI.md +16 -16
- data/DEPS_IDE.md +39 -39
- data/MICROCONTROLLERS.md +103 -0
- data/PERIPHERALS.md +178 -0
- data/README.md +73 -58
- data/Rakefile +1 -1
- data/build +1 -1
- data/denko.gemspec +11 -3
- data/lib/denko/analog_io/ads1100.rb +127 -0
- data/lib/denko/analog_io/ads1115.rb +8 -25
- data/lib/denko/analog_io/ads1118.rb +12 -27
- data/lib/denko/analog_io/ads111x.rb +39 -21
- data/lib/denko/analog_io/input.rb +29 -55
- data/lib/denko/analog_io/input_helper.rb +42 -0
- data/lib/denko/analog_io/joystick.rb +87 -0
- data/lib/denko/analog_io/output.rb +5 -5
- data/lib/denko/analog_io/potentiometer.rb +3 -9
- data/lib/denko/analog_io.rb +22 -7
- data/lib/denko/behaviors/board_proxy.rb +13 -1
- data/lib/denko/behaviors/bus_controller.rb +3 -1
- data/lib/denko/behaviors/bus_controller_addressed.rb +1 -0
- data/lib/denko/behaviors/bus_peripheral.rb +3 -4
- data/lib/denko/behaviors/bus_peripheral_addressed.rb +8 -6
- data/lib/denko/behaviors/callbacks.rb +18 -14
- data/lib/denko/behaviors/component.rb +12 -14
- data/lib/denko/behaviors/input_pin.rb +14 -15
- data/lib/denko/behaviors/lifecycle.rb +51 -0
- data/lib/denko/behaviors/listener.rb +9 -3
- data/lib/denko/behaviors/multi_pin.rb +22 -20
- data/lib/denko/behaviors/output_pin.rb +9 -4
- data/lib/denko/behaviors/poller.rb +11 -2
- data/lib/denko/behaviors/reader.rb +109 -21
- data/lib/denko/behaviors/single_pin.rb +3 -4
- data/lib/denko/behaviors/state.rb +24 -13
- data/lib/denko/behaviors/subcomponents.rb +72 -12
- data/lib/denko/behaviors/threaded.rb +19 -8
- data/lib/denko/behaviors.rb +36 -22
- data/lib/denko/board/core.rb +36 -18
- data/lib/denko/board/eeprom.rb +1 -1
- data/lib/denko/board/i2c.rb +15 -15
- data/lib/denko/board/i2c_bit_bang.rb +53 -0
- data/lib/denko/board/infrared.rb +6 -6
- data/lib/denko/board/led_array.rb +6 -5
- data/lib/denko/board/map.rb +6 -2
- data/lib/denko/board/one_wire.rb +3 -3
- data/lib/denko/board/spi.rb +35 -30
- data/lib/denko/board/spi_bit_bang.rb +14 -15
- data/lib/denko/board.rb +41 -36
- data/lib/denko/connection/binary_echo.rb +17 -0
- data/lib/denko/connection/flow_control.rb +12 -16
- data/lib/denko/connection/handshake.rb +2 -0
- data/lib/denko/connection/serial.rb +5 -5
- data/lib/denko/digital_io/button.rb +4 -0
- data/lib/denko/digital_io/c_bit_bang.rb +15 -0
- data/lib/denko/digital_io/input.rb +4 -5
- data/lib/denko/digital_io/output.rb +19 -10
- data/lib/denko/digital_io/pcf8574.rb +114 -0
- data/lib/denko/digital_io/relay.rb +2 -0
- data/lib/denko/digital_io/rotary_encoder.rb +83 -61
- data/lib/denko/digital_io.rb +24 -5
- 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 +152 -105
- 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 +38 -0
- 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 -168
- 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 -3
- 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/helpers/mutex_stub.rb +13 -0
- data/lib/denko/helpers.rb +6 -0
- data/lib/denko/i2c/bit_bang.rb +32 -0
- data/lib/denko/i2c/bus.rb +8 -36
- data/lib/denko/i2c/bus_common.rb +50 -0
- data/lib/denko/i2c/peripheral.rb +32 -19
- data/lib/denko/i2c.rb +17 -2
- data/lib/denko/led/apa102.rb +42 -30
- data/lib/denko/led/base.rb +13 -2
- data/lib/denko/led/rgb.rb +18 -14
- data/lib/denko/led/seven_segment.rb +24 -9
- data/lib/denko/led/ws2812.rb +10 -7
- data/lib/denko/led.rb +17 -8
- data/lib/denko/message.rb +5 -0
- data/lib/denko/motor/{stepper.rb → a3967.rb} +12 -15
- data/lib/denko/motor/l298.rb +11 -10
- data/lib/denko/motor/servo.rb +37 -15
- data/lib/denko/motor.rb +16 -3
- data/lib/denko/one_wire/bus.rb +31 -23
- data/lib/denko/one_wire/bus_enumerator.rb +25 -14
- data/lib/denko/one_wire/helper.rb +4 -2
- data/lib/denko/one_wire/peripheral.rb +0 -3
- data/lib/denko/one_wire.rb +18 -5
- data/lib/denko/pulse_io/buzzer.rb +11 -9
- data/lib/denko/pulse_io/{ir_transmitter.rb → ir_output.rb} +6 -5
- data/lib/denko/pulse_io/pwm_output.rb +94 -15
- data/lib/denko/pulse_io.rb +17 -3
- data/lib/denko/rtc/ds3231.rb +13 -14
- data/lib/denko/rtc.rb +14 -1
- data/lib/denko/sensor/aht.rb +35 -38
- data/lib/denko/sensor/bme280.rb +76 -92
- data/lib/denko/sensor/bmp180.rb +46 -48
- data/lib/denko/sensor/dht.rb +34 -7
- data/lib/denko/sensor/ds18b20.rb +41 -34
- data/lib/denko/sensor/hcsr04.rb +7 -5
- data/lib/denko/sensor/hdc1080.rb +174 -0
- data/lib/denko/sensor/helper.rb +37 -0
- data/lib/denko/sensor/htu21d.rb +57 -57
- data/lib/denko/sensor/htu31d.rb +36 -36
- data/lib/denko/sensor/jsnsr04t.rb +49 -0
- data/lib/denko/sensor/qmp6988.rb +34 -48
- data/lib/denko/sensor/rcwl9620.rb +3 -5
- data/lib/denko/sensor/sht3x.rb +27 -24
- data/lib/denko/sensor/sht4x.rb +125 -0
- data/lib/denko/sensor/vl53l0x.rb +58 -0
- data/lib/denko/sensor.rb +33 -16
- data/lib/denko/spi/base_register.rb +25 -21
- data/lib/denko/spi/bit_bang.rb +17 -51
- data/lib/denko/spi/bus.rb +15 -29
- data/lib/denko/spi/bus_common.rb +33 -0
- data/lib/denko/spi/input_register.rb +37 -31
- data/lib/denko/spi/output_register.rb +33 -39
- data/lib/denko/spi/peripheral.rb +81 -14
- data/lib/denko/spi.rb +21 -6
- data/lib/denko/uart/bit_bang.rb +7 -30
- data/lib/denko/uart/common.rb +33 -0
- data/lib/denko/uart/hardware.rb +10 -34
- data/lib/denko/uart.rb +16 -2
- data/lib/denko/version.rb +1 -1
- data/lib/denko.rb +23 -16
- data/lib/denko_cli/generator.rb +2 -2
- data/lib/denko_cli/packages.rb +8 -10
- data/lib/denko_cli/targets.rb +13 -13
- data/lib/denko_cli/targets.txt +23 -24
- data/lib/denko_cli/usage.txt +1 -1
- data/src/denko_ethernet.ino +0 -14
- data/src/denko_serial.ino +0 -14
- data/src/denko_wifi.ino +6 -15
- data/src/lib/Denko.cpp +65 -16
- data/src/lib/Denko.h +46 -30
- data/src/lib/DenkoCoreIO.cpp +57 -102
- data/src/lib/DenkoDefines.h +32 -46
- data/src/lib/DenkoI2C.cpp +54 -45
- data/src/lib/DenkoI2CBB.cpp +238 -0
- data/src/lib/DenkoIROut.cpp +12 -7
- data/src/lib/DenkoLEDArray.cpp +29 -13
- data/src/lib/DenkoSPI.cpp +36 -33
- data/src/lib/DenkoSPIBB.cpp +19 -20
- data/target.yml +37 -2
- data/test/analog_io/input_test.rb +1 -1
- data/test/analog_io/potentiometer_test.rb +12 -12
- data/test/behaviors/board_proxy_test.rb +1 -1
- data/test/behaviors/bus_peripheral_test.rb +4 -4
- data/test/behaviors/callbacks_test.rb +28 -10
- data/test/behaviors/component_test.rb +32 -14
- data/test/behaviors/input_pin_test.rb +14 -9
- data/test/behaviors/multi_pin_test.rb +14 -4
- data/test/behaviors/output_pin_test.rb +11 -8
- data/test/behaviors/poller_test.rb +1 -0
- data/test/behaviors/reader_test.rb +3 -2
- data/test/behaviors/subcomponents_test.rb +22 -2
- data/test/board/board_test.rb +9 -9
- data/test/board/core_test.rb +15 -11
- data/test/board/i2c_test.rb +39 -33
- data/test/board/infrared_test.rb +1 -1
- data/test/board/message_test.rb +17 -11
- data/test/board/one_wire_test.rb +25 -14
- data/test/board/spi_test.rb +45 -29
- data/test/digital_io/button_test.rb +15 -0
- data/test/digital_io/input_test.rb +2 -2
- data/test/digital_io/relay_test.rb +18 -0
- data/test/digital_io/rotary_encoder_test.rb +80 -60
- 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 +108 -29
- data/test/i2c/peripheral_test.rb +38 -19
- data/test/led/apa102_test.rb +24 -0
- data/test/led/base_test.rb +2 -1
- data/test/led/rgb_test.rb +9 -9
- data/test/led/seven_segment_test.rb +7 -7
- data/test/motor/{stepper_test.rb → a3967_test.rb} +4 -4
- data/test/motor/servo_test.rb +1 -1
- data/test/one_wire/bus_enumerator_test.rb +1 -1
- data/test/one_wire/bus_test.rb +43 -35
- data/test/one_wire/peripheral_test.rb +5 -17
- data/test/pulse_io/buzzer_test.rb +7 -4
- data/test/pulse_io/{ir_transmitter_test.rb → ir_output_test.rb} +15 -10
- data/test/pulse_io/pwm_output_test.rb +74 -18
- data/test/rtc/ds3231_test.rb +13 -14
- data/test/sensor/dht_test.rb +12 -12
- data/test/sensor/ds18b20_test.rb +4 -8
- data/test/spi/bitbang_test.rb +27 -0
- data/test/spi/bus_test.rb +24 -34
- data/test/spi/input_register_test.rb +17 -17
- data/test/spi/output_register_test.rb +10 -28
- data/test/spi/peripheral_test.rb +73 -0
- data/test/test_helper.rb +44 -121
- data/vendor/board-maps/BoardMap.h +678 -54
- data/vendor/board-maps/lib/header_parser.rb +12 -2
- data/vendor/board-maps/yaml/ADAFRUIT_CAMERA_ESP32S3.yml +2 -2
- data/vendor/board-maps/yaml/ADAFRUIT_FEATHER_ESP32C6.yml +15 -0
- data/vendor/board-maps/yaml/ADAFRUIT_FEATHER_ESP32_V2.yml +1 -1
- data/vendor/board-maps/yaml/ADAFRUIT_FEATHER_RP2040_ADALOGGER.yml +44 -0
- data/vendor/board-maps/yaml/ADAFRUIT_QTPY_ESP32C3.yml +1 -0
- data/vendor/board-maps/yaml/ADAFRUIT_QTPY_ESP32S2.yml +1 -0
- data/vendor/board-maps/yaml/ADAFRUIT_QTPY_ESP32S3_N4R2.yml +1 -0
- data/vendor/board-maps/yaml/ADAFRUIT_QTPY_ESP32S3_NOPSRAM.yml +1 -0
- data/vendor/board-maps/yaml/ADAFRUIT_QTPY_ESP32_PICO.yml +1 -0
- data/vendor/board-maps/yaml/ALFREDO_NOU3.yml +2 -0
- data/vendor/board-maps/yaml/AMKEN_BB.yml +48 -0
- data/vendor/board-maps/yaml/AMKEN_ES.yml +48 -0
- data/vendor/board-maps/yaml/AMKEN_REVELOP.yml +48 -0
- data/vendor/board-maps/yaml/AMKEN_REVELOP_PLUS.yml +48 -0
- data/vendor/board-maps/yaml/ASL_CAN_X2.yml +41 -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/BLING.yml +25 -0
- data/vendor/board-maps/yaml/BRIDGETEK_IDM2040_7A.yml +48 -0
- data/vendor/board-maps/yaml/Bee_Motion_Mini.yml +13 -1
- data/vendor/board-maps/yaml/Breadstick_Raspberry.yml +31 -0
- 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/DFROBOT_BEETLE_ESP32C6.yml +8 -0
- data/vendor/board-maps/yaml/DFROBOT_FIREBEETLE_2_ESP32C6.yml +20 -0
- data/vendor/board-maps/yaml/DFROBOT_FIREBEETLE_ESP32.yml +46 -0
- data/vendor/board-maps/yaml/DPTECHNICS_WALTER.yml +39 -0
- data/vendor/board-maps/yaml/EDGES3D.yml +25 -0
- data/vendor/board-maps/yaml/ELECROW_CROWPANEL_7.yml +8 -0
- data/vendor/board-maps/yaml/ESP32C2_DEV.yml +12 -0
- data/vendor/board-maps/yaml/ESP32C3_DEVKIT_LIPO.yml +14 -0
- data/vendor/board-maps/yaml/ESP32C6_DEV.yml +14 -0
- data/vendor/board-maps/yaml/ESP32C6_EVB.yml +15 -0
- data/vendor/board-maps/yaml/ESP32C6_QWIIC_POCKET.yml +15 -0
- data/vendor/board-maps/yaml/ESP32C6_THING_PLUS.yml +14 -0
- data/vendor/board-maps/yaml/ESP32H2_DEV.yml +12 -0
- data/vendor/board-maps/yaml/ESP32H2_DEVKIT_LIPO.yml +12 -0
- data/vendor/board-maps/yaml/ESP32P4_DEV.yml +35 -0
- data/vendor/board-maps/yaml/{RMP.yml → ESP32S2_DEVKIT_LIPO.yml} +1 -1
- data/vendor/board-maps/yaml/ESP32S2_DEVKIT_LIPO_USB.yml +43 -0
- data/vendor/board-maps/yaml/ESP32S3_DEVKIT_LIPO.yml +42 -0
- data/vendor/board-maps/yaml/ESP32S3_POWERFEATHER.yml +22 -0
- data/vendor/board-maps/yaml/ESP32_2432S028R.yml +14 -0
- data/vendor/board-maps/yaml/ESP32_SBC_FABGL.yml +35 -0
- data/vendor/board-maps/yaml/EVN_ALPHA.yml +48 -0
- data/vendor/board-maps/yaml/FEATHERS3.yml +1 -1
- data/vendor/board-maps/yaml/FEATHERS3NEO.yml +32 -0
- data/vendor/board-maps/yaml/FRI3D_2024_ESP32S3.yml +43 -0
- data/vendor/board-maps/yaml/GEEKBLE_ESP32C3.yml +13 -0
- data/vendor/board-maps/yaml/GEEKBLE_NANO_ESP32S3.yml +25 -0
- data/vendor/board-maps/yaml/HELTEC_CAPSULE_SENSOR_V3.yml +43 -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/HELTEC_WIFI_LORA_32_V3.yml +42 -0
- data/vendor/board-maps/yaml/HELTEC_WIRELESS_BRIDGE.yml +8 -0
- data/vendor/board-maps/yaml/HELTEC_WIRELESS_MINI_SHELL.yml +13 -0
- data/vendor/board-maps/yaml/HELTEC_WIRELESS_PAPER.yml +42 -0
- data/vendor/board-maps/yaml/HELTEC_WIRELESS_SHELL_V3.yml +42 -0
- data/vendor/board-maps/yaml/HELTEC_WIRELESS_STICK_LITE_V3.yml +30 -0
- data/vendor/board-maps/yaml/HELTEC_WIRELESS_TRACKER.yml +41 -0
- data/vendor/board-maps/yaml/HT_DE01.yml +42 -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/IMBRIOS_LOGSENS_V1P1.yml +1 -1
- 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/LILYGO_T3S3_LR1121.yml +9 -0
- data/vendor/board-maps/yaml/LILYGO_T3S3_SX1262.yml +9 -0
- data/vendor/board-maps/yaml/LILYGO_T3S3_SX1276.yml +9 -0
- data/vendor/board-maps/yaml/LILYGO_T3S3_SX1278.yml +9 -0
- data/vendor/board-maps/yaml/LILYGO_T3S3_SX1280.yml +9 -0
- data/vendor/board-maps/yaml/LILYGO_T3S3_SX1280PA.yml +8 -0
- data/vendor/board-maps/yaml/LILYGO_T_ETH_LITE.yml +21 -0
- data/vendor/board-maps/yaml/LOLIN_C3_MINI.yml +0 -1
- data/vendor/board-maps/yaml/LOLIN_C3_PICO.yml +13 -0
- data/vendor/board-maps/yaml/LOLIN_S3.yml +1 -0
- data/vendor/board-maps/yaml/LOLIN_S3_MINI_PRO.yml +40 -0
- data/vendor/board-maps/yaml/Lion_Bit_Dev_Board.yml +0 -2
- data/vendor/board-maps/yaml/M5STACK_CAPSULE.yml +8 -0
- data/vendor/board-maps/yaml/M5STACK_CARDPUTER.yml +8 -0
- data/vendor/board-maps/yaml/M5STACK_DIAL.yml +8 -0
- data/vendor/board-maps/yaml/M5STACK_DINMETER.yml +8 -0
- data/vendor/board-maps/yaml/M5STACK_FIRE.yml +1 -2
- data/vendor/board-maps/yaml/M5STACK_NANOC6.yml +17 -0
- data/vendor/board-maps/yaml/M5STACK_PAPER.yml +9 -0
- data/vendor/board-maps/yaml/M5STACK_POE_CAM.yml +5 -0
- data/vendor/board-maps/yaml/M5STACK_STAMP_C3.yml +13 -0
- data/vendor/board-maps/yaml/M5STACK_STAMP_S3.yml +4 -0
- data/vendor/board-maps/yaml/{M5Stick_C.yml → M5STACK_STICKC.yml} +0 -1
- data/vendor/board-maps/yaml/M5STACK_STICKC_PLUS.yml +9 -0
- data/vendor/board-maps/yaml/M5STACK_STICKC_PLUS2.yml +9 -0
- data/vendor/board-maps/yaml/M5STACK_TOUGH.yml +9 -0
- data/vendor/board-maps/yaml/M5STACK_UNIT_CAM.yml +10 -0
- data/vendor/board-maps/yaml/M5STACK_UNIT_CAMS3.yml +4 -0
- data/vendor/board-maps/yaml/M5Stack_ATOM.yml +0 -1
- data/vendor/board-maps/yaml/MAKERGO_C3_SUPERMINI.yml +14 -0
- data/vendor/board-maps/yaml/MARBLE_PICO.yml +48 -0
- data/vendor/board-maps/yaml/METEHOCA_AKANA_R1.yml +46 -0
- data/vendor/board-maps/yaml/NAMINO_BIANCO.yml +13 -0
- data/vendor/board-maps/yaml/NEBULAS3.yml +0 -1
- data/vendor/board-maps/yaml/NEWSAN_ARCHI.yml +48 -0
- data/vendor/board-maps/yaml/NOLOGO_ESP32C3_SUPER_MINI.yml +14 -0
- data/vendor/board-maps/yaml/NOLOGO_ESP32S3_PICO.yml +12 -0
- data/vendor/board-maps/yaml/OLIMEX_RP2040_PICO30_16MB.yml +48 -0
- data/vendor/board-maps/yaml/OLIMEX_RP2040_PICO30_2MB.yml +48 -0
- data/vendor/board-maps/yaml/OMGS3.yml +25 -0
- data/vendor/board-maps/yaml/OPTA_ANALOG.yml +7 -0
- data/vendor/board-maps/yaml/OPTA_DIGITAL.yml +5 -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/PINTRONIX_PINMAX.yml +42 -0
- data/vendor/board-maps/yaml/REDPILL_ESP32S3.yml +0 -1
- data/vendor/board-maps/yaml/SENSEBOX_MCU_ESP32S2.yml +12 -0
- data/vendor/board-maps/yaml/SPARKFUN_ESP32S3_THING_PLUS.yml +13 -0
- data/vendor/board-maps/yaml/SPARKFUN_MICROMOD_RP2040.yml +48 -0
- data/vendor/board-maps/yaml/SPARKFUN_PRO_MICRO_ESP32C3.yml +24 -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.yml +31 -0
- data/vendor/board-maps/yaml/THINGPULSE_EPULSE_FEATHER_C6.yml +14 -0
- data/vendor/board-maps/yaml/TINYC6.yml +25 -0
- 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/UPESY_EDU_ESP32.yml +28 -0
- data/vendor/board-maps/yaml/UPESY_ESP32C3_BASIC.yml +13 -0
- data/vendor/board-maps/yaml/UPESY_ESP32C3_MINI.yml +12 -0
- data/vendor/board-maps/yaml/UPESY_ESP32S3_BASIC.yml +42 -0
- data/vendor/board-maps/yaml/VIRALINK_GATE32_01.yml +6 -0
- data/vendor/board-maps/yaml/VIRALINK_GATE32_11.yml +7 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32S3_TOUCH_LCD_128.yml +8 -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/WAVESHARE_RP2040_MATRIX.yml +48 -0
- data/vendor/board-maps/yaml/WAVESHARE_RP2040_ONE.yml +1 -0
- data/vendor/board-maps/yaml/WAVESHARE_RP2040_PIZERO.yml +47 -0
- data/vendor/board-maps/yaml/WAVESHARE_RP2040_ZERO.yml +1 -0
- data/vendor/board-maps/yaml/WEACT_STUDIO_ESP32C3.yml +14 -0
- data/vendor/board-maps/yaml/WS_ESP32_S3_MATRIX.yml +38 -0
- data/vendor/board-maps/yaml/WT32_SC01_PLUS.yml +7 -0
- data/vendor/board-maps/yaml/WiFiduinoV2.yml +1 -0
- data/vendor/board-maps/yaml/XIAO_ESP32C3.yml +0 -1
- data/vendor/board-maps/yaml/XIAO_ESP32C6.yml +22 -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
- data/vendor/board-maps/yaml/unphone9.yml +8 -0
- metadata +259 -105
- data/.vscode/settings.json +0 -5
- data/.vscode/tasks.json +0 -20
- data/HARDWARE.md +0 -264
- data/benchmarks/i2c_ssd1306_refresh.rb +0 -84
- data/examples/advanced/m5_env.rb +0 -48
- data/examples/advanced/rotary_encoder_mac_volume.rb +0 -48
- data/examples/advanced/ssd1306_time_temp_rh.rb +0 -48
- data/examples/analog_io/ads1115.rb +0 -57
- data/examples/analog_io/ads1118.rb +0 -73
- data/examples/analog_io/dac_loopback.rb +0 -34
- data/examples/analog_io/input.rb +0 -55
- data/examples/connection/tcp.rb +0 -34
- data/examples/digital_io/button.rb +0 -13
- data/examples/digital_io/rotary_encoder.rb +0 -26
- data/examples/display/hd44780.png +0 -0
- data/examples/display/hd44780.rb +0 -39
- data/examples/display/ssd1306.rb +0 -40
- data/examples/display/ssd1306_s2_pico.rb +0 -29
- data/examples/eeprom/built_in.rb +0 -32
- data/examples/i2c/search.rb +0 -55
- data/examples/led/apa102_bounce.rb +0 -33
- data/examples/led/apa102_breathe.rb +0 -45
- data/examples/led/builtin_blink.rb +0 -12
- data/examples/led/seven_segment_char_echo.rb +0 -15
- data/examples/led/ws2812_bounce.rb +0 -32
- data/examples/led/ws2812_builtin_blink.rb +0 -21
- data/examples/motor/l298.rb +0 -43
- data/examples/motor/servo.rb +0 -16
- data/examples/motor/stepper.png +0 -0
- data/examples/motor/stepper.rb +0 -43
- data/examples/pulse_io/buzzer.rb +0 -30
- data/examples/pulse_io/ir_transmitter.rb +0 -55
- data/examples/rtc/ds3231.rb +0 -48
- data/examples/sensor/aht10.rb +0 -19
- data/examples/sensor/aht20.rb +0 -19
- data/examples/sensor/bme280.rb +0 -38
- data/examples/sensor/bmp180.rb +0 -22
- data/examples/sensor/dht.rb +0 -24
- data/examples/sensor/ds18b20.rb +0 -58
- data/examples/sensor/generic_pir.rb +0 -25
- data/examples/sensor/hcsr04.rb +0 -14
- data/examples/sensor/htu21d.rb +0 -54
- data/examples/sensor/htu31d.rb +0 -35
- data/examples/sensor/neat_tph_readings.rb +0 -26
- data/examples/sensor/qmp6988.rb +0 -53
- data/examples/sensor/rcwl9620.rb +0 -15
- data/examples/sensor/sht3x.rb +0 -34
- data/examples/spi/input_register.rb +0 -50
- data/examples/spi/output_register.rb +0 -49
- data/examples/spi/ssd_through_register.rb +0 -40
- data/examples/spi/two_registers.rb +0 -46
- data/examples/uart/bit_bang_read.rb +0 -16
- data/examples/uart/bit_bang_write.rb +0 -16
- data/examples/uart/board_passthrough.rb +0 -34
- data/examples/uart/hardware_loopback.rb +0 -16
- data/lib/denko/analog_io/sensor.rb +0 -6
- data/lib/denko/eeprom/built_in.rb +0 -69
- data/lib/denko/fonts.rb +0 -106
- data/lib/denko/sensor/virtual.rb +0 -42
- data/src/lib/DenkoIROutESP.cpp +0 -26
- data/test/eeprom/built_in_test.rb +0 -61
- 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 -64
- data/tutorial/03-potentiometer/potentiometer.fzz +0 -0
- data/tutorial/03-potentiometer/potentiometer.pdf +0 -0
- data/tutorial/03-potentiometer/potentiometer.rb +0 -62
- 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 -66
- 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
- data/vendor/board-maps/yaml/STAMP_S3.yml +0 -8
- /data/vendor/board-maps/yaml/{BRIDGETEK_IDM2040-7A.yml → BRIDGETEK_IDM2040_43A.yml} +0 -0
- /data/vendor/board-maps/yaml/{heltec_wifi_32_lora_V3.yml → HELTEC_WIRELESS_STICK_V3.yml} +0 -0
- /data/vendor/board-maps/yaml/{M5Stack_Core_ESP32.yml → M5STACK_CORE.yml} +0 -0
- /data/vendor/board-maps/yaml/{M5Stamp_Pico.yml → M5STACK_STAMP_PICO.yml} +0 -0
- /data/vendor/board-maps/yaml/{M5Stack-Timer-CAM.yml → M5STACK_TIMER_CAM.yml} +0 -0
data/lib/denko/display/canvas.rb
CHANGED
@@ -1,181 +1,283 @@
|
|
1
1
|
module Denko
|
2
2
|
module Display
|
3
3
|
class Canvas
|
4
|
-
|
5
|
-
|
6
|
-
attr_reader :columns, :rows, :framebuffer
|
7
|
-
|
8
|
-
def initialize(columns, rows)
|
9
|
-
raise ArgumentError, "bitmap height must be divisible by 8" unless (rows % 8 == 0)
|
10
|
-
|
11
|
-
@columns = columns
|
12
|
-
@rows = rows
|
4
|
+
attr_reader :columns, :rows, :framebuffer, :framebuffers, :colors
|
13
5
|
|
6
|
+
def initialize(columns, rows, colors: 1)
|
7
|
+
@columns = columns
|
8
|
+
@rows = rows
|
9
|
+
@rows = ((rows / 8.0).ceil * 8) if (rows % 8 != 0)
|
14
10
|
# Use a byte array for the framebuffer. Each byte is 8 pixels arranged vertically.
|
15
11
|
# Each slice @columns long represents an area @columns wide * 8 pixels tall.
|
16
|
-
@bytes
|
17
|
-
|
12
|
+
@bytes = @columns * (@rows / 8)
|
13
|
+
|
14
|
+
# Framebuffer setup. 1-bit framebuffer for each color.
|
15
|
+
# Works for mono LCDs and OLEDs, or mono/multi-color e-paper.
|
16
|
+
@colors = colors
|
17
|
+
@framebuffers = []
|
18
|
+
@colors.times { @framebuffers << Array.new(@bytes) { 0x00 } }
|
19
|
+
# Only first framebuffer is used for mono displays.
|
20
|
+
@framebuffer = @framebuffers.first
|
21
|
+
|
22
|
+
# Default drawing state
|
23
|
+
self.font = Denko::Display::Font::BMP_6X8
|
24
|
+
@font_scale = 1
|
25
|
+
@current_color = 1
|
26
|
+
|
27
|
+
# Transformation state
|
28
|
+
@swap_xy = false
|
29
|
+
@invert_x = false
|
30
|
+
@invert_y = false
|
31
|
+
@rotation = 0
|
32
|
+
calculate_bounds
|
33
|
+
end
|
34
|
+
|
35
|
+
def clear
|
36
|
+
@framebuffers.each { |fb| fb.fill 0x00 }
|
18
37
|
end
|
19
38
|
|
20
39
|
def fill
|
21
|
-
|
40
|
+
# Clear all buffers, then fill the first one, which is the only
|
41
|
+
# one for mono displays, black for multi-color e-paper.
|
42
|
+
clear
|
43
|
+
@framebuffers.first.fill 0xFF
|
22
44
|
end
|
23
45
|
|
24
|
-
|
25
|
-
|
46
|
+
#
|
47
|
+
# PIXEL OPERATIONS
|
48
|
+
#
|
49
|
+
def _get_pixel(x, y)
|
50
|
+
byte = ((y / 8) * @columns) + x
|
51
|
+
bit = y % 8
|
52
|
+
|
53
|
+
# Go through framebuffers and return that color when bit is set.
|
54
|
+
@framebuffers.each_with_index do |fb, index|
|
55
|
+
return index+1 if ((fb[byte] >> bit) & 0b1 == 1)
|
56
|
+
end
|
57
|
+
|
58
|
+
# If bit wasn't set in any framebuffer, color is 0.
|
59
|
+
return 0
|
26
60
|
end
|
27
61
|
|
28
|
-
def get_pixel(x
|
29
|
-
|
30
|
-
bit = y % 8
|
31
|
-
(@framebuffer[byte] >> bit) & 0b00000001
|
62
|
+
def get_pixel(x:, y:)
|
63
|
+
_get_pixel(x, y)
|
32
64
|
end
|
33
65
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
66
|
+
def _set_pixel(x, y, color=current_color)
|
67
|
+
xt = (@invert_x) ? @x_max - x : x
|
68
|
+
yt = (@invert_y) ? @y_max - y : y
|
69
|
+
if (@swap_xy)
|
70
|
+
tt = xt
|
71
|
+
xt = yt
|
72
|
+
yt = tt
|
73
|
+
end
|
74
|
+
|
75
|
+
# Bounds check
|
76
|
+
return nil if (xt < 0 || yt < 0 || xt > @columns-1 || yt > @rows -1)
|
77
|
+
return nil if (color < 0) || (color > colors)
|
78
|
+
|
79
|
+
byte = ((yt / 8) * @columns) + xt
|
80
|
+
bit = yt % 8
|
81
|
+
|
82
|
+
# Set pixel bit in that color's buffer. Clear in others.
|
83
|
+
# When color == 0, clears in all buffers and sets in none.
|
84
|
+
for i in 1..colors
|
85
|
+
if (color == i)
|
86
|
+
@framebuffers[i-1][byte] |= (0b1 << bit)
|
87
|
+
else
|
88
|
+
@framebuffers[i-1][byte] &= ~(0b1 << bit)
|
89
|
+
end
|
90
|
+
end
|
38
91
|
end
|
39
92
|
|
40
|
-
def
|
41
|
-
|
42
|
-
bit = y % 8
|
43
|
-
@framebuffer[byte] &= ~(0b1 << bit)
|
93
|
+
def set_pixel(x:, y:, color:current_color)
|
94
|
+
_set_pixel(x, y, color)
|
44
95
|
end
|
45
96
|
|
46
|
-
def
|
47
|
-
(
|
97
|
+
def clear_pixel(x:, y:)
|
98
|
+
_set_pixel(x, y, 0)
|
48
99
|
end
|
49
100
|
|
50
|
-
#
|
51
|
-
|
101
|
+
#
|
102
|
+
# LINE
|
103
|
+
#
|
104
|
+
def _line(x1, y1, x2, y2, color=current_color)
|
52
105
|
# Deltas in each axis.
|
53
106
|
dy = y2 - y1
|
54
107
|
dx = x2 - x1
|
55
108
|
|
56
|
-
#
|
109
|
+
# Optimize vertical lines, and avoid division by 0.
|
57
110
|
if (dx == 0)
|
58
111
|
# Ensure y1 < y2.
|
59
112
|
y1, y2 = y2, y1 if (y2 < y1)
|
60
|
-
(y1..y2).each
|
61
|
-
pixel(x1, y, color)
|
62
|
-
end
|
113
|
+
(y1..y2).each { |y| _set_pixel(x1, y, color) }
|
63
114
|
return
|
64
115
|
end
|
65
116
|
|
66
|
-
|
67
|
-
|
68
|
-
# Gradient magnitude <= 45 degrees: find y for each x.
|
69
|
-
if (gradient >= -1) && (gradient <= 1)
|
117
|
+
# Optimize horizontal lines.
|
118
|
+
if (dy == 0)
|
70
119
|
# Ensure x1 < x2.
|
71
|
-
x1,
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
y_step = gradient
|
76
|
-
(x1..x2).each do |x|
|
77
|
-
pixel(x, y.round, color)
|
78
|
-
y = y + y_step
|
79
|
-
end
|
120
|
+
x1, x2 = x2, x1 if (x2 < x1)
|
121
|
+
(x1..x2).each { |x| _set_pixel(x, y1, color) }
|
122
|
+
return
|
123
|
+
end
|
80
124
|
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
125
|
+
# Based on Bresenham's line algorithm
|
126
|
+
# Slope calculations
|
127
|
+
step_axis = (dx.abs > dy.abs) ? :x : :y
|
128
|
+
step_count = (step_axis == :x) ? dx.abs : dy.abs
|
129
|
+
x_step = (dx > 0) ? 1 : -1
|
130
|
+
y_step = (dy > 0) ? 1 : -1
|
131
|
+
|
132
|
+
# Error calculations
|
133
|
+
error_step = (step_axis == :x) ? dy.abs : dx.abs
|
134
|
+
error_threshold = (step_axis == :x) ? dx.abs : dy.abs
|
135
|
+
|
136
|
+
x = x1
|
137
|
+
y = y1
|
138
|
+
error = 0
|
139
|
+
(0..step_count).each do |i|
|
140
|
+
_set_pixel(x, y, color)
|
141
|
+
|
142
|
+
if (step_axis == :x)
|
143
|
+
x += x_step
|
144
|
+
error += error_step
|
145
|
+
if (error >= error_threshold)
|
146
|
+
y += y_step
|
147
|
+
error -= error_threshold
|
148
|
+
end
|
149
|
+
else
|
150
|
+
y += y_step
|
151
|
+
error += error_step
|
152
|
+
if (error >= error_threshold)
|
153
|
+
x += x_step
|
154
|
+
error -= error_threshold
|
155
|
+
end
|
92
156
|
end
|
93
157
|
end
|
94
158
|
end
|
95
159
|
|
96
|
-
|
97
|
-
|
98
|
-
line(x, y, x+width, y, color)
|
99
|
-
line(x+width, y, x+width, y+height, color)
|
100
|
-
line(x+width, y+height, x, y+height, color)
|
101
|
-
line(x, y+height, x, y, color)
|
160
|
+
def line(x1:, y1:, x2:, y2:, color:current_color)
|
161
|
+
_line(x1, y1, x2, y2, color)
|
102
162
|
end
|
103
163
|
|
104
|
-
#
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
164
|
+
#
|
165
|
+
# RECTANGLE & SQUARE
|
166
|
+
#
|
167
|
+
def _rectangle(x1, y1, x2, y2, filled=false, color=current_color)
|
168
|
+
if filled
|
169
|
+
y1, y2 = y2, y1 if (y2 < y1)
|
170
|
+
(y1..y2).each { |y| _line(x1, y, x2, y, color) }
|
171
|
+
else
|
172
|
+
_line(x1, y1, x2, y1, color)
|
173
|
+
_line(x2, y1, x2, y2, color)
|
174
|
+
_line(x2, y2, x1, y2, color)
|
175
|
+
_line(x1, y2, x1, y1, color)
|
110
176
|
end
|
111
177
|
end
|
112
178
|
|
113
|
-
|
114
|
-
|
115
|
-
|
179
|
+
def rectangle(x1:nil, y1:nil, x2:nil, y2:nil, x:nil, y:nil, w:nil, h:nil, filled:false, color:current_color)
|
180
|
+
if (x || y || w || h) && (x1 || x2 || y1 || y2)
|
181
|
+
raise ArgumentError, "#rectangle accepts x:, y:, w:, h: OR x1:, y1:, x2:, y2: not a combination of both"
|
182
|
+
end
|
183
|
+
|
184
|
+
if (w && h)
|
185
|
+
x1 = x
|
186
|
+
x2 = x1 + w
|
187
|
+
x2 += 1 if (x2 < x1)
|
188
|
+
x2 -= 1 if (x1 < x2)
|
189
|
+
|
190
|
+
y1 = y
|
191
|
+
y2 = y1 + h
|
192
|
+
y2 += 1 if (y2 < y1)
|
193
|
+
y2 -= 1 if (y1 < y2)
|
194
|
+
end
|
195
|
+
|
196
|
+
_rectangle(x1, y1, x2, y2, filled, color)
|
197
|
+
end
|
198
|
+
|
199
|
+
def square(x:, y:, size:, filled:false, color:current_color)
|
200
|
+
rectangle(x: x, y: y, w: size, h: size, filled: filled, color: color)
|
201
|
+
end
|
202
|
+
|
203
|
+
#
|
204
|
+
# PATH, POLYGON & TRIANGLE
|
205
|
+
#
|
206
|
+
def _path(points, color=current_color)
|
116
207
|
start = points[0]
|
117
208
|
(1..points.length-1).each do |i|
|
118
209
|
finish = points[i]
|
119
|
-
|
210
|
+
_line(start[0], start[1], finish[0], finish[1], color)
|
120
211
|
start = finish
|
121
212
|
end
|
122
213
|
end
|
123
214
|
|
124
|
-
|
125
|
-
|
126
|
-
points << points[0]
|
127
|
-
path(points)
|
215
|
+
def path(points, color:current_color)
|
216
|
+
_path(points, color)
|
128
217
|
end
|
129
218
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
219
|
+
def _polygon(points, filled=false, color=current_color)
|
220
|
+
if filled
|
221
|
+
# Get all the X and Y coordinates from the points as floats.
|
222
|
+
coords_x = points.map { |point| point.first.to_f }
|
223
|
+
coords_y = points.map { |point| point.last.to_f }
|
224
|
+
|
225
|
+
# Get Y bounds of the polygon to limit rows.
|
226
|
+
y_min = coords_y.min.to_i
|
227
|
+
y_max = coords_y.max.to_i
|
228
|
+
|
229
|
+
# Cast horizontal ray on each row, storing nodes where it intersects polygon edges.
|
230
|
+
(y_min..y_max).each do |y|
|
231
|
+
nodes = []
|
232
|
+
i = 0
|
233
|
+
j = points.count - 1
|
234
|
+
|
235
|
+
while (i < points.count) do
|
236
|
+
# First condition excludes horizontal edges.
|
237
|
+
# Second and third check for +ve and -ve intersection respectively.
|
238
|
+
if (coords_y[i] != coords_y[j]) && ((coords_y[i] < y && coords_y[j] >= y) || (coords_y[j] < y && coords_y[i] >= y))
|
239
|
+
# Interoplate to find the intersection point (node).
|
240
|
+
nodes << (coords_x[i] + (y - coords_y[i]) / (coords_y[j] - coords_y[i]) * (coords_x[j] - coords_x[i])).round
|
241
|
+
end
|
242
|
+
j = i
|
243
|
+
i += 1
|
149
244
|
end
|
150
|
-
|
151
|
-
i += 1
|
152
|
-
end
|
153
|
-
nodes = nodes.sort
|
245
|
+
nodes = nodes.sort
|
154
246
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
247
|
+
# Take pairs of nodes and fill between them.
|
248
|
+
# This ignores the spaces between odd then even nodes (eg. 1->2), which are outside the polygon.
|
249
|
+
nodes.each_slice(2) do |pair|
|
250
|
+
_line(pair.first, y, pair.last, y, color) if pair.length == 2
|
251
|
+
end
|
160
252
|
end
|
161
253
|
end
|
162
254
|
|
163
|
-
# Stroke
|
164
|
-
|
255
|
+
# Stroke regardless, since floating point math misses thin areas of fill.
|
256
|
+
_path(points, color)
|
257
|
+
# Close open path by adding a line between the first and last points.
|
258
|
+
_line(points[-1][0], points[-1][1], points[0][0], points[0][1], color)
|
259
|
+
end
|
260
|
+
|
261
|
+
def polygon(points, filled:false, color:current_color)
|
262
|
+
_polygon(points, filled, color)
|
165
263
|
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
264
|
+
|
265
|
+
def _triangle(x1, y1, x2, y2, x3, y3, filled=false, color=current_color)
|
266
|
+
if filled
|
267
|
+
_polygon([[x1,y1], [x2,y2], [x3,y3]], filled, color)
|
268
|
+
else
|
269
|
+
_line(x1, y1, x2, y2, color)
|
270
|
+
_line(x2, y2, x3, y3, color)
|
271
|
+
_line(x3, y3, x1, y1, color)
|
272
|
+
end
|
170
273
|
end
|
171
274
|
|
172
|
-
|
173
|
-
|
174
|
-
filled_polygon([[x1,y1], [x2,y2], [x3,y3]], color)
|
275
|
+
def triangle(x1:, y1:, x2:, y2:, x3:, y3:, filled:false, color:current_color)
|
276
|
+
_triangle(x1, y1, x2, y2, x3, y3, filled, color)
|
175
277
|
end
|
176
278
|
|
177
|
-
|
178
|
-
|
279
|
+
def _ellipse(x_center, y_center, a, b, filled=false, color=current_color)
|
280
|
+
# Midpoint ellipse / circle based on Bresenham's circle algorithm.
|
179
281
|
# Start position
|
180
282
|
x = -a
|
181
283
|
y = 0
|
@@ -193,9 +295,15 @@ module Denko
|
|
193
295
|
# Since starting at max negative X, continue until x is 0.
|
194
296
|
while (x <= 0)
|
195
297
|
if filled
|
196
|
-
|
298
|
+
# Fill left and right quadrants in single line, alternating +ve and -ve y.
|
299
|
+
_line(x_center - x, y_center + y, x_center + x, y_center + y, color)
|
300
|
+
_line(x_center - x, y_center - y, x_center + x, y_center - y, color)
|
197
301
|
else
|
198
|
-
|
302
|
+
# Stroke quadrants in order as if y-axis is reversed and going counter-clockwise from +ve X.
|
303
|
+
_set_pixel(x_center - x, y_center - y, color)
|
304
|
+
_set_pixel(x_center + x, y_center - y, color)
|
305
|
+
_set_pixel(x_center + x, y_center + y, color)
|
306
|
+
_set_pixel(x_center - x, y_center + y, color)
|
199
307
|
end
|
200
308
|
|
201
309
|
e2 = 2 * e1
|
@@ -214,69 +322,154 @@ module Denko
|
|
214
322
|
# Continue if y hasn't reached the vertical size.
|
215
323
|
while (y < b)
|
216
324
|
y += 1
|
217
|
-
|
218
|
-
|
325
|
+
_set_pixel(x_center, y_center + y, color)
|
326
|
+
_set_pixel(x_center, y_center - y, color)
|
219
327
|
end
|
220
328
|
end
|
221
329
|
|
222
|
-
def
|
223
|
-
|
224
|
-
pixel(x_center - x, y_center - y, color)
|
225
|
-
pixel(x_center + x, y_center - y, color)
|
226
|
-
pixel(x_center + x, y_center + y, color)
|
227
|
-
pixel(x_center - x, y_center + y, color)
|
330
|
+
def ellipse(x:, y:, a:, b:, filled:false, color:current_color)
|
331
|
+
_ellipse(x, y, a, b, filled, color)
|
228
332
|
end
|
229
333
|
|
230
|
-
def
|
231
|
-
|
232
|
-
line(x_center - x, y_center - y, x_center + x, y_center - y, color)
|
334
|
+
def circle(x:, y:, r:, filled:false, color:current_color)
|
335
|
+
_ellipse(x, y, r, r, filled, color)
|
233
336
|
end
|
234
337
|
|
235
|
-
|
236
|
-
|
338
|
+
#
|
339
|
+
# BITMAP TEXT
|
340
|
+
#
|
341
|
+
def text(str, color:current_color)
|
342
|
+
str.to_s.split("").each { |char| draw_char(char, color: color) }
|
237
343
|
end
|
238
344
|
|
239
|
-
def
|
240
|
-
|
345
|
+
def draw_char(char, color:current_color)
|
346
|
+
# 0th character in font is SPACE. Offset ASCII code and show ? if character doesn't exist in font.
|
347
|
+
index = char.ord - 32
|
348
|
+
index = 31 if (index < 0 || index > @font_last_character)
|
349
|
+
char_map = @font_characters[index]
|
350
|
+
|
351
|
+
# Offset by scaled height, since bottom left of char starts at text cursor.
|
352
|
+
x = text_cursor[0]
|
353
|
+
y = text_cursor[1] + 1 - (@font_height * @font_scale)
|
354
|
+
|
355
|
+
# Draw it
|
356
|
+
_draw_char(char_map, x, y, @font_width, @font_scale, color)
|
357
|
+
|
358
|
+
# Increment the text cursor, scaling width.
|
359
|
+
self.text_cursor[0] += @font_width * @font_scale
|
241
360
|
end
|
242
361
|
|
243
|
-
def
|
244
|
-
|
362
|
+
def _draw_char(byte_array, x, y, width, scale, color=current_color)
|
363
|
+
byte_array.each_slice(width) do |slice|
|
364
|
+
slice.each_with_index do |byte, col_offset|
|
365
|
+
8.times do |bit|
|
366
|
+
# Don't do anything if this bit isn't set in the font.
|
367
|
+
if (((byte >> bit) & 0b1) == 1)
|
368
|
+
scale.times do |x_offset|
|
369
|
+
scale.times do |y_offset|
|
370
|
+
_set_pixel(x + (col_offset * scale) + x_offset, y + (bit * scale) + y_offset, color)
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
y = y + (8 * scale)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
#
|
381
|
+
# DRAWING STATE
|
382
|
+
#
|
383
|
+
def current_color=(color)
|
384
|
+
raise Argument error, "color must be within (0..#{colors})" if (color < 0) || (color > colors)
|
385
|
+
@current_color = color
|
245
386
|
end
|
246
387
|
|
388
|
+
attr_reader :current_color
|
389
|
+
|
390
|
+
DEFAULT_TEXT_CURSOR = [0, 7]
|
391
|
+
|
247
392
|
def text_cursor
|
248
|
-
@text_cursor ||=
|
393
|
+
@text_cursor ||= DEFAULT_TEXT_CURSOR
|
249
394
|
end
|
250
395
|
|
251
|
-
def
|
252
|
-
|
253
|
-
print_char(char)
|
254
|
-
end
|
396
|
+
def text_cursor=(array=DEFAULT_TEXT_CURSOR)
|
397
|
+
@text_cursor = array
|
255
398
|
end
|
256
399
|
|
257
|
-
def
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
400
|
+
def font=(font)
|
401
|
+
if font.class == Symbol
|
402
|
+
@font = Display::Font.const_get(font.to_s.upcase)
|
403
|
+
else
|
404
|
+
@font = font
|
405
|
+
end
|
262
406
|
|
263
|
-
|
407
|
+
@font_height = @font[:height]
|
408
|
+
@font_width = @font[:width]
|
409
|
+
@font_characters = @font[:characters]
|
410
|
+
@font_last_character = @font_characters.length - 1
|
264
411
|
end
|
265
412
|
|
266
|
-
def
|
267
|
-
#
|
268
|
-
|
269
|
-
|
413
|
+
def font_scale=(scale)
|
414
|
+
raise ArgumentError, "#font_scale must be a positive integer" unless (scale.class == Integer) && scale > 0
|
415
|
+
@font_scale = scale
|
416
|
+
end
|
270
417
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
418
|
+
attr_reader :font, :font_scale
|
419
|
+
|
420
|
+
#
|
421
|
+
# TRANSFORMATION
|
422
|
+
#
|
423
|
+
def rotate(degrees=180)
|
424
|
+
raise ArgumentError, "Canvas can only be rotated in multiples of 90 degrees" unless (degrees % 90 == 0)
|
425
|
+
old_rotation = @rotation
|
426
|
+
@rotation = (old_rotation + degrees) % 360
|
427
|
+
change = (@rotation - old_rotation) % 360
|
428
|
+
|
429
|
+
(change / 90).times do
|
430
|
+
@swap_xy = !@swap_xy
|
431
|
+
if (!@invert_x && !@invert_y)
|
432
|
+
@invert_x = true
|
433
|
+
@invert_y = false
|
434
|
+
elsif (@invert_x && !@invert_y)
|
435
|
+
@invert_x = true
|
436
|
+
@invert_y = true
|
437
|
+
elsif (@invert_x && @invert_y)
|
438
|
+
@invert_x = false
|
439
|
+
@invert_y = true
|
440
|
+
elsif (!@invert_x && @invert_y)
|
441
|
+
@invert_x = false
|
442
|
+
@invert_y = false
|
443
|
+
end
|
275
444
|
end
|
445
|
+
calculate_bounds
|
446
|
+
end
|
276
447
|
|
277
|
-
|
278
|
-
|
448
|
+
def reflect(axis)
|
449
|
+
raise ArgumentError "Canvas can only be reflected in :x or :y axis" unless [:x, :y].include? (axis)
|
450
|
+
(axis == :x) ? @invert_x = !@invert_x : @invert_y = !@invert_y
|
451
|
+
calculate_bounds
|
279
452
|
end
|
453
|
+
|
454
|
+
def reflect_x
|
455
|
+
reflect(:x)
|
456
|
+
end
|
457
|
+
|
458
|
+
def reflect_y
|
459
|
+
reflect(:y)
|
460
|
+
end
|
461
|
+
|
462
|
+
def calculate_bounds
|
463
|
+
if @swap_xy
|
464
|
+
@x_max = @rows - 1
|
465
|
+
@y_max = @columns - 1
|
466
|
+
else
|
467
|
+
@x_max = @columns - 1
|
468
|
+
@y_max = @rows - 1
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
attr_reader :x_max, :y_max
|
280
473
|
end
|
281
474
|
end
|
282
475
|
end
|