From 98e619fbe17039ba21cbf5e20968b964bbcaf89f Mon Sep 17 00:00:00 2001 From: Anders Brownworth Date: Sun, 2 Aug 2026 07:56:29 -0400 Subject: [PATCH] gate non-functional IT8951 (13in3gray) driver behind experimental option --- README.md | 14 ++++++++++++-- displays/EPD13in3Gray.js | 12 ++++++++++++ displays/index.js | 2 +- examples/grayscale-16level.js | 4 +++- test/run-tests.js | 18 ++++++++++++++++++ 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 816a171..3621843 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,11 @@ Not all devices have been tested in the field. Please create a GitHub issue if y | 7in3f | 800 × 480 | 7-color | 7.3" full color (7 colors) | Untested | | 13in3k | 960 × 680 | Mono, 4-grayscale | 13.3" with grayscale support | Confirmed working | | 13in3b | 960 × 680 | 3-color | 13.3" black/white/red or yellow | Untested | -| 13in3gray | 1600 × 1200 | 16-grayscale | 13.3" 16-level grayscale (IT8951) | Untested | +| 13in3gray | 1600 × 1200 | 16-grayscale | 13.3" 16-level grayscale (IT8951) | Experimental — not functional | + +Note: the 13in3gray driver is gated behind an `experimental: true` option +because the IT8951's 16-bit command protocol is not yet implemented — +constructing it without that option throws. Contributions welcome. ## Installation @@ -100,6 +104,11 @@ const { createDisplay } = require('waveshare-epaper'); ``` ### 16-grayscale Example (IT8951 Controller) + +> ⚠️ **Experimental:** this driver does not yet speak the IT8951's actual +> protocol and will not drive the panel. The example shows the intended API; +> it requires `experimental: true` to run. + ```javascript const { createDisplay } = require('waveshare-epaper'); @@ -109,7 +118,8 @@ const { createDisplay } = require('waveshare-epaper'); dcPin: 25, busyPin: 24, pwrPin: 18, - vcom: -2.30 // Adjust according to your display + vcom: -2.30, // Adjust according to your display + experimental: true // Driver is not yet functional; see note above }); await epd.init(); diff --git a/displays/EPD13in3Gray.js b/displays/EPD13in3Gray.js index e514a7b..97a6864 100644 --- a/displays/EPD13in3Gray.js +++ b/displays/EPD13in3Gray.js @@ -4,6 +4,18 @@ class EPD13in3Gray extends EPDBase { constructor(options = {}) { super(options); + // The IT8951 controller speaks a different protocol than the other + // panels: 16-bit command words with 0x6000/0x0000 preambles and SPI + // reads, none of which this driver implements yet - as written it + // sends truncated bytes the controller cannot understand. + if (!options.experimental) { + throw new Error( + 'The 13in3gray (IT8951) driver is experimental and not yet functional: ' + + 'the IT8951 16-bit command protocol is not implemented. ' + + 'Pass { experimental: true } to construct it anyway for development.' + ); + } + // 13.3 inch display with 1600x1200 resolution this.width = 1600; this.height = 1200; diff --git a/displays/index.js b/displays/index.js index 5dbd30f..49095a5 100644 --- a/displays/index.js +++ b/displays/index.js @@ -79,7 +79,7 @@ module.exports = { { model: '7in3f', size: '800x480', colorModes: ['7color'], description: '7.3" full color (7 colors)' }, { model: '13in3k', size: '960x680', colorModes: ['mono', '4gray'], description: '13.3" mono/4-grayscale' }, { model: '13in3b', size: '960x680', colorModes: ['3color'], description: '13.3" black/white/red' }, - { model: '13in3gray', size: '1600x1200', colorModes: ['16gray'], description: '13.3" 16-level grayscale (IT8951)' } + { model: '13in3gray', size: '1600x1200', colorModes: ['16gray'], description: '13.3" 16-level grayscale (IT8951) - EXPERIMENTAL, driver not yet functional', experimental: true } ]; } }; \ No newline at end of file diff --git a/examples/grayscale-16level.js b/examples/grayscale-16level.js index d30f5e0..d377387 100644 --- a/examples/grayscale-16level.js +++ b/examples/grayscale-16level.js @@ -1,7 +1,9 @@ const { createDisplay } = require('waveshare-epaper'); async function main() { - const display = createDisplay('13in3gray', '16gray'); + // NOTE: the IT8951 driver is experimental and does not yet drive the + // panel - this example shows the intended API only + const display = createDisplay('13in3gray', '16gray', { experimental: true }); try { await display.init(); diff --git a/test/run-tests.js b/test/run-tests.js index 4df3a35..b391306 100644 --- a/test/run-tests.js +++ b/test/run-tests.js @@ -146,6 +146,24 @@ test('waitUntilIdle: UC8176-class (7in5, 7in3f) waits while BUSY reads 0', async assert.strictEqual(await countBusyPolls('7in3f', [0, 1]), 2); }); +// --- Experimental driver gating ------------------------------------------- + +test('13in3gray (IT8951) is gated behind the experimental option', () => { + const { gpio, spi } = createMockHal(); + + assert.throws( + () => createDisplay('13in3gray', '16gray', { gpio, spi }), + /experimental and not yet functional/ + ); + + const epd = createDisplay('13in3gray', '16gray', { gpio, spi, experimental: true }); + assert.strictEqual(epd.width, 1600); + + const { getSupportedModels } = require('..'); + const entry = getSupportedModels().find(m => m.model === '13in3gray'); + assert.strictEqual(entry.experimental, true); +}); + // --- Native GPIO backend -------------------------------------------------- // Fake node-libgpiod binding matching the Chip/Line API of v0.6