From 6052af94b0b0d7d156f459546c0eb8777e64a3c1 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Thu, 23 Dec 2021 10:10:27 +0100 Subject: [PATCH] waveshare213v2: Move initialization to testable functions --- waveshare2in13v2/controller.go | 75 +++++++++++++++++++ waveshare2in13v2/controller_test.go | 110 ++++++++++++++++++++++++++++ waveshare2in13v2/drawing.go | 5 -- waveshare2in13v2/drawing_test.go | 18 ----- waveshare2in13v2/waveshare213v2.go | 91 ++--------------------- 5 files changed, 191 insertions(+), 108 deletions(-) create mode 100644 waveshare2in13v2/controller.go create mode 100644 waveshare2in13v2/controller_test.go diff --git a/waveshare2in13v2/controller.go b/waveshare2in13v2/controller.go new file mode 100644 index 0000000..2f1eace --- /dev/null +++ b/waveshare2in13v2/controller.go @@ -0,0 +1,75 @@ +// Copyright 2021 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 waveshare2in13v2 + +type controller interface { + sendCommand(byte) + sendData([]byte) + waitUntilIdle() +} + +func initDisplayFull(ctrl controller, opts *Opts) { + ctrl.waitUntilIdle() + ctrl.sendCommand(swReset) + ctrl.waitUntilIdle() + + ctrl.sendCommand(setAnalogBlockControl) + ctrl.sendData([]byte{0x54}) + + ctrl.sendCommand(setDigitalBlockControl) + ctrl.sendData([]byte{0x3B}) + + ctrl.sendCommand(driverOutputControl) + ctrl.sendData([]byte{ + byte((opts.Height - 1) % 0xFF), + byte((opts.Height - 1) / 0xFF), + 0x00, + }) + + ctrl.sendCommand(borderWaveformControl) + ctrl.sendData([]byte{0x03}) + + ctrl.sendCommand(writeVcomRegister) + ctrl.sendData([]byte{0x55}) + + ctrl.sendCommand(gateDrivingVoltageControl) + ctrl.sendData([]byte{gateDrivingVoltage19V}) + + ctrl.sendCommand(sourceDrivingVoltageControl) + ctrl.sendData([]byte{sourceDrivingVoltageVSH1_15V, sourceDrivingVoltageVSH2_5V, sourceDrivingVoltageVSL_neg15V}) + + ctrl.sendCommand(setDummyLinePeriod) + ctrl.sendData([]byte{0x30}) + + ctrl.sendCommand(setGateTime) + ctrl.sendData([]byte{0x0A}) + + ctrl.sendCommand(writeLutRegister) + ctrl.sendData(opts.FullUpdate[:70]) +} + +func initDisplayPartial(ctrl controller, opts *Opts) { + ctrl.sendCommand(writeVcomRegister) + ctrl.sendData([]byte{0x26}) + + ctrl.waitUntilIdle() + + ctrl.sendCommand(writeLutRegister) + ctrl.sendData(opts.PartialUpdate[:70]) + + // Undocumented command used in vendor example code. + ctrl.sendCommand(0x37) + ctrl.sendData([]byte{0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00}) + + ctrl.sendCommand(displayUpdateControl2) + ctrl.sendData([]byte{0xC0}) + + ctrl.sendCommand(masterActivation) + + ctrl.waitUntilIdle() + + ctrl.sendCommand(borderWaveformControl) + ctrl.sendData([]byte{0x01}) +} diff --git a/waveshare2in13v2/controller_test.go b/waveshare2in13v2/controller_test.go new file mode 100644 index 0000000..ec3de83 --- /dev/null +++ b/waveshare2in13v2/controller_test.go @@ -0,0 +1,110 @@ +// Copyright 2021 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 waveshare2in13v2 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" +) + +type record struct { + cmd byte + data []byte +} + +type fakeController []record + +func (r *fakeController) sendCommand(cmd byte) { + *r = append(*r, record{ + cmd: cmd, + }) +} + +func (r *fakeController) sendData(data []byte) { + cur := &(*r)[len(*r)-1] + cur.data = append(cur.data, data...) +} + +func (*fakeController) waitUntilIdle() { +} + +func TestInitDisplayFull(t *testing.T) { + for _, tc := range []struct { + name string + opts Opts + want []record + }{ + { + name: "epd2in13v2", + opts: EPD2in13v2, + want: []record{ + {cmd: swReset}, + {cmd: setAnalogBlockControl, data: []byte{0x54}}, + {cmd: setDigitalBlockControl, data: []byte{0x3b}}, + { + cmd: driverOutputControl, + data: []byte{250 - 1, 0, 0}, + }, + {cmd: borderWaveformControl, data: []byte{0x03}}, + {cmd: writeVcomRegister, data: []byte{0x55}}, + {cmd: gateDrivingVoltageControl, data: []byte{gateDrivingVoltage19V}}, + { + cmd: sourceDrivingVoltageControl, + data: []byte{ + sourceDrivingVoltageVSH1_15V, + sourceDrivingVoltageVSH2_5V, + sourceDrivingVoltageVSL_neg15V, + }, + }, + {cmd: setDummyLinePeriod, data: []byte{0x30}}, + {cmd: setGateTime, data: []byte{0x0a}}, + {cmd: writeLutRegister, data: EPD2in13v2.FullUpdate}, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + var got fakeController + + initDisplayFull(&got, &tc.opts) + + if diff := cmp.Diff([]record(got), tc.want, cmpopts.EquateEmpty(), cmp.AllowUnexported(record{})); diff != "" { + t.Errorf("initDisplayFull() difference (-got +want):\n%s", diff) + } + }) + } +} + +func TestInitDisplayPartial(t *testing.T) { + for _, tc := range []struct { + name string + opts Opts + want []record + }{ + { + name: "epd2in13v2", + opts: EPD2in13v2, + want: []record{ + {cmd: writeVcomRegister, data: []byte{0x26}}, + {cmd: writeLutRegister, data: EPD2in13v2.PartialUpdate}, + {cmd: 0x37, data: []byte{0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00}}, + {cmd: displayUpdateControl2, data: []byte{0xc0}}, + {cmd: masterActivation}, + {cmd: borderWaveformControl, data: []byte{0x01}}, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + var got fakeController + + initDisplayPartial(&got, &tc.opts) + + if diff := cmp.Diff([]record(got), tc.want, cmpopts.EquateEmpty(), cmp.AllowUnexported(record{})); diff != "" { + t.Errorf("initDisplayPartial() difference (-got +want):\n%s", diff) + } + }) + } +} diff --git a/waveshare2in13v2/drawing.go b/waveshare2in13v2/drawing.go index 4fe200d..f606a11 100644 --- a/waveshare2in13v2/drawing.go +++ b/waveshare2in13v2/drawing.go @@ -12,11 +12,6 @@ import ( "periph.io/x/devices/v3/ssd1306/image1bit" ) -type controller interface { - sendCommand(byte) - sendData([]byte) -} - // setMemoryArea configures the target drawing area (horizontal is in bytes, // vertical in pixels). func setMemoryArea(ctrl controller, area image.Rectangle) { diff --git a/waveshare2in13v2/drawing_test.go b/waveshare2in13v2/drawing_test.go index 087bd43..7ad5476 100644 --- a/waveshare2in13v2/drawing_test.go +++ b/waveshare2in13v2/drawing_test.go @@ -14,24 +14,6 @@ import ( "periph.io/x/devices/v3/ssd1306/image1bit" ) -type record struct { - cmd byte - data []byte -} - -type fakeController []record - -func (r *fakeController) sendCommand(cmd byte) { - *r = append(*r, record{ - cmd: cmd, - }) -} - -func (r *fakeController) sendData(data []byte) { - cur := &(*r)[len(*r)-1] - cur.data = append(cur.data, data...) -} - func TestDrawSpec(t *testing.T) { for _, tc := range []struct { name string diff --git a/waveshare2in13v2/waveshare213v2.go b/waveshare2in13v2/waveshare213v2.go index 79b37ba..11b4deb 100644 --- a/waveshare2in13v2/waveshare213v2.go +++ b/waveshare2in13v2/waveshare213v2.go @@ -154,89 +154,6 @@ func NewHat(p spi.Port, opts *Opts) (*Dev, error) { return New(p, dc, cs, rst, busy, opts) } -func (d *Dev) initFull() error { - eh := errorHandler{d: *d} - - // Software Reset - eh.waitUntilIdle() - eh.sendCommand(swReset) - eh.waitUntilIdle() - - // Set analog block control - eh.sendCommand(setAnalogBlockControl) - eh.sendData([]byte{0x54}) - - // Set digital block control - eh.sendCommand(setDigitalBlockControl) - eh.sendData([]byte{0x3B}) - - // Driver output control - eh.sendCommand(driverOutputControl) - eh.sendData([]byte{ - byte((d.opts.Height - 1) % 0xFF), - byte((d.opts.Height - 1) / 0xFF), - 0x00, - }) - - // Border Waveform - eh.sendCommand(borderWaveformControl) - eh.sendData([]byte{0x03}) - - // VCOM Voltage - eh.sendCommand(writeVcomRegister) - eh.sendData([]byte{0x55}) - - eh.sendCommand(gateDrivingVoltageControl) - eh.sendData([]byte{gateDrivingVoltage19V}) - - eh.sendCommand(sourceDrivingVoltageControl) - eh.sendData([]byte{sourceDrivingVoltageVSH1_15V, sourceDrivingVoltageVSH2_5V, sourceDrivingVoltageVSL_neg15V}) - - // Dummy Line - eh.sendCommand(setDummyLinePeriod) - eh.sendData([]byte{0x30}) - - // Gate Time - eh.sendCommand(setGateTime) - eh.sendData([]byte{0x0A}) - - eh.sendCommand(writeLutRegister) - eh.sendData(d.opts.FullUpdate[:70]) - - eh.waitUntilIdle() - - return eh.err -} - -func (d *Dev) initPartial() error { - eh := errorHandler{d: *d} - - // VCOM Voltage - eh.sendCommand(writeVcomRegister) - eh.sendData([]byte{0x26}) - - eh.waitUntilIdle() - - eh.sendCommand(writeLutRegister) - eh.sendData(d.opts.PartialUpdate[:70]) - - eh.sendCommand(0x37) - eh.sendData([]byte{0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00}) - - eh.sendCommand(displayUpdateControl2) - eh.sendData([]byte{0xC0}) - - eh.sendCommand(masterActivation) - - eh.waitUntilIdle() - - // Border Waveform - eh.sendCommand(borderWaveformControl) - eh.sendData([]byte{0x01}) - - return eh.err -} - // Init will initialize the display with the partial-update or full-update mode. func (d *Dev) Init(partialUpdate PartialUpdate) error { // Hardware Reset @@ -244,11 +161,15 @@ func (d *Dev) Init(partialUpdate PartialUpdate) error { return err } + eh := errorHandler{d: *d} + if partialUpdate { - return d.initPartial() + initDisplayPartial(&eh, d.opts) + } else { + initDisplayFull(&eh, d.opts) } - return d.initFull() + return eh.err } // Clear clears the display.