Skip to content

Commit 12ed6f5

Browse files
committed
ssd1327: Add test scenario for OLED display driver.
1 parent a8301fd commit 12ed6f5

4 files changed

Lines changed: 159 additions & 2 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""Stub for the MicroPython framebuf module."""
2+
3+
GS4_HMSB = 2
4+
5+
6+
class FrameBuffer:
7+
"""Minimal FrameBuffer stub for testing display drivers on CPython."""
8+
9+
def __init__(self, buffer, width, height, fmt):
10+
self.buffer = buffer
11+
self.width = width
12+
self.height = height
13+
self.format = fmt
14+
15+
def fill(self, col):
16+
val = (col & 0x0F) | ((col & 0x0F) << 4)
17+
for i in range(len(self.buffer)):
18+
self.buffer[i] = val
19+
20+
def pixel(self, x, y, col=None):
21+
pass
22+
23+
def text(self, string, x, y, col=15):
24+
pass
25+
26+
def line(self, x1, y1, x2, y2, col):
27+
pass
28+
29+
def scroll(self, dx, dy):
30+
pass

tests/fake_machine/i2c.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ def writeto_mem(self, addr, reg, buf, *, addrsize=8):
4040
self._registers[reg] = bytes(buf)
4141
self._write_log.append((reg, bytes(buf)))
4242

43+
def writeto(self, addr, buf, stop=True):
44+
self._check_address(addr)
45+
self._write_log.append((None, bytes(buf)))
46+
47+
def writevto(self, addr, bufs, stop=True):
48+
self._check_address(addr)
49+
data = b"".join(bytes(b) for b in bufs)
50+
self._write_log.append((None, data))
51+
4352
def scan(self):
4453
if self._address is not None:
4554
return [self._address]

tests/runner/executor.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def load_driver_mock(driver_name, fake_i2c, module_name=None):
2121
module_name = driver_name
2222
from tests.fake_machine import FakeI2C, FakePin
2323
from tests.fake_machine import micropython_stub
24+
from tests.fake_machine import framebuf_stub
2425

2526
# Patch modules before importing driver
2627
import types
@@ -32,6 +33,7 @@ def load_driver_mock(driver_name, fake_i2c, module_name=None):
3233

3334
sys.modules["machine"] = fake_machine
3435
sys.modules["micropython"] = micropython_stub
36+
sys.modules["framebuf"] = framebuf_stub
3537

3638
# Patch time module to add MicroPython-specific functions
3739
import time
@@ -107,8 +109,8 @@ def run_action(action, driver_instance):
107109

108110
if action_type == "manual":
109111
prompt = action.get("prompt", "Manual check required")
110-
response = input(f"\n [MANUAL] {prompt} [y/n] ")
111-
return response.strip().lower() == "y"
112+
from tests.test_scenarios import _prompt_yes_no
113+
return _prompt_yes_no(prompt)
112114

113115
if action_type == "interactive":
114116
# Prompt first, then call method (used for hold-button-and-read tests)

tests/scenarios/ssd1327.yaml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
driver: ssd1327
2+
driver_class: WS_OLED_128X128_I2C
3+
i2c_address: 0x3C
4+
5+
# I2C config for hardware tests (STeaMi board - STM32WB55)
6+
# The display uses SPI on hardware, but i2c config is required by the bridge.
7+
i2c:
8+
id: 1
9+
10+
# Custom hardware init (STeaMi display is on SPI, not I2C)
11+
hardware_init: |
12+
from ssd1327.device import WS_OLED_128X128_SPI
13+
from machine import SPI, Pin
14+
spi = SPI(1)
15+
dc = Pin("DATA_COMMAND_DISPLAY")
16+
res = Pin("RST_DISPLAY")
17+
cs = Pin("CS_DISPLAY")
18+
dev = WS_OLED_128X128_SPI(spi, dc, res, cs)
19+
20+
tests:
21+
- name: "Fill black does not crash"
22+
action: call
23+
method: fill
24+
args: [0]
25+
mode: [mock]
26+
27+
- name: "Fill white does not crash"
28+
action: call
29+
method: fill
30+
args: [15]
31+
mode: [mock]
32+
33+
- name: "Text rendering does not crash"
34+
action: call
35+
method: text
36+
args: ["Test", 0, 0, 15]
37+
mode: [mock]
38+
39+
- name: "Show does not crash"
40+
action: call
41+
method: show
42+
mode: [mock]
43+
44+
- name: "Display white screen"
45+
action: hardware_script
46+
script: |
47+
dev.fill(15)
48+
dev.show()
49+
result = True
50+
expect_true: true
51+
mode: [hardware]
52+
53+
- name: "Screen is white"
54+
action: manual
55+
prompt: "L'écran affiche-t-il un fond blanc uniforme ?"
56+
expect_true: true
57+
mode: [hardware]
58+
59+
- name: "Display text"
60+
action: hardware_script
61+
script: |
62+
dev.fill(0)
63+
dev.text("STeaMi", 35, 56, 15)
64+
dev.text("Test OK", 32, 68, 15)
65+
dev.show()
66+
result = True
67+
expect_true: true
68+
mode: [hardware]
69+
70+
- name: "Text is visible"
71+
action: manual
72+
prompt: "L'écran affiche-t-il 'STeaMi' et 'Test OK' sur fond noir ?"
73+
expect_true: true
74+
mode: [hardware]
75+
76+
- name: "Display grayscale gradient"
77+
action: hardware_script
78+
script: |
79+
dev.fill(0)
80+
w = 128 // 16
81+
for level in range(16):
82+
x = level * w
83+
for row in range(128):
84+
for col in range(x, x + w):
85+
dev.pixel(col, row, level)
86+
dev.show()
87+
result = True
88+
expect_true: true
89+
mode: [hardware]
90+
91+
- name: "Grayscale gradient is visible"
92+
action: manual
93+
prompt: "L'écran affiche-t-il 16 bandes verticales du noir au blanc ?"
94+
expect_true: true
95+
mode: [hardware]
96+
97+
- name: "Scrolling animation"
98+
action: hardware_script
99+
script: |
100+
from time import sleep_ms
101+
dev.fill(0)
102+
dev.text("STeaMi", 35, 60, 15)
103+
dev.show()
104+
for i in range(128):
105+
dev.scroll(1, 0)
106+
dev.show()
107+
sleep_ms(20)
108+
result = True
109+
expect_true: true
110+
mode: [hardware]
111+
112+
- name: "Animation was smooth"
113+
action: manual
114+
prompt: "Le texte 'STeaMi' a-t-il defile horizontalement de maniere fluide ?"
115+
expect_true: true
116+
mode: [hardware]

0 commit comments

Comments
 (0)