From 89a9731dff66d896a8f41682b7441a691853469b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Flar=20Onur?= Date: Sat, 16 May 2026 11:36:01 -0700 Subject: [PATCH] inky: fix blend precision, height quirk, and minor cleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix color blending truncation in blend(): compute the full weighted sum as float64 before casting to uint8, avoiding double truncation - Fix UC8159 on IMPRESSION57 incorrectly reporting height as 447; correct it to 448 in DetectOpts - Add Opts.String() for human-readable option printing - Refactor update() if/else chain to a switch statement - Add TestDevImpression_BlendPrecision to cover the blend fix Signed-off-by: Çağlar Onur --- inky/impression.go | 25 ++++++++++----------- inky/impression_test.go | 48 +++++++++++++++++++++++++++++++++++++++++ inky/opts.go | 8 +++++++ 3 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 inky/impression_test.go diff --git a/inky/impression.go b/inky/impression.go index c64b557..4a76162 100644 --- a/inky/impression.go +++ b/inky/impression.go @@ -283,16 +283,11 @@ func (d *DevImpression) blend() color.Palette { pr := make([]color.Color, 0) for i := range satPalette { - rs, gs, bs := uint8(float64(satPalette[i].R)*sat), - uint8(float64(satPalette[i].G)*sat), - uint8(float64(satPalette[i].B)*sat) + r := uint8(float64(satPalette[i].R)*sat + float64(dscPalette[i].R)*(1.0-sat)) + g := uint8(float64(satPalette[i].G)*sat + float64(dscPalette[i].G)*(1.0-sat)) + b := uint8(float64(satPalette[i].B)*sat + float64(dscPalette[i].B)*(1.0-sat)) - rd, gd, bd := - uint8(float64(dscPalette[i].R)*(1.0-sat)), - uint8(float64(dscPalette[i].G)*(1.0-sat)), - uint8(float64(dscPalette[i].B)*(1.0-sat)) - - pr = append(pr, color.RGBA{rs + rd, gs + gd, bs + bd, dscPalette[i].A}) + pr = append(pr, color.RGBA{r, g, b, dscPalette[i].A}) } if d.Dev.model == IMPRESSION73SPECTRA6 { @@ -567,6 +562,7 @@ func (d *DevImpression) resetEC() error { if err := d.sendCommand(el673PSR, []byte{0x5F, 0x69}); err != nil { return err } + if err := d.sendCommand(el673BTST1, []byte{0x40, 0x1F, 0x1F, 0x2C}); err != nil { return err } @@ -576,6 +572,7 @@ func (d *DevImpression) resetEC() error { if err := d.sendCommand(el673BTST2, []byte{0x6F, 0x1F, 0x17, 0x17}); err != nil { return err } + if err := d.sendCommand(el673POFS, []byte{0x00, 0x54, 0x00, 0x44}); err != nil { return err } @@ -602,12 +599,14 @@ func (d *DevImpression) resetEC() error { } func (d *DevImpression) update(pix []uint8) error { - if d.model == IMPRESSION73 { + switch d.model { + case IMPRESSION73: return d.updateAC(pix) - } else if d.model == IMPRESSION73SPECTRA6 { + case IMPRESSION73SPECTRA6: return d.updateEC(pix) + default: + return d.updateUC(pix) } - return d.updateUC(pix) } func (d *DevImpression) updateUC(pix []uint8) error { @@ -710,10 +709,12 @@ func (d *DevImpression) wait(dur time.Duration) { log.Printf("Err: %s", err) return } + if d.busy.Read() == gpio.High { time.Sleep(dur) return } + // Wait for rising edges (Low -> High) or the timeout. tEnd := time.Now().Add(dur) edgeDur := dur diff --git a/inky/impression_test.go b/inky/impression_test.go new file mode 100644 index 0000000..e53dfbc --- /dev/null +++ b/inky/impression_test.go @@ -0,0 +1,48 @@ +// Copyright 2019 The Periph Authors. All rights reserved. +// Use of this source code is governed under the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +package inky + +import ( + "image/color" + "testing" +) + +func TestDevImpression_BlendPrecision(t *testing.T) { + // Saturation level that triggers truncation if not handled correctly. + // For example, if rs=10.9 and rd=5.9: + // Old: uint8(10.9) + uint8(5.9) = 10 + 5 = 15 + // New: uint8(10.9 + 5.9) = uint8(16.8) = 16 + + // We need to simulate this with real palette values and saturation. + // Let's use a simplified case. + // satPalette[0].R = 109, dscPalette[0].R = 59, saturation = 10% + // rs = 109 * 0.1 = 10.9 + // rd = 59 * 0.9 = 53.1 + // Old: 10 + 53 = 63 + // New: uint8(10.9 + 53.1) = uint8(64.0) = 64 + + d := &DevImpression{ + saturation: 10, + } + d.Dev.model = IMPRESSION73 // This uses sc7 and dsc + + // Override sc7 and dsc for the test up to at least common length + oldSc7 := sc7 + oldDsc := dsc + defer func() { + sc7 = oldSc7 + dsc = oldDsc + }() + + sc7 = []color.NRGBA{{R: 109, G: 0, B: 0, A: 255}} + dsc = []color.NRGBA{{R: 59, G: 0, B: 0, A: 255}} + + p := d.blend() + c := p[0].(color.RGBA) + + if c.R != 64 { + t.Errorf("Expected R=64, got %d. Precision loss detected!", c.R) + } +} diff --git a/inky/opts.go b/inky/opts.go index acc63e2..b6e4df4 100644 --- a/inky/opts.go +++ b/inky/opts.go @@ -97,6 +97,10 @@ func DetectOpts(bus i2c.Bus) (*Opts, error) { options.Model = WHAT case 14: options.Model = IMPRESSION57 + // Some UC8159's report Height as 447 so fix that. + if options.Height == 447 { + options.Height = 448 + } case 15, 16: options.Model = IMPRESSION4 case 20: @@ -124,3 +128,7 @@ func readEep(bus i2c.Bus) ([]byte, error) { return data, nil } + +func (o *Opts) String() string { + return fmt.Sprintf("Resolution: %dx%d Model: %s Model Color: %s Border Color: %s PCB Variant: %d Display Variant: %d", o.Width, o.Height, o.Model, o.ModelColor, o.BorderColor, o.PCBVariant, o.DisplayVariant) +}