mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 22:35:08 +00:00
* fix(web): accept every panel size and row address type the rgbmatrix library does The Display form capped columns at 128 and chain length at 24, and its submit handler (fixInvalidNumberInputs) rewrote anything larger to the cap, so wide panels and long chains silently saved as the wrong size. The config API checked none of the hardware numbers, so values the library rejects (odd rows, parallel 4, PWM dither bits 3) saved and the matrix then refused to start. - Form limits now match the pinned library: rows even 8-64, cols >= 16 and chain_length >= 1 with no upper bound, parallel 1-3, PWM dither bits 0-2, PWM LSB nanoseconds 50-3000. - save_main_config rejects out-of-range rows, cols, chain_length, parallel, brightness, scan_mode, pwm_bits, pwm_dither_bits, pwm_lsb_nanoseconds and gpio_slowdown with a 400. - A stored gpio_slowdown or pwm_dither_bits of 0 renders as 0 instead of the default, so saving the tab no longer overwrites it. - Row Address Type offers 5 (SM5368 / B707 row shift register). Verified on a Waveshare 96x48 V2 (24S-A1) on a Pi 4 with the Adafruit Triple LED Matrix Bonnet: rows 48, cols 96, row address type 5, BGR, GPIO slowdown 8. - Help text and docs: FM6124-family panels use Panel Type Standard; on a Pi 5 the library supports only row address types 0 and 2. No change to the rpi-rgb-led-matrix submodule. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(web): drop the rows cap and document every display setting accurately Rows: no upper limit in the form or the API. Still even and at least 8. The current rgbmatrix library rejects more than 64 per panel, so a larger value saves but the matrix won't start; the help tip, README, config reference and troubleshooting section all say so, and nothing here needs changing if the library lifts the limit. limit_refresh_rate_hz: the form accepts 0 (the library's "no cap"), a stored 0 no longer renders and re-saves as 120, and the API rejects negatives. pwm_dither_bits stays 0-2: the library rejects 3 and 4, so the old form's 0-4 only ever let users save a config the display couldn't start with. Docs and help tips, checked against the pinned library and its README: - panel_type and rp1_rio get README entries - show_refresh_rate prints to stdout; it never drew on the panel - dither bits raise the refresh rate; the tip said they lowered it - scan_mode is about interlacing at low refresh, not wrong colours - disable_hardware_pulsing: hardware pulsing needs OE on GPIO 18 and the onboard sound driver off; software timing makes rows flash brighter - gpio_slowdown guidance agrees between the README and the UI - all 22 multiplexing values listed; every numeric setting states its range - troubleshooting for a blank panel after a settings change, jumping rows and brightness flashes Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(web): reject true and 5.5 for row_address_type and multiplexing Both still went straight through int(), so a JSON true saved as 1 and 5.5 as 5. They now use the shared hardware range check like the other panel fields. Review feedback on #586. Also: the RP1 Backend tooltip said it is ignored on Pi 3/4 (it is ignored on every model but the Pi 5), and the README gave the dynamic-duration default cap as 90s; the code default is 180s. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: refuse matrix settings a Raspberry Pi 5 can't drive On a Pi 5 the pinned rgbmatrix library drives the panel through the RP1 chip, and that path supports only row address types 0 and 2, parallel 1-3 and the regular / regular-pi1 / classic / adafruit-hat(-pwm) mappings (Rp1PioConfigSupported in lib/rp1/rp1_pio_backend.cc). For anything else CreateFromOptions returns NULL; the Python binding doesn't check, so the display process crashed on its first call into the matrix and systemd restarted it into the same crash every 10 seconds. - src/pi5_matrix_support.py: the rule and Pi 5 detection, matching the library's /proc/device-tree/model check - DisplayManager raises before creating the matrix, so it is a logged init failure (reported by /api/v3/hardware/status) and fallback mode - the config API rejects those settings on a Pi 5 when a request sets row_address_type, parallel or hardware_mapping - the Display form offers only row address types 0 and 2 on a Pi 5, and warns when a stored value can't be used - CLAUDE.md: re-check the rule whenever the submodule is bumped Review feedback on #586. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
80 lines
2.6 KiB
Python
80 lines
2.6 KiB
Python
"""The Pi 5 rule in src/pi5_matrix_support.py mirrors the pinned library.
|
|
|
|
Rp1PioPlatformDetected() and Rp1PioConfigSupported() in
|
|
rpi-rgb-led-matrix-master/lib/rp1/rp1_pio_backend.cc (commit 1ee4f76). When the
|
|
submodule is bumped and those change, these are the cases to revisit.
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from src import pi5_matrix_support as pi5 # noqa: E402
|
|
|
|
|
|
@pytest.fixture
|
|
def model_file(tmp_path, monkeypatch):
|
|
def write(model):
|
|
path = tmp_path / 'model'
|
|
# The device tree string is NUL-terminated.
|
|
path.write_bytes(model.encode() + b'\x00')
|
|
monkeypatch.setattr(pi5, 'MODEL_PATH', str(path))
|
|
return write
|
|
|
|
|
|
@pytest.mark.parametrize('model', [
|
|
'Raspberry Pi 5 Model B Rev 1.0',
|
|
'Raspberry Pi 500 Rev 1.0',
|
|
'Raspberry Pi Compute Module 5 Rev 1.0',
|
|
])
|
|
def test_pi5_family_is_detected(model_file, model):
|
|
model_file(model)
|
|
assert pi5.is_raspberry_pi_5()
|
|
|
|
|
|
@pytest.mark.parametrize('model', [
|
|
'Raspberry Pi 4 Model B Rev 1.5',
|
|
'Raspberry Pi Zero 2 W Rev 1.0',
|
|
'Raspberry Pi Compute Module 4 Rev 1.0',
|
|
])
|
|
def test_other_boards_are_not(model_file, model):
|
|
model_file(model)
|
|
assert not pi5.is_raspberry_pi_5()
|
|
|
|
|
|
def test_no_device_tree_is_not_a_pi5(tmp_path, monkeypatch):
|
|
monkeypatch.setattr(pi5, 'MODEL_PATH', str(tmp_path / 'missing'))
|
|
assert not pi5.is_raspberry_pi_5()
|
|
|
|
|
|
@pytest.mark.parametrize('hardware', [
|
|
{},
|
|
{'row_address_type': 0}, {'row_address_type': 2}, {'row_address_type': '2'},
|
|
{'parallel': 1}, {'parallel': 3},
|
|
{'hardware_mapping': 'regular'}, {'hardware_mapping': 'regular-pi1'},
|
|
{'hardware_mapping': 'classic'}, {'hardware_mapping': 'adafruit-hat'},
|
|
{'hardware_mapping': 'adafruit-hat-pwm'}, {'hardware_mapping': ''},
|
|
])
|
|
def test_what_the_pi5_path_supports(hardware):
|
|
assert pi5.pi5_unsupported_settings(hardware) is None
|
|
|
|
|
|
@pytest.mark.parametrize('hardware,named', [
|
|
({'row_address_type': 1}, 'row address type 1'),
|
|
({'row_address_type': 3}, 'row address type 3'),
|
|
({'row_address_type': 4}, 'row address type 4'),
|
|
({'row_address_type': '5'}, 'row address type 5'),
|
|
({'parallel': 4}, 'parallel 4'),
|
|
({'hardware_mapping': 'compute-module'}, 'hardware mapping "compute-module"'),
|
|
])
|
|
def test_what_it_does_not(hardware, named):
|
|
message = pi5.pi5_unsupported_settings(hardware)
|
|
assert message is not None and named in message
|
|
|
|
|
|
def test_every_problem_is_named():
|
|
message = pi5.pi5_unsupported_settings({'row_address_type': 5, 'parallel': 4})
|
|
assert 'row address type 5' in message and 'parallel 4' in message
|