mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 14:25: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>
71 lines
3.1 KiB
Python
71 lines
3.1 KiB
Python
"""Which matrix settings the pinned rgbmatrix library can drive on a Raspberry Pi 5.
|
|
|
|
On a Pi 5 the library drives the panel through the RP1 chip, and at the pinned
|
|
rpi-rgb-led-matrix-master commit (1ee4f76) that path supports only some
|
|
settings -- ``Rp1PioConfigSupported()`` in ``lib/rp1/rp1_pio_backend.cc``. For
|
|
anything else ``RGBMatrix::CreateFromOptions()`` returns NULL. The Python
|
|
binding does not check for that, so instead of raising, the display process
|
|
crashes on its first call into the matrix, and systemd restarts it into the
|
|
same crash every 10 seconds.
|
|
|
|
``DisplayManager`` checks this rule before creating the matrix, turning that
|
|
crash into a logged error and the usual fallback mode. The config API and the
|
|
Display form use the same rule to refuse the settings up front.
|
|
|
|
**Re-check this when the submodule is bumped.** Upstream is extending Pi 5
|
|
support (e.g. 4e326c1b, "Pi5 - Improvements, additional led-row-addr-type
|
|
support"); a stale rule here would block settings the new library drives.
|
|
"""
|
|
|
|
from typing import Any, Mapping, Optional
|
|
|
|
#: Read the way the library's ``Rp1PioPlatformDetected()`` reads it.
|
|
MODEL_PATH = "/proc/device-tree/model"
|
|
PI5_MODEL_MARKERS = ("Raspberry Pi 5", "Compute Module 5")
|
|
|
|
PI5_ROW_ADDRESS_TYPES = (0, 2)
|
|
PI5_MAX_PARALLEL = 3
|
|
PI5_HARDWARE_MAPPINGS = ("regular", "regular-pi1", "classic", "adafruit-hat", "adafruit-hat-pwm")
|
|
|
|
|
|
def is_raspberry_pi_5() -> bool:
|
|
"""True on a Pi 5-family board: Pi 5, Pi 500 or Compute Module 5."""
|
|
try:
|
|
with open(MODEL_PATH, "rb") as f:
|
|
model = f.read(256).decode("utf-8", "replace")
|
|
except OSError:
|
|
return False
|
|
return any(marker in model for marker in PI5_MODEL_MARKERS)
|
|
|
|
|
|
def _as_int(value: Any, default: int) -> Optional[int]:
|
|
if value is None or value == "":
|
|
return default
|
|
try:
|
|
return int(value)
|
|
except (TypeError, ValueError, OverflowError):
|
|
return None
|
|
|
|
|
|
def pi5_unsupported_settings(hardware: Mapping[str, Any]) -> Optional[str]:
|
|
"""Why a Pi 5 can't drive this ``display.hardware`` config, or None if it can.
|
|
|
|
Missing keys take DisplayManager's defaults. A value that isn't a number is
|
|
left to the caller's own validation rather than reported here.
|
|
"""
|
|
problems = []
|
|
row_address_type = _as_int(hardware.get("row_address_type"), 0)
|
|
if row_address_type is not None and row_address_type not in PI5_ROW_ADDRESS_TYPES:
|
|
problems.append(f"row address type {row_address_type} (only 0 and 2 are supported)")
|
|
parallel = _as_int(hardware.get("parallel"), 1)
|
|
if parallel is not None and not 1 <= parallel <= PI5_MAX_PARALLEL:
|
|
problems.append(f"parallel {parallel} (1 to {PI5_MAX_PARALLEL} are supported)")
|
|
mapping = hardware.get("hardware_mapping", "adafruit-hat-pwm")
|
|
# The library treats an empty mapping as "regular".
|
|
if isinstance(mapping, str) and (mapping or "regular") not in PI5_HARDWARE_MAPPINGS:
|
|
problems.append(f'hardware mapping "{mapping}"')
|
|
if not problems:
|
|
return None
|
|
return ("Not supported on a Raspberry Pi 5 by the installed rgbmatrix library: "
|
|
+ "; ".join(problems) + ".")
|