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.
Files changed (344) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build_atmega_avr.yml +2 -1
  3. data/.github/workflows/build_atmega_megaavr.yml +2 -1
  4. data/.github/workflows/build_atsam3x.yml +1 -0
  5. data/.github/workflows/build_atsamd21.yml +2 -1
  6. data/.github/workflows/build_esp32.yml +4 -2
  7. data/.github/workflows/build_esp32c3.yml +4 -3
  8. data/.github/workflows/build_esp32c6.yml +4 -2
  9. data/.github/workflows/build_esp32h2.yml +4 -2
  10. data/.github/workflows/build_esp32s2.yml +4 -2
  11. data/.github/workflows/build_esp32s3.yml +4 -2
  12. data/.github/workflows/build_esp8266.yml +2 -1
  13. data/.github/workflows/build_ra4m1.yml +1 -0
  14. data/.github/workflows/build_rp2040.yml +4 -3
  15. data/.github/workflows/ruby.yml +1 -1
  16. data/CHANGELOG.md +203 -0
  17. data/DEPS_CLI.md +16 -16
  18. data/DEPS_IDE.md +31 -30
  19. data/MICROCONTROLLERS.md +103 -0
  20. data/PERIPHERALS.md +178 -0
  21. data/README.md +28 -21
  22. data/denko.gemspec +6 -1
  23. data/lib/denko/analog_io/ads1118.rb +5 -5
  24. data/lib/denko/analog_io/ads111x.rb +23 -19
  25. data/lib/denko/analog_io/joystick.rb +87 -0
  26. data/lib/denko/analog_io/potentiometer.rb +1 -5
  27. data/lib/denko/analog_io.rb +22 -8
  28. data/lib/denko/behaviors/bus_controller.rb +2 -1
  29. data/lib/denko/behaviors/bus_peripheral.rb +1 -1
  30. data/lib/denko/behaviors/callbacks.rb +18 -16
  31. data/lib/denko/behaviors/component.rb +0 -4
  32. data/lib/denko/behaviors/lifecycle.rb +1 -1
  33. data/lib/denko/behaviors/listener.rb +9 -3
  34. data/lib/denko/behaviors/multi_pin.rb +4 -6
  35. data/lib/denko/behaviors/poller.rb +11 -2
  36. data/lib/denko/behaviors/reader.rb +109 -21
  37. data/lib/denko/behaviors/single_pin.rb +2 -4
  38. data/lib/denko/behaviors/state.rb +18 -13
  39. data/lib/denko/behaviors/threaded.rb +19 -8
  40. data/lib/denko/behaviors.rb +36 -23
  41. data/lib/denko/board/eeprom.rb +1 -1
  42. data/lib/denko/board/i2c.rb +1 -1
  43. data/lib/denko/board/i2c_bit_bang.rb +9 -5
  44. data/lib/denko/board/map.rb +6 -2
  45. data/lib/denko/board/one_wire.rb +3 -3
  46. data/lib/denko/board/spi.rb +30 -30
  47. data/lib/denko/board/spi_bit_bang.rb +8 -11
  48. data/lib/denko/board.rb +6 -3
  49. data/lib/denko/connection/flow_control.rb +1 -1
  50. data/lib/denko/connection/serial.rb +5 -5
  51. data/lib/denko/digital_io/output.rb +12 -4
  52. data/lib/denko/digital_io/pcf8574.rb +114 -0
  53. data/lib/denko/digital_io/rotary_encoder.rb +10 -6
  54. data/lib/denko/digital_io.rb +24 -6
  55. data/lib/denko/display/canvas.rb +350 -157
  56. data/lib/denko/display/font/bmp_5x7.rb +142 -0
  57. data/lib/denko/display/font/bmp_6x8.rb +142 -0
  58. data/lib/denko/display/font/bmp_8x16.rb +141 -0
  59. data/lib/denko/display/font.rb +22 -0
  60. data/lib/denko/display/hd44780.rb +24 -20
  61. data/lib/denko/display/il0373.rb +186 -0
  62. data/lib/denko/display/mono_oled.rb +193 -0
  63. data/lib/denko/display/pcd8544.rb +154 -0
  64. data/lib/denko/display/pixel_common.rb +83 -0
  65. data/lib/denko/display/sh1106.rb +17 -21
  66. data/lib/denko/display/sh1107.rb +10 -0
  67. data/lib/denko/display/spi_common.rb +35 -0
  68. data/lib/denko/display/spi_epaper_common.rb +30 -0
  69. data/lib/denko/display/ssd1306.rb +6 -228
  70. data/lib/denko/display/ssd1680.rb +14 -0
  71. data/lib/denko/display/ssd1681.rb +8 -0
  72. data/lib/denko/display/ssd168x.rb +227 -0
  73. data/lib/denko/display/st7302.rb +207 -0
  74. data/lib/denko/display/st7565.rb +166 -0
  75. data/lib/denko/display.rb +40 -4
  76. data/lib/denko/eeprom/at24c.rb +67 -0
  77. data/lib/denko/eeprom/board.rb +69 -0
  78. data/lib/denko/eeprom.rb +15 -1
  79. data/lib/denko/helpers/engine_check.rb +13 -0
  80. data/lib/denko/{mutex_stub.rb → helpers/mutex_stub.rb} +6 -0
  81. data/lib/denko/helpers.rb +6 -0
  82. data/lib/denko/i2c/bit_bang.rb +1 -0
  83. data/lib/denko/i2c/bus_common.rb +9 -4
  84. data/lib/denko/i2c/peripheral.rb +5 -1
  85. data/lib/denko/i2c.rb +17 -4
  86. data/lib/denko/led/apa102.rb +1 -3
  87. data/lib/denko/led/base.rb +5 -0
  88. data/lib/denko/led/rgb.rb +16 -10
  89. data/lib/denko/led/seven_segment.rb +1 -1
  90. data/lib/denko/led.rb +17 -8
  91. data/lib/denko/motor/{stepper.rb → a3967.rb} +1 -1
  92. data/lib/denko/motor/servo.rb +16 -6
  93. data/lib/denko/motor.rb +16 -3
  94. data/lib/denko/one_wire/bus.rb +20 -16
  95. data/lib/denko/one_wire/bus_enumerator.rb +25 -14
  96. data/lib/denko/one_wire/helper.rb +4 -2
  97. data/lib/denko/one_wire.rb +18 -5
  98. data/lib/denko/pulse_io/buzzer.rb +2 -6
  99. data/lib/denko/pulse_io/ir_output.rb +1 -5
  100. data/lib/denko/pulse_io/pwm_output.rb +56 -31
  101. data/lib/denko/pulse_io.rb +17 -3
  102. data/lib/denko/rtc/ds3231.rb +4 -3
  103. data/lib/denko/rtc.rb +14 -1
  104. data/lib/denko/sensor/aht.rb +16 -20
  105. data/lib/denko/sensor/bme280.rb +23 -36
  106. data/lib/denko/sensor/bmp180.rb +8 -13
  107. data/lib/denko/sensor/dht.rb +17 -7
  108. data/lib/denko/sensor/ds18b20.rb +5 -4
  109. data/lib/denko/sensor/hdc1080.rb +174 -0
  110. data/lib/denko/sensor/htu21d.rb +17 -6
  111. data/lib/denko/sensor/htu31d.rb +6 -5
  112. data/lib/denko/sensor/jsnsr04t.rb +49 -0
  113. data/lib/denko/sensor/qmp6988.rb +14 -30
  114. data/lib/denko/sensor/rcwl9620.rb +1 -0
  115. data/lib/denko/sensor/sht3x.rb +6 -5
  116. data/lib/denko/sensor/sht4x.rb +125 -0
  117. data/lib/denko/sensor/vl53l0x.rb +58 -0
  118. data/lib/denko/sensor.rb +33 -15
  119. data/lib/denko/spi/base_register.rb +11 -7
  120. data/lib/denko/spi/bus_common.rb +12 -15
  121. data/lib/denko/spi/input_register.rb +6 -6
  122. data/lib/denko/spi/output_register.rb +13 -4
  123. data/lib/denko/spi/peripheral.rb +82 -84
  124. data/lib/denko/spi.rb +20 -10
  125. data/lib/denko/uart/bit_bang.rb +2 -27
  126. data/lib/denko/uart/common.rb +33 -0
  127. data/lib/denko/uart/hardware.rb +1 -26
  128. data/lib/denko/uart.rb +16 -2
  129. data/lib/denko/version.rb +1 -1
  130. data/lib/denko.rb +22 -25
  131. data/lib/denko_cli/targets.rb +7 -7
  132. data/lib/denko_cli/targets.txt +19 -20
  133. data/src/lib/Denko.cpp +26 -13
  134. data/src/lib/Denko.h +4 -4
  135. data/src/lib/DenkoDefines.h +7 -26
  136. data/src/lib/DenkoLEDArray.cpp +1 -8
  137. data/src/lib/DenkoSPI.cpp +31 -29
  138. data/src/lib/DenkoSPIBB.cpp +12 -14
  139. data/test/analog_io/input_test.rb +1 -1
  140. data/test/analog_io/potentiometer_test.rb +2 -2
  141. data/test/behaviors/bus_peripheral_test.rb +4 -4
  142. data/test/behaviors/callbacks_test.rb +20 -10
  143. data/test/behaviors/component_test.rb +18 -8
  144. data/test/board/board_test.rb +9 -9
  145. data/test/board/one_wire_test.rb +25 -14
  146. data/test/board/spi_test.rb +31 -15
  147. data/test/digital_io/input_test.rb +2 -2
  148. data/test/display/canvas_test.rb +306 -0
  149. data/test/display/hd44780_test.rb +34 -7
  150. data/test/eeprom/board_test.rb +45 -0
  151. data/test/helpers/mruby_minitest.rb +95 -0
  152. data/test/helpers/mruby_runner.rb +13 -0
  153. data/test/i2c/bus_test.rb +93 -30
  154. data/test/i2c/peripheral_test.rb +2 -2
  155. data/test/led/apa102_test.rb +24 -0
  156. data/test/led/rgb_test.rb +4 -4
  157. data/test/motor/{stepper_test.rb → a3967_test.rb} +2 -2
  158. data/test/one_wire/bus_enumerator_test.rb +1 -1
  159. data/test/one_wire/bus_test.rb +42 -35
  160. data/test/one_wire/peripheral_test.rb +5 -17
  161. data/test/pulse_io/ir_output_test.rb +5 -0
  162. data/test/pulse_io/pwm_output_test.rb +10 -10
  163. data/test/rtc/ds3231_test.rb +3 -2
  164. data/test/sensor/dht_test.rb +11 -11
  165. data/test/spi/bitbang_test.rb +27 -0
  166. data/test/spi/bus_test.rb +19 -29
  167. data/test/spi/input_register_test.rb +2 -2
  168. data/test/spi/{peripheral_multi_pin_test.rb → peripheral_test.rb} +25 -5
  169. data/test/test_helper.rb +44 -124
  170. data/vendor/board-maps/BoardMap.h +264 -0
  171. data/vendor/board-maps/yaml/ALFREDO_NOU3.yml +2 -0
  172. data/vendor/board-maps/yaml/ATD143_S3.yml +1 -0
  173. data/vendor/board-maps/yaml/BHARATPI_A7672S_4G.yml +14 -0
  174. data/vendor/board-maps/yaml/BHARATPI_LORA.yml +14 -0
  175. data/vendor/board-maps/yaml/BHARATPI_NODE_WIFI.yml +14 -0
  176. data/vendor/board-maps/yaml/BPI_LEAF_S3.yml +0 -1
  177. data/vendor/board-maps/yaml/CEZERIO_DEV_ESP32C6.yml +14 -0
  178. data/vendor/board-maps/yaml/CEZERIO_MINI_DEV_ESP32C6.yml +12 -0
  179. data/vendor/board-maps/yaml/CIRCUITART_ZERO_S3.yml +71 -0
  180. data/vendor/board-maps/yaml/CODECELLC3.yml +13 -0
  181. data/vendor/board-maps/yaml/CYOBOT_V2_ESP32S3.yml +7 -0
  182. data/vendor/board-maps/yaml/EDGES3D.yml +25 -0
  183. data/vendor/board-maps/yaml/ESP32C6_DEV.yml +3 -4
  184. data/vendor/board-maps/yaml/ESP32C6_THING_PLUS.yml +0 -1
  185. data/vendor/board-maps/yaml/ESP32H2_DEV.yml +0 -1
  186. data/vendor/board-maps/yaml/ESP32H2_DEVKIT_LIPO.yml +0 -1
  187. data/vendor/board-maps/yaml/ESP32P4_DEV.yml +35 -0
  188. data/vendor/board-maps/yaml/ESP32S2_DEV.yml +0 -1
  189. data/vendor/board-maps/yaml/ESP32S2_DEVKIT_LIPO.yml +0 -1
  190. data/vendor/board-maps/yaml/ESP32S2_DEVKIT_LIPO_USB.yml +0 -1
  191. data/vendor/board-maps/yaml/ESP32_2432S028R.yml +14 -0
  192. data/vendor/board-maps/yaml/FEATHERS3.yml +1 -1
  193. data/vendor/board-maps/yaml/FRI3D_2024_ESP32S3.yml +43 -0
  194. data/vendor/board-maps/yaml/GEEKBLE_ESP32C3.yml +0 -1
  195. data/vendor/board-maps/yaml/GEEKBLE_NANO_ESP32S3.yml +25 -0
  196. data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_E290.yml +41 -0
  197. data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_E_213.yml +41 -0
  198. data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_T190.yml +41 -0
  199. data/vendor/board-maps/yaml/HUIDU_HD_WF2.yml +5 -0
  200. data/vendor/board-maps/yaml/HUIDU_HD_WF4.yml +1 -0
  201. data/vendor/board-maps/yaml/LILYGO_LORA_CC1101.yml +6 -0
  202. data/vendor/board-maps/yaml/LILYGO_LORA_LR1121.yml +6 -0
  203. data/vendor/board-maps/yaml/LILYGO_LORA_SI4432.yml +6 -0
  204. data/vendor/board-maps/yaml/LILYGO_LORA_SX1262.yml +6 -0
  205. data/vendor/board-maps/yaml/LILYGO_LORA_SX1280.yml +6 -0
  206. data/vendor/board-maps/yaml/LOLIN_C3_MINI.yml +0 -1
  207. data/vendor/board-maps/yaml/LOLIN_C3_PICO.yml +1 -2
  208. data/vendor/board-maps/yaml/LoPy.yml +0 -1
  209. data/vendor/board-maps/yaml/LoPy4.yml +0 -1
  210. data/vendor/board-maps/yaml/M5STACK_DINMETER.yml +8 -0
  211. data/vendor/board-maps/yaml/M5STACK_FIRE.yml +1 -1
  212. data/vendor/board-maps/yaml/OMGS3.yml +25 -0
  213. data/vendor/board-maps/yaml/PCBCUPID_GLYPHC3.yml +23 -0
  214. data/vendor/board-maps/yaml/PCBCUPID_GLYPHC6.yml +32 -0
  215. data/vendor/board-maps/yaml/PCBCUPID_GLYPHH2.yml +24 -0
  216. data/vendor/board-maps/yaml/PYCOM_GPY.yml +0 -1
  217. data/vendor/board-maps/yaml/SENSEBOX_MCU_ESP32S2.yml +1 -1
  218. data/vendor/board-maps/yaml/SPARKFUN_ESP32S3_THING_PLUS.yml +13 -0
  219. data/vendor/board-maps/yaml/SPARKLEMOTIONMINI_ESP32.yml +12 -0
  220. data/vendor/board-maps/yaml/SPARKLEMOTIONSTICK_ESP32.yml +11 -0
  221. data/vendor/board-maps/yaml/SPARKLEMOTION_ESP32.yml +12 -0
  222. data/vendor/board-maps/yaml/SQUIXL.yml +7 -0
  223. data/vendor/board-maps/yaml/THINGPULSE_EPULSE_FEATHER_C6.yml +0 -1
  224. data/vendor/board-maps/yaml/T_LORA_PAGER.yml +6 -0
  225. data/vendor/board-maps/yaml/T_WATCH_S3.yml +7 -0
  226. data/vendor/board-maps/yaml/T_WATCH_S3_ULTRA.yml +6 -0
  227. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_146.yml +41 -0
  228. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_147.yml +41 -0
  229. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_169.yml +38 -0
  230. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_185.yml +41 -0
  231. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_RELAY_6CH.yml +41 -0
  232. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_143.yml +7 -0
  233. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_164.yml +7 -0
  234. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_18.yml +38 -0
  235. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_191.yml +7 -0
  236. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_241.yml +7 -0
  237. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_146.yml +41 -0
  238. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_169.yml +38 -0
  239. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_185.yml +41 -0
  240. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_185_BOX.yml +41 -0
  241. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_21.yml +41 -0
  242. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_28.yml +41 -0
  243. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_4.yml +36 -0
  244. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_43.yml +38 -0
  245. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_43B.yml +38 -0
  246. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_5.yml +38 -0
  247. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_5B.yml +38 -0
  248. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_7.yml +38 -0
  249. data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_ZERO.yml +36 -0
  250. data/vendor/board-maps/yaml/WIPY3.yml +0 -1
  251. data/vendor/board-maps/yaml/WS_ESP32_S3_MATRIX.yml +38 -0
  252. data/vendor/board-maps/yaml/XIAO_ESP32S3_PLUS.yml +46 -0
  253. data/vendor/board-maps/yaml/YB_ESP32S3_AMP_V2.yml +28 -0
  254. data/vendor/board-maps/yaml/YB_ESP32S3_AMP_V3.yml +28 -0
  255. data/vendor/board-maps/yaml/YB_ESP32S3_ETH.yml +40 -0
  256. data/vendor/board-maps/yaml/mercury.yml +20 -0
  257. metadata +116 -101
  258. data/.vscode/settings.json +0 -5
  259. data/.vscode/tasks.json +0 -20
  260. data/HARDWARE.md +0 -263
  261. data/benchmarks/analog_listen.rb +0 -49
  262. data/benchmarks/digital_write.rb +0 -28
  263. data/benchmarks/i2c_ssd1306_refresh.rb +0 -91
  264. data/examples/advanced/m5_env3.rb +0 -46
  265. data/examples/advanced/rotary_encoder_mac_volume.rb +0 -53
  266. data/examples/advanced/ssd1306_time_temp_rh.rb +0 -43
  267. data/examples/analog_io/ads1100.rb +0 -48
  268. data/examples/analog_io/ads1115.rb +0 -57
  269. data/examples/analog_io/ads1118.rb +0 -65
  270. data/examples/analog_io/dac_loopback.rb +0 -34
  271. data/examples/analog_io/input.rb +0 -56
  272. data/examples/analog_io/input_smoothing.rb +0 -27
  273. data/examples/analog_io/potentiometer.rb +0 -31
  274. data/examples/connection/binary_echo.rb +0 -34
  275. data/examples/connection/tcp.rb +0 -19
  276. data/examples/digital_io/button.rb +0 -17
  277. data/examples/digital_io/relay.rb +0 -17
  278. data/examples/digital_io/rotary_encoder.rb +0 -36
  279. data/examples/display/hd44780.png +0 -0
  280. data/examples/display/hd44780.rb +0 -47
  281. data/examples/display/ssd1306.rb +0 -43
  282. data/examples/display/ssd1306_s2_pico.rb +0 -29
  283. data/examples/eeprom/built_in.rb +0 -32
  284. data/examples/i2c/search.rb +0 -39
  285. data/examples/led/apa102_bounce.rb +0 -32
  286. data/examples/led/apa102_fade.rb +0 -44
  287. data/examples/led/builtin_blink.rb +0 -14
  288. data/examples/led/builtin_fade.rb +0 -19
  289. data/examples/led/rgb_led.rb +0 -31
  290. data/examples/led/seven_segment_char_echo.rb +0 -17
  291. data/examples/led/ws2812_bounce.rb +0 -30
  292. data/examples/led/ws2812_builtin_blink.rb +0 -22
  293. data/examples/led/ws2812_fade.rb +0 -43
  294. data/examples/motor/l298.rb +0 -45
  295. data/examples/motor/servo.rb +0 -17
  296. data/examples/motor/stepper.png +0 -0
  297. data/examples/motor/stepper.rb +0 -43
  298. data/examples/one_wire/search.rb +0 -32
  299. data/examples/pulse_io/buzzer.rb +0 -35
  300. data/examples/pulse_io/ir_output.rb +0 -51
  301. data/examples/pulse_io/pwm_output.rb +0 -30
  302. data/examples/rtc/ds3231.rb +0 -31
  303. data/examples/sensor/aht10.rb +0 -17
  304. data/examples/sensor/aht20.rb +0 -17
  305. data/examples/sensor/bme280.rb +0 -38
  306. data/examples/sensor/bmp180.rb +0 -26
  307. data/examples/sensor/dht.rb +0 -29
  308. data/examples/sensor/ds18b20.rb +0 -57
  309. data/examples/sensor/generic_pir.rb +0 -27
  310. data/examples/sensor/hcsr04.rb +0 -17
  311. data/examples/sensor/htu21d.rb +0 -43
  312. data/examples/sensor/htu31d.rb +0 -33
  313. data/examples/sensor/neat_tph_readings.rb +0 -32
  314. data/examples/sensor/qmp6988.rb +0 -51
  315. data/examples/sensor/rcwl9620.rb +0 -15
  316. data/examples/sensor/sht3x.rb +0 -32
  317. data/examples/spi/bitbang_loopback.rb +0 -46
  318. data/examples/spi/input_register.rb +0 -40
  319. data/examples/spi/output_register.rb +0 -41
  320. data/examples/spi/ssd_through_registers.rb +0 -28
  321. data/examples/spi/two_registers.rb +0 -40
  322. data/examples/uart/bit_bang_demo.rb +0 -25
  323. data/examples/uart/board_passthrough.rb +0 -40
  324. data/examples/uart/hardware_loopback.rb +0 -16
  325. data/lib/denko/eeprom/built_in.rb +0 -72
  326. data/lib/denko/fonts.rb +0 -106
  327. data/test/eeprom/built_in_test.rb +0 -61
  328. data/test/spi/peripheral_single_pin_test.rb +0 -48
  329. data/tutorial/01-led/led.fzz +0 -0
  330. data/tutorial/01-led/led.pdf +0 -0
  331. data/tutorial/01-led/led.rb +0 -73
  332. data/tutorial/02-button/button.fzz +0 -0
  333. data/tutorial/02-button/button.pdf +0 -0
  334. data/tutorial/02-button/button.rb +0 -65
  335. data/tutorial/03-potentiometer/potentiometer.fzz +0 -0
  336. data/tutorial/03-potentiometer/potentiometer.pdf +0 -0
  337. data/tutorial/03-potentiometer/potentiometer.rb +0 -66
  338. data/tutorial/04-pwm_led/pwm_led.fzz +0 -0
  339. data/tutorial/04-pwm_led/pwm_led.pdf +0 -0
  340. data/tutorial/04-pwm_led/pwm_led.rb +0 -64
  341. data/tutorial/05-rgb_led/rgb_led.fzz +0 -0
  342. data/tutorial/05-rgb_led/rgb_led.pdf +0 -0
  343. data/tutorial/05-rgb_led/rgb_led.rb +0 -58
  344. data/tutorial/05-rgb_led/rgb_mapping.rb +0 -76
@@ -0,0 +1,186 @@
1
+ module Denko
2
+ module Display
3
+ class IL0373
4
+ include SPIEPaperCommon
5
+ include Behaviors::Lifecycle
6
+
7
+ COLUMNS = 212
8
+ ROWS = 104
9
+
10
+ # Subset of used commands from datasheet:
11
+ PANEL_SETTING = 0x00
12
+ POWER_SETTING = 0x01
13
+ POWER_OFF = 0x02
14
+ POWER_OFF_SEQUENCE = 0x03
15
+ POWER_ON = 0x04
16
+ POWER_ON_MEASURE = 0x05
17
+ BOOSTER_SOFT_START = 0x06
18
+ DEEP_SLEEP = 0x07
19
+ DATA_START_1 = 0x10
20
+ DATA_STOP = 0x11
21
+ DISPLAY_REFRESH = 0x12
22
+ DATA_START_2 = 0x13
23
+ VCOM_DATA_SETTING = 0x50
24
+ RESOLUTION_SETTING = 0x61
25
+ PARTIAL_WINDOW = 0x90
26
+ PARTIAL_IN = 0x91
27
+ PARTIAL_OUT = 0x92
28
+
29
+ def set_power_setting
30
+ # Defaults from datasheet.
31
+ command [POWER_SETTING]
32
+ data [0x03, 0x00, 0x26, 0x26, 0x03]
33
+ end
34
+
35
+ def set_panel_setting
36
+ # NOT DEFAULTS
37
+ # From datasheet:
38
+ # Bits 7..6: Enable all source and gate channels
39
+ # Bit 5: 0 = LUT from OTP
40
+ # Bit 4: 0 = B/W/R mode, 1 = B/W mode
41
+ # Bit 3: 0 = Gate scan decrements (1 increments)
42
+ # Bit 2: 0 = Source scan decrements (1 increments)
43
+ # Bit 1: 1 = Enable booster
44
+ # Bit 0: 1 = Soft reset
45
+ value = 0b0000_0011
46
+
47
+ # Handle colors
48
+ value |= (1 << 4) if colors == 2
49
+
50
+ # Handle screen size
51
+ source_gate_bits = 0b11
52
+ source_gate_bits = 0b10 if (rows <= 128)
53
+ source_gate_bits = 0b01 if (rows <= 96) && (columns <= 252)
54
+ source_gate_bits = 0b00 if (rows <= 96) && (columns <= 230)
55
+ value |= source_gate_bits
56
+
57
+ # Handle hardware reflection/rotation
58
+ value |= (1 << 2) if @reflect_y
59
+ value |= (1 << 3) if @reflect_x
60
+
61
+ command [PANEL_SETTING]
62
+ data [value]
63
+ end
64
+
65
+ def reflect_x
66
+ @reflect_x = !@reflect_x
67
+ end
68
+
69
+ def reflect_y
70
+ @reflect_y = !@reflect_y
71
+ end
72
+
73
+ def rotate
74
+ @reflect_x = !@reflect_x
75
+ @reflect_y = !@reflect_y
76
+ end
77
+
78
+ def set_vcom_data_setting
79
+ # Default value from data sheet.
80
+ value = 0b0000_0111
81
+
82
+ # Datsheet may be wrong here. Bit 5 set seems to always invert DATA2, so Bit 4 does DATA1?
83
+ # In B/W mode: set bit 5 to avoid black channel inversion relative to Canvas.
84
+ # In B/W/R mode: set bit 4 to avoid black channel inversion relative to Canvas.
85
+ if (colors == 2)
86
+ value |= (1 << 4) unless @invert_black
87
+ else
88
+ value |= (1 << 5) unless @invert_black
89
+ end
90
+
91
+ command [VCOM_DATA_SETTING]
92
+ data [value]
93
+ end
94
+
95
+ def invert_black
96
+ @invert_black = !@invert_black
97
+ end
98
+
99
+ def set_resolution
100
+ command [RESOLUTION_SETTING]
101
+ data [
102
+ p_max+1 << 3,
103
+ (columns >> 8) & 0b1,
104
+ columns & 0xFF
105
+ ]
106
+ end
107
+
108
+ def booster_soft_start
109
+ # Defaults from datasheet.
110
+ command [BOOSTER_SOFT_START]
111
+ data [0x17, 0x17, 0x17]
112
+ end
113
+
114
+ def power_on
115
+ command [POWER_ON]
116
+ busy_wait
117
+ end
118
+
119
+ def wake
120
+ hw_reset
121
+ set_power_setting
122
+ set_panel_setting
123
+ set_vcom_data_setting
124
+ set_resolution
125
+ booster_soft_start
126
+ power_on
127
+ end
128
+
129
+ def deep_sleep
130
+ # Default from datasheet.
131
+ command [DEEP_SLEEP]
132
+ data [0xA5]
133
+ end
134
+
135
+ # Treat what the datasheet calls x as vertical (y, page), and vertical as horizontal (x).
136
+ def set_window(x_start=x_min, x_finish=x_max, p_start=p_min, p_finish=p_max)
137
+ command [PARTIAL_WINDOW]
138
+ data [
139
+ p_start << 3,
140
+ p_finish << 3,
141
+ (x_start >> 8) & 0b1,
142
+ x_start & 0xFF,
143
+ (x_finish >> 8) & 0b1,
144
+ x_finish & 0xFF,
145
+ 0b0
146
+ ]
147
+ command [PARTIAL_IN]
148
+ end
149
+
150
+ def draw(*args, **kwargs)
151
+ wake
152
+ super(*args, **kwargs)
153
+ end
154
+
155
+ def draw_partial(buffer, x_start, x_finish, p_start, p_finish, color=1)
156
+ set_window(x_start, x_finish, p_start, p_finish)
157
+
158
+ if (colors == 2)
159
+ # In B/W/Red mode, red goes in DATA2, black in DATA1
160
+ (color == 2) ? command[DATA_START_2] : command[DATA_START_1]
161
+ else
162
+ # In B/W mode, always write to DATA2
163
+ command [DATA_START_2]
164
+ end
165
+
166
+ # Can't control address increment to go horizontally, always vertical.
167
+ # So get partial from the full buffer and reorder the bytes.
168
+ transformed_buffer = []
169
+ (x_start..x_finish).each do |x|
170
+ (p_start..p_finish).to_a.reverse.each do |page|
171
+ index = (page * columns) + x
172
+ transformed_buffer << buffer[index]
173
+ end
174
+ end
175
+ transformed_buffer.each_slice(transfer_limit) { |slice| data(slice) }
176
+
177
+ command [DATA_STOP]
178
+ end
179
+
180
+ def refresh
181
+ command [DISPLAY_REFRESH]
182
+ busy_wait
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,193 @@
1
+ module Denko
2
+ module Display
3
+ module MonoOLED
4
+ include Behaviors::BusPeripheral
5
+ include Behaviors::Lifecycle
6
+
7
+ # I2C Defaults
8
+ I2C_ADDRESS = 0x3C
9
+ I2C_FREQUENCY = 400_000
10
+
11
+ # Fundamental Commands
12
+ # Single byte (no need to OR with anything)
13
+ PIXELS_FROM_RAM = 0xA4
14
+ PIXELS_ALL_ON = 0xA5
15
+ INVERT_OFF = 0xA6
16
+ INVERT_ON = 0xA7
17
+ DISPLAY_OFF = 0xAE
18
+ DISPLAY_ON = 0xAF
19
+
20
+ # Double byte (following byte sets value)
21
+ CONTRAST = 0x81
22
+ # Values: 0x00 to 0xFF. Default is 0x7F
23
+
24
+ # Scrolling commands ignored.
25
+
26
+ # Address Setting Commands
27
+ # Single byte. OR with value. These are for page addressing mode only.
28
+ COLUMN_START_LOWER = 0x00 # lower 4 bytes of column
29
+ COLUMN_START_UPPER = 0x10 # upper 4 bytes of column
30
+ PAGE_START = 0xB0 # page 0-7
31
+
32
+ # Double byte. Following byte sets value.
33
+ ADDRESSING_MODE = 0x20
34
+ # Values:
35
+ # 0x00 = horizontal (Pages auto-increment. Used for SSD1306)
36
+ # 0x01 = vertical
37
+ # 0x02 = page (Default. Page and column must be set each time. Needed on SH1106, SH1107)
38
+ ADDRESSING_MODE_DEFAULT = 0x00
39
+
40
+ # Triple byte. Following 2 bytes sets value. For H/V addressing modes only.
41
+ COLUMN_ADDRESS_RANGE = 0x21
42
+ PAGE_ADDRESS_RANGE = 0x22
43
+ # For both: first value = min column/row, second value = max column/row
44
+
45
+ # Hardware Configuration Commands
46
+ # Single byte. OR with value.
47
+ START_LINE = 0x40 # Value: lowest 6 bits set RAM start line (default 0b000000)
48
+ SEGMENT_REMAP = 0xA0 # Value: 0x00 = default, 0x01 = column draw order reversed (horizontal reflection)
49
+ COM_DIRECTION = 0xC0 # Value: 0x00 = default, 0x08 = row draw order reversed (vertical reflection)
50
+
51
+ # Double-byte commands. Following byte sets value.
52
+ CHARGE_PUMP = 0x8D # Value: 0x10 = disable/external, 0x14 = enable/internal
53
+ MULTIPLEX_RATIO = 0xA8 # Value: rows of display - 1
54
+ DISPLAY_OFFSET = 0xD3 # Value: lowest 5 bits. Vertically shifts COM by that amount.
55
+ COM_PIN_CONFIG = 0xDA
56
+ # 0x02 = sequential, left and right not swapped
57
+ # 0x12 = alternative, left and right not swapped (default)
58
+ # 0x22 = sequential, left and right sawpped
59
+ # 0x32 = alternative, left and right swapped
60
+
61
+ # Timing & Driving Commands
62
+ # Double-byte commands. Following byte sets value.
63
+ CLOCK = 0xD5 # Lowest 4 bits = divider. Upper 4 bits = oscillator frequency.
64
+ PRECHARGE_PERIOD = 0xD9 # Lowest 4 bits = phase 1. Upper 4 bits = phase 2. 0xF1 for internal charge pump. 0x22 for external.
65
+ VCOM_DESELECT_LEVEL = 0xDB # 0x00 = 0.65 x Vcc, 0x20 = x 0.77 * Vcc (default), 0x30 = 0.83 x Vcc
66
+
67
+ # Valid widths and heights for displays
68
+ WIDTHS = [64,96,128]
69
+ HEIGHTS = [16,32,48,64,128]
70
+
71
+ # Default to a 128x64 display.
72
+ COLUMNS = 128
73
+ ROWS = 64
74
+
75
+ # Decide whether this instance is I2C or SPI.
76
+ before_initialize do
77
+ bus = params[:bus] || params[:board]
78
+
79
+ if bus.class.ancestors.include?(Denko::I2C::BusCommon)
80
+ mutate_i2c
81
+ elsif bus.class.ancestors.include?(Denko::SPI::BusCommon)
82
+ mutate_spi
83
+ else
84
+ raise ArgumentError, "#{self.class} must be connected to either an I2C or SPI bus"
85
+ end
86
+ end
87
+
88
+ def mutate_i2c
89
+ singleton_class.class_eval do
90
+ include I2C::Peripheral
91
+ include PixelCommon
92
+
93
+ # Commands are I2C messages prefixed with 0x00.
94
+ def command(bytes)
95
+ i2c_write([0x00] + bytes)
96
+ end
97
+
98
+ # Data are I2C messages prefixed with 0x40.
99
+ def data(bytes)
100
+ i2c_write([0x40] + bytes)
101
+ end
102
+
103
+ # Data prefix always takes one byte, so subtract that.
104
+ def transfer_limit
105
+ @transfer_limit ||= bus.board.i2c_limit - 1
106
+ end
107
+ end
108
+ end
109
+
110
+ def mutate_spi
111
+ singleton_class.class_eval do
112
+ include SPICommon
113
+ end
114
+ end
115
+
116
+ after_initialize do
117
+ # Validate known sizes.
118
+ raise ArgumentError, "error in #{self.class} width: #{columns}. Must be in: #{WIDTHS.inspect}" unless WIDTHS.include?(columns)
119
+ raise ArgumentError, "error in #{self.class} height: #{rows}. Must be in: #{HEIGHTS.inspect}" unless HEIGHTS.include?(rows)
120
+
121
+ # Everything except 96x16 size uses clock 0x80.
122
+ clock = 0x80
123
+ clock = 0x60 if (columns == 96 && rows == 16)
124
+
125
+ # 128x32 and 96x16 sizes use com pin config 0x02
126
+ com_pin_config = 0x12
127
+ com_pin_config = 0x02 if (columns == 96 && rows == 16) || (columns == 128 && rows == 32)
128
+
129
+ # Defaul to no reflection or rotation.
130
+ @seg_remap = 0x00
131
+ @com_direction = 0x00
132
+
133
+ # Startup sequence. SPI needs 2 repeats for some reason.
134
+ startup_count = 1
135
+ startup_count = 2 if singleton_class.ancestors.include? Denko::SPI::Peripheral
136
+ startup_count.times do
137
+ command [
138
+ MULTIPLEX_RATIO, rows - 1,
139
+ DISPLAY_OFFSET, 0x00,
140
+ START_LINE | 0x00,
141
+ SEGMENT_REMAP | @seg_remap,
142
+ COM_DIRECTION | @com_direction,
143
+ COM_PIN_CONFIG, com_pin_config,
144
+ PIXELS_FROM_RAM,
145
+ INVERT_OFF,
146
+ CLOCK, clock,
147
+ VCOM_DESELECT_LEVEL, 0x20,
148
+ PRECHARGE_PERIOD, 0xF1, # Charge period for internal charge pump
149
+ CHARGE_PUMP, 0x14, # Internal charge pump
150
+ ADDRESSING_MODE, self.class::ADDRESSING_MODE_DEFAULT,
151
+ DISPLAY_ON
152
+ ]
153
+ end
154
+
155
+ draw
156
+ end
157
+
158
+ def off
159
+ command [DISPLAY_OFF]
160
+ end
161
+
162
+ def on
163
+ command [DISPLAY_ON]
164
+ end
165
+
166
+ def contrast=(value)
167
+ raise ArgumentError, "contrast must be in range 0..255" if (value < 0 || value > 255)
168
+ command [CONTRAST, value]
169
+ end
170
+
171
+ def reflect_x
172
+ # Swap @seg_remap to the other value and write it.
173
+ @seg_remap = (@seg_remap == 0x00) ? 0x01 : 0x00
174
+ command [SEGMENT_REMAP | @seg_remap]
175
+ end
176
+
177
+ def reflect_y
178
+ # Swap @com_direction to the other value and write it.
179
+ @com_direction = (@com_direction == 0x00) ? 0x08 : 0x00
180
+ command [COM_DIRECTION | @com_direction]
181
+ end
182
+
183
+ def rotate
184
+ reflect_x
185
+ reflect_y
186
+ end
187
+
188
+ def draw_partial(buffer, x_min, x_max, p_min, p_max)
189
+ raise NotImplementedError, "#draw_partial must be implemented for each class including MonoOLED"
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,154 @@
1
+ module Denko
2
+ module Display
3
+ class PCD8544
4
+ include Behaviors::Lifecycle
5
+ include SPICommon
6
+
7
+ COLUMNS = 84
8
+ ROWS = 48
9
+
10
+ FUNCTION_SET = 0b00100000
11
+ # OR these options into lowest 3 bits:
12
+ POWER_UP = 0b000
13
+ POWER_DOWN = 0b100
14
+ H_ADDRESSING = 0b00
15
+ V_ADDRESSING = 0b10
16
+ BASIC_INS_SET = 0b0
17
+ EXT_INS_SET = 0b1
18
+
19
+ #
20
+ # Basic Instruciton Set (H = 0)
21
+ #
22
+ DISPLAY_CONTROL_SET = 0b00001000
23
+ # OR these options into lowest 3 bits:
24
+ DISPLAY_BLANK = 0b000
25
+ DISPLAY_NORMAL = 0b100
26
+ DISPLAY_ALL_SEGS = 0b001
27
+ DISPLAY_INVERT = 0b101
28
+
29
+ RAM_Y_SET = 0b01000000 # OR Y value into lowest 3 bits
30
+ RAM_X_SET = 0b10000000 # OR X value into lowest 7 bits
31
+
32
+ #
33
+ # Extended Instruciton Set (H = 1)
34
+ #
35
+ TEMP_COEFF_SET = 0b00000100 # OR temperature coeff. into lowest 2 bits
36
+ BIAS_SET = 0b00010000 # OR bias system values into lowest 3 bits
37
+ VOP_SET = 0b10000000 # OR VOP values into lowest 7 bits
38
+
39
+ def power_up
40
+ @function_state = (function_state & 0b11111011) | POWER_UP
41
+ command [function_state]
42
+ end
43
+
44
+ def power_down
45
+ @function_state = (function_state & 0b11111011) | POWER_DOWN
46
+ command [function_state]
47
+ end
48
+
49
+ def basic_instruction_mode
50
+ @function_state = (function_state & 0b11111110) | BASIC_INS_SET
51
+ command [function_state]
52
+ end
53
+
54
+ def extended_instruction_mode
55
+ @function_state = (function_state & 0b11111110) | EXT_INS_SET
56
+ command [function_state]
57
+ end
58
+
59
+ def function_state
60
+ @function_state ||= FUNCTION_SET
61
+ end
62
+
63
+ VALID_VOPS = (0..127).to_a
64
+
65
+ def vop=(value)
66
+ raise ArgumentError, "invalid Vop: #{value}" unless VALID_VOPS.include?(value)
67
+ extended_instruction_mode
68
+ command [VOP_SET | value]
69
+ basic_instruction_mode
70
+ @vop = value
71
+ end
72
+
73
+ VALID_BIASES = (0..7).to_a
74
+
75
+ def bias=(value)
76
+ raise ArgumentError, "invalid bias: #{value}" unless VALID_BIASES.include?(value)
77
+ extended_instruction_mode
78
+ command [BIAS_SET | value]
79
+ basic_instruction_mode
80
+ @bias = value
81
+ end
82
+
83
+ VALID_TCOEFFS = (0..3).to_a
84
+
85
+ def temperature_coefficient=(value)
86
+ raise ArgumentError, "invalid temperature coefficient: #{value}" unless VALID_TCOEFFS.include?(value)
87
+ extended_instruction_mode
88
+ command [TEMP_COEFF_SET | value]
89
+ basic_instruction_mode
90
+ @temperature_coefficient = value
91
+ end
92
+
93
+ def vop
94
+ @vop ||= 0
95
+ end
96
+
97
+ def bias
98
+ @bias ||= 0
99
+ end
100
+
101
+ def temperature_coefficient
102
+ @temperature_coefficient ||= 0
103
+ end
104
+
105
+ def set_display_control(value)
106
+ command [DISPLAY_CONTROL_SET | value]
107
+ end
108
+
109
+ def blank
110
+ set_display_control(DISPLAY_BLANK)
111
+ end
112
+
113
+ def all_segments_on
114
+ set_display_control(DISPLAY_ALL_SEGS)
115
+ end
116
+
117
+ def invert
118
+ @inverted = !@inverted
119
+ value = @inverted ? DISPLAY_INVERT : DISPLAY_NORMAL
120
+ set_display_control(value)
121
+ end
122
+
123
+ after_initialize do
124
+ # Reset sequence.
125
+ reset.low if reset
126
+ sleep 0.001
127
+ reset.high if reset
128
+
129
+ self.vop = 56
130
+ self.bias = 4
131
+ set_display_control(DISPLAY_NORMAL)
132
+ self.temperature_coefficient = 0
133
+ end
134
+
135
+ def draw_partial(buffer, x_start, x_finish, p_start, p_finish, color=1)
136
+ # Always use horizontal addressing mode.
137
+ basic_instruction_mode
138
+
139
+ (p_start..p_finish).each do |page|
140
+ # Set start page and column.
141
+ command [RAM_X_SET | x_start, RAM_Y_SET | page]
142
+
143
+ # Get needed bytes for this page only.
144
+ src_start = (columns * page) + x_start
145
+ src_end = (columns * page) + x_finish
146
+ partial_buffer = buffer[src_start..src_end]
147
+
148
+ # Send in chunks up to maximum transfer size.
149
+ partial_buffer.each_slice(transfer_limit) { |slice| data(slice) }
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,83 @@
1
+ module Denko
2
+ module Display
3
+ module PixelCommon
4
+ def columns
5
+ return @columns if @columns
6
+ @columns = self.class.const_get("COLUMNS") if self.class.const_defined?("COLUMNS")
7
+ @columns = params[:width] if params[:width]
8
+ @columns = params[:columns] if params[:columns]
9
+ @columns
10
+ end
11
+ alias :cols :columns
12
+
13
+ def rows
14
+ return @rows if @rows
15
+ @rows = self.class.const_get("ROWS") if self.class.const_defined?("ROWS")
16
+ @rows = params[:height] if params[:height]
17
+ @rows = params[:rows] if params[:rows]
18
+ @rows
19
+ end
20
+
21
+ def x_min
22
+ @x_min ||= 0
23
+ end
24
+
25
+ def x_max
26
+ @x_max ||= columns - 1
27
+ end
28
+
29
+ def y_min
30
+ @y_min ||= 0
31
+ end
32
+
33
+ def y_max
34
+ @y_max ||= rows - 1
35
+ end
36
+
37
+ def p_min
38
+ @p_min ||= 0
39
+ end
40
+
41
+ def p_max
42
+ @p_max ||= (rows / 8.0).ceil - 1
43
+ end
44
+
45
+ def colors
46
+ @colors ||= params[:colors] || 1
47
+ end
48
+
49
+ def canvas
50
+ @canvas ||= Canvas.new(columns, rows, colors: colors)
51
+ end
52
+
53
+ def refresh
54
+ end
55
+
56
+ def get_partial_buffer(buffer, x_start, x_finish, p_start, p_finish)
57
+ # If bounds == max bounds, just return the buffer.
58
+ return buffer if (x_start == x_min) && (x_finish == x_max) && (p_start == p_min) && (p_finish == p_max)
59
+
60
+ # Copy bytes for the given rectangle into a temp buffer.
61
+ temp_buffer = []
62
+ (p_start..p_finish).each do |page|
63
+ src_start = (columns * page) + x_start
64
+ src_end = (columns * page) + x_finish
65
+ temp_buffer += buffer[src_start..src_end]
66
+ end
67
+ temp_buffer
68
+ end
69
+
70
+ def draw(x_start=x_min, x_finish=x_max, y_start=y_min, y_finish=y_max)
71
+ # Convert y-coords to page coords.
72
+ p_start = y_start / 8
73
+ p_finish = y_finish / 8
74
+
75
+ colors.times do |i|
76
+ draw_partial(canvas.framebuffers[i], x_start, x_finish, p_start, p_finish, i+1)
77
+ end
78
+
79
+ refresh
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,40 +1,36 @@
1
- require_relative 'ssd1306'
2
-
3
1
  module Denko
4
2
  module Display
5
- class SH1106 < SSD1306
3
+ class SH1106
4
+ include MonoOLED
6
5
  #
7
- # Unlike the SSD1306, SH1106 only supports page addressing mode.
6
+ # SH1106/SH1107 only support page addressing mode.
8
7
  # Can't send all data as sequential pages and let page index auto-increment,
9
8
  # like with horizontal addressing on the SSD1306.
10
9
  #
11
10
  ADDRESSING_MODE_DEFAULT = 0x02
11
+ RAM_X_OFFSET = 2
12
+ #
13
+ # SH1106 has RAM for 132 columns, but only 128 pixels, so offset by 2 to center.
14
+ def ram_x_offset
15
+ @ram_x_offset ||= self.class.const_get("RAM_X_OFFSET")
16
+ end
12
17
 
13
- def draw(x_min=0, x_max=(@columns-1), y_min=0, y_max=(@rows-1))
14
- # Convert y-coords to page coords.
15
- p_min = y_min / 8
16
- p_max = y_max / 8
17
-
18
- # Offset x_min by 2, since SH1106 has RAM for 132 columns, but we only use 128, then convert to nibbles.
19
- x = x_min + 2
18
+ def draw_partial(buffer, x_start, x_finish, p_start, p_finish, color=1)
19
+ x = x_start + ram_x_offset
20
20
  x_lower = (x & 0b00001111)
21
21
  x_upper = (x & 0b11110000) >> 4
22
22
 
23
- (p_min..p_max).each do |page|
23
+ (p_start..p_finish).each do |page|
24
24
  # Set the page and column to start writing at.
25
25
  command [PAGE_START | page, COLUMN_START_LOWER | x_lower, COLUMN_START_UPPER | x_upper]
26
26
 
27
27
  # Get needed bytes for this page only.
28
- src_start = (@columns * page) + x_min
29
- src_end = (@columns * page) + x_max
30
- buffer = canvas.framebuffer[src_start..src_end]
28
+ src_start = (columns * page) + x_start
29
+ src_end = (columns * page) + x_finish
30
+ partial_buffer = buffer[src_start..src_end]
31
31
 
32
- # Send all bytes at once if within limit, or split into chunks.
33
- if buffer.length < (bus.board.i2c_limit - 1)
34
- data(buffer)
35
- else
36
- buffer.each_slice(bus.board.i2c_limit - 1) { |slice| data(slice) }
37
- end
32
+ # Send in chunks up to maximum transfer size.
33
+ partial_buffer.each_slice(transfer_limit) { |slice| data(slice) }
38
34
  end
39
35
  end
40
36
  end
@@ -0,0 +1,10 @@
1
+ module Denko
2
+ module Display
3
+ class SH1107 < SH1106
4
+ COLUMNS = 128
5
+ ROWS = 128
6
+ # SH1107 RAM has 128 columns, unlike 132 on SH1106. Don't offset by 2.
7
+ RAM_X_OFFSET = 0
8
+ end
9
+ end
10
+ end