[inky] Add Inky Impression 5.7" and 4" support (#55)

It is a 7 colour ePaper/eInk HAT that comes with 5.7" (600 x 448 pixel) or 4" (640 x 400 pixel).

Refactors the existing 3 color Inky and adds additional fields to
auto-detect via EEPROM.

Tested with 5.7" version.
pull/57/head
Çağlar Onur 3 years ago committed by GitHub
parent ae3205944c
commit e271f7c07b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -128,6 +128,7 @@ jobs:
go install github.com/securego/gosec/v2/cmd/gosec@latest
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
go install golang.org/x/tools/cmd/stringer@latest
- name: 'go install necessary tools (ubuntu)'
if: always() && matrix.os == 'ubuntu-latest'
run: |

@ -12,6 +12,7 @@ import (
"os"
"periph.io/x/conn/v3/gpio/gpioreg"
"periph.io/x/conn/v3/i2c/i2creg"
"periph.io/x/conn/v3/spi/spireg"
"periph.io/x/devices/v3/inky"
"periph.io/x/host/v3"
@ -58,3 +59,52 @@ func Example() {
log.Fatal(err)
}
}
func ExampleNewImpression() {
path := flag.String("image", "", "Path to image file (600x448) to display")
flag.Parse()
f, err := os.Open(*path)
if err != nil {
log.Fatal(err)
}
defer f.Close()
m, _, err := image.Decode(f)
if err != nil {
log.Fatal(err)
}
if _, err = host.Init(); err != nil {
log.Fatal(err)
}
b, err := spireg.Open("SPI0.0")
if err != nil {
log.Fatal(err)
}
dc := gpioreg.ByName("22")
reset := gpioreg.ByName("27")
busy := gpioreg.ByName("17")
eeprom, err := i2creg.Open("")
if err != nil {
log.Fatal(err)
}
defer eeprom.Close()
o, err := inky.DetectOpts(eeprom)
if err != nil {
log.Fatal(err)
}
dev, err := inky.NewImpression(b, dc, reset, busy, o)
if err != nil {
log.Fatal(err)
}
if err := dev.Draw(m.Bounds(), m, image.Point{}); err != nil {
log.Fatal(err)
}
}

@ -0,0 +1,414 @@
// Copyright 2023 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 (
"encoding/binary"
"fmt"
"image"
"image/color"
"image/draw"
"log"
"time"
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/display"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/spi"
)
var _ display.Drawer = &DevImpression{}
var _ conn.Resource = &DevImpression{}
var _ draw.Image = &DevImpression{}
var (
// For more: https://github.com/pimoroni/inky/issues/115#issuecomment-887453065
dsc = []color.NRGBA{
{0, 0, 0, 0}, // Black
{255, 255, 255, 255}, // White
{0, 255, 0, 255}, // Green
{0, 0, 255, 255}, // Blue
{255, 0, 0, 255}, // Red
{255, 255, 0, 255}, // Yellow
{255, 140, 0, 255}, // Orange
{255, 255, 255, 255},
}
sc = []color.NRGBA{
{57, 48, 57, 0}, // Black
{255, 255, 255, 255}, // White
{58, 91, 70, 255}, // Green
{61, 59, 94, 255}, // Blue
{156, 72, 75, 255}, // Red
{208, 190, 71, 255}, // Yellow
{177, 106, 73, 255}, // Orange
{255, 255, 255, 255},
}
)
const (
uc8159PSR = 0x00
uc8159PWR = 0x01
uc8159POF = 0x02
uc8159PFS = 0x03
uc8159PON = 0x04
uc8159BTST = 0x06
uc8159DSLP = 0x07
uc8159DTM1 = 0x10
uc8159DSP = 0x11
uc8159DRF = 0x12
uc8159IPC = 0x13
uc8159PLL = 0x30
uc8159TSC = 0x40
uc8159TSE = 0x41
uc8159TSW = 0x42
uc8159TSR = 0x43
uc8159CDI = 0x50
uc8159LPD = 0x51
uc8159TCON = 0x60
uc8159TRES = 0x61
uc8159DAM = 0x65
uc8159REV = 0x70
uc8159FLG = 0x71
uc8159AMV = 0x80
uc8159VV = 0x81
uc8159VDCS = 0x82
uc8159PWS = 0xE3
uc8159TSSET = 0xE5
)
// DevImpression is a handle to an Inky Impression.
type DevImpression struct {
*Dev
// Color Palette used to convert images to the 7 color.
Palette color.Palette
// Representation of the pixels.
Pix []uint8
// Saturation level used by the color palette.
saturation uint
// Resolution magic number used for resetting the panel.
res int
}
// NewImpression opens a handle to an Inky Impression.
func NewImpression(p spi.Port, dc gpio.PinOut, reset gpio.PinOut, busy gpio.PinIn, o *Opts) (*DevImpression, error) {
if o.ModelColor != Multi {
return nil, fmt.Errorf("unsupported color: %v", o.ModelColor)
}
c, err := p.Connect(3000*physic.KiloHertz, spi.Mode0, cs0Pin)
if err != nil {
return nil, fmt.Errorf("failed to connect to inky over spi: %v", err)
}
// Get the maxTxSize from the conn if it implements the conn.Limits interface,
// otherwise use 4096 bytes.
maxTxSize := 0
if limits, ok := c.(conn.Limits); ok {
maxTxSize = limits.MaxTxSize()
}
if maxTxSize == 0 {
maxTxSize = 4096 // Use a conservative default.
}
d := &DevImpression{
Dev: &Dev{
c: c,
maxTxSize: maxTxSize,
dc: dc,
r: reset,
busy: busy,
color: o.ModelColor,
border: o.BorderColor,
model: o.Model,
variant: o.DisplayVariant,
pcbVariant: o.PCBVariant,
},
saturation: 50, // Looks good enough for most of the images.
}
switch o.Model {
case IMPRESSION4:
d.width = 640
d.height = 400
d.res = 0b10
case IMPRESSION57:
d.width = 600
d.height = 448
d.res = 0b11
}
// Prefer the passed in values via Opts.
if o.Width == 0 && o.Height == 0 {
d.width = o.Width
d.height = o.Height
}
d.bounds = image.Rect(0, 0, d.width, d.height)
d.Pix = make([]uint8, d.height*d.width)
return d, nil
}
// blend recalculates the palette based on the saturation level.
func (d *DevImpression) blend() []color.Color {
sat := float64(d.saturation / 100)
pr := []color.Color{}
for i := 0; i < 7; i++ {
rs, gs, bs :=
uint8(float64(sc[i].R)*sat),
uint8(float64(sc[i].G)*sat),
uint8(float64(sc[i].B)*sat)
rd, gd, bd :=
uint8(float64(dsc[i].R)*(1.0-sat)),
uint8(float64(dsc[i].G)*(1.0-sat)),
uint8(float64(dsc[i].B)*(1.0-sat))
pr = append(pr, color.RGBA{rs + rd, gs + gd, bs + bd, dsc[i].A})
}
// Add Transparent color and return the result.
return append(pr, color.RGBA{255, 255, 255, 0})
}
// Saturation returns the current saturation level.
func (d *DevImpression) Saturation() uint {
return d.saturation
}
// SetSaturaton changes the saturation level. This will not take effect until the next Draw().
func (d *DevImpression) SetSaturation(level uint) error {
if level > 100 {
return fmt.Errorf("saturation level needs to be between 0 and 100")
}
d.saturation = level
// so that caller can recalculate next time they need it.
d.Palette = nil
return nil
}
// SetBorder changes the border color. This will not take effect until the next Draw().
func (d *DevImpression) SetBorder(c ImpressionColor) {
d.border = Color(c)
}
// Render renders the content of the Pix to the screen.
func (d *DevImpression) Render() error {
if d.flipVertically {
for w := 0; w < len(d.Pix)/2-1; w = w + d.width {
for offset := 0; offset < d.width; offset++ {
d.Pix[w+offset], d.Pix[len(d.Pix)-d.width-w+offset] = d.Pix[len(d.Pix)-d.width-w+offset], d.Pix[w+offset]
}
}
}
if d.flipHorizontally {
for offset := 0; offset < len(d.Pix)-1; offset = offset + d.width {
for i, j := 0, d.width-1; i < j; i, j = i+1, j-1 {
d.Pix[i+offset], d.Pix[j+offset] = d.Pix[j+offset], d.Pix[i+offset]
}
}
}
merged := make([]uint8, len(d.Pix)/2)
for i, offset := 0, 0; i < len(d.Pix)-1; i, offset = i+2, offset+1 {
merged[offset] = (d.Pix[i]<<4)&0xF0 | d.Pix[i+1]&0x0F
}
return d.update(merged)
}
func (d *DevImpression) reset() error {
if err := d.r.Out(gpio.Low); err != nil {
return err
}
time.Sleep(100 * time.Millisecond)
if err := d.r.Out(gpio.High); err != nil {
return err
}
d.wait(1 * time.Second)
// Resolution Setting
// 10bit horizontal followed by a 10bit vertical resolution
tres := make([]byte, 4)
binary.LittleEndian.PutUint16(tres[0:], uint16(d.width))
binary.LittleEndian.PutUint16(tres[2:], uint16(d.height))
if err := d.sendCommand(uc8159TRES, tres); err != nil {
return err
}
// Panel Setting
// 0b11000000 = Resolution select, 0b00 = 640x480, our panel is 0b11 = 600x448
// 0b00100000 = LUT selection, 0 = ext flash, 1 = registers, we use ext flash
// 0b00010000 = Ignore
// 0b00001000 = Gate scan direction, 0 = down, 1 = up (default)
// 0b00000100 = Source shift direction, 0 = left, 1 = right (default)
// 0b00000010 = DC-DC converter, 0 = off, 1 = on
// 0b00000001 = Soft reset, 0 = Reset, 1 = Normal (Default)
// 0b11 = 600x448
// 0b10 = 640x400
if err := d.sendCommand(
uc8159PSR,
[]byte{
byte(d.res<<6) | 0b101111, // See above for more magic numbers
0x08, // display_colours == UC81597C
}); err != nil {
return err
}
// Power Settings
if err := d.sendCommand(
uc8159PWR,
[]byte{
(0x06 << 3) | // ??? - not documented in UC8159 datasheet
(0x01 << 2) | // SOURCE_INTERNAL_DC_DC
(0x01 << 1) | // GATE_INTERNAL_DC_DC
(0x01), // LV_SOURCE_INTERNAL_DC_DC
0x00, // VGx_20V
0x23, // UC81597C
0x23, // UC81597C
}); err != nil {
return err
}
// Set the PLL clock frequency to 50Hz
// 0b11000000 = Ignore
// 0b00111000 = M
// 0b00000111 = N
// PLL = 2MHz * (M / N)
// PLL = 2MHz * (7 / 4)
// PLL = 2,800,000 ???
if err := d.sendCommand(uc8159PLL, []byte{0x3C}); err != nil {
return err
}
// 0b00111100
// Send the TSE register to the display
if err := d.sendCommand(uc8159TSE, []byte{0x00}); err != nil { // Color
return err
}
// VCOM and Data Interval setting
// 0b11100000 = Vborder control (0b001 = LUTB voltage)
// 0b00010000 = Data polarity
// 0b00001111 = Vcom and data interval (0b0111 = 10, default)
cdi := make([]byte, 2)
binary.LittleEndian.PutUint16(cdi[0:], uint16(d.border<<5)|0x17) // 0b00110111
if err := d.sendCommand(uc8159CDI, cdi); err != nil {
return err
}
// Gate/Source non-overlap period
// 0b11110000 = Source to Gate (0b0010 = 12nS, default)
// 0b00001111 = Gate to Source
if err := d.sendCommand(uc8159TCON, []byte{0x22}); err != nil { // 0b00100010
return err
}
// Disable external flash
if err := d.sendCommand(uc8159DAM, []byte{0x00}); err != nil {
return err
}
// UC81597C
if err := d.sendCommand(uc8159PWS, []byte{0xAA}); err != nil {
return err
}
// Power off sequence
// 0b00110000 = power off sequence of VDH and VDL, 0b00 = 1 frame (default)
// All other bits ignored?
if err := d.sendCommand(uc8159PFS, []byte{0x00}); err != nil { // PFS_1_FRAME
return err
}
return nil
}
func (d *DevImpression) update(pix []uint8) error {
if err := d.reset(); err != nil {
return err
}
if err := d.sendCommand(uc8159DTM1, pix); err != nil {
return err
}
if err := d.sendCommand(uc8159PON, nil); err != nil {
return err
}
d.wait(200 * time.Millisecond)
if err := d.sendCommand(uc8159DRF, nil); err != nil {
return err
}
d.wait(32 * time.Second)
if err := d.sendCommand(uc8159POF, nil); err != nil {
return err
}
d.wait(200 * time.Millisecond)
return nil
}
// Wait for busy/wait pin.
func (d *DevImpression) wait(dur time.Duration) {
// Set it as input, with a pull down and enable rising edge triggering.
if err := d.busy.In(gpio.PullDown, gpio.RisingEdge); err != nil {
log.Printf("Err: %s", err)
return
}
// Wait for rising edges (Low -> High) or the timeout.
d.busy.WaitForEdge(dur)
}
// ColorModel returns the device native color model.
func (d *DevImpression) ColorModel() color.Model {
if d.Palette == nil {
d.Palette = d.blend()
}
return d.Palette
}
// At returns the color of the pixel at (x, y).
func (d *DevImpression) At(x, y int) color.Color {
if d.Palette == nil {
d.Palette = d.blend()
}
return d.Palette[d.Pix[y*d.width+x]]
}
// Set sets the pixel at (x, y) to the given color. This will not take effect until the next Draw().
func (d *DevImpression) Set(x, y int, c color.Color) {
if d.Palette == nil {
d.Palette = d.blend()
}
d.Pix[y*d.width+x] = uint8(d.Palette.Index(c))
}
// Draw updates the display with the image.
func (d *DevImpression) Draw(r image.Rectangle, src image.Image, sp image.Point) error {
if r != d.Bounds() {
return fmt.Errorf("partial updates are not supported")
}
if src.Bounds() != d.Bounds() {
return fmt.Errorf("image must be the same size as bounds: %v", d.Bounds())
}
// Dither the image using FloydSteinberg dithering algorithm otherwise it won't look as good on the screen.
draw.FloydSteinberg.Draw(d, r, src, image.Point{})
return d.Render()
}
// DrawAll redraws the whole display.
func (d *DevImpression) DrawAll(src image.Image) error {
return d.Draw(d.Bounds(), src, image.Point{})
}

@ -14,142 +14,17 @@ import (
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/display"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/i2c"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/spi"
)
// Color is used to define which model of inky is being used, and also for
// setting the border color.
type Color int
// Valid Color.
const (
Black Color = iota
Red
Yellow
White
)
func (c *Color) String() string {
switch *c {
case Black:
return "black"
case Red:
return "red"
case Yellow:
return "yellow"
case White:
return "white"
default:
return "unknown"
}
}
// Set sets the Color to a value represented by the string s. Set implements the flag.Value interface.
func (c *Color) Set(s string) error {
switch s {
case "black":
*c = Black
case "red":
*c = Red
case "yellow":
*c = Yellow
case "white":
*c = White
default:
return fmt.Errorf("unknown color %q: expected either black, red, yellow or white", s)
}
return nil
}
// Model lists the supported e-ink display models.
type Model int
var _ display.Drawer = &Dev{}
var _ conn.Resource = &Dev{}
// Supported Model.
const (
PHAT Model = iota
WHAT
PHAT2
cs0Pin = 8
)
func (m *Model) String() string {
switch *m {
case PHAT:
return "PHAT"
case PHAT2:
return "PHAT2"
case WHAT:
return "WHAT"
default:
return "Unknown"
}
}
// Set sets the Model to a value represented by the string s. Set implements the flag.Value interface.
func (m *Model) Set(s string) error {
switch s {
case "PHAT":
*m = PHAT
case "PHAT2":
*m = PHAT2
case "WHAT":
*m = WHAT
default:
return fmt.Errorf("unknown model %q: expected either PHAT or WHAT", s)
}
return nil
}
// Opts is the options to specify which device is being controlled and its
// default settings.
type Opts struct {
// Model being used.
Model Model
// Model color.
ModelColor Color
// Initial border color. Will be set on the first Draw().
BorderColor Color
}
// DetectOpts tries to read the device opts from EEPROM.
func DetectOpts(bus i2c.Bus) (*Opts, error) {
// Read data from EEPROM
data, err := readEep(bus)
if err != nil {
return nil, fmt.Errorf("failed to detect Inky board: %v", err)
}
options := new(Opts)
switch data[6] {
case 1, 4, 5:
options.Model = PHAT
case 10, 11, 12:
options.Model = PHAT2
case 2, 3, 6, 7, 8:
options.Model = WHAT
default:
return nil, fmt.Errorf("failed to get ops: display type not supported")
}
switch data[4] {
case 1:
options.ModelColor = Black
options.BorderColor = Black
case 2:
options.ModelColor = Red
options.BorderColor = Red
case 3:
options.ModelColor = Yellow
options.BorderColor = Yellow
default:
return nil, fmt.Errorf("failed to get ops: color not supported")
}
return options, nil
}
var borderColor = map[Color]byte{
Black: 0x00,
Red: 0x73,
@ -157,13 +32,48 @@ var borderColor = map[Color]byte{
White: 0x31,
}
// Dev is a handle to an Inky.
type Dev struct {
c conn.Conn
// Maximum number of bytes allowed to be sent as a single I/O on c.
maxTxSize int
// Low when sending a command, high when sending data.
dc gpio.PinOut
// Reset pin, active low.
r gpio.PinOut
// High when device is busy.
busy gpio.PinIn
// Size of this model's display.
bounds image.Rectangle
// Whether this model needs the image flipped vertically.
flipVertically bool
// Whether this model needs the image flipped horizontally.
flipHorizontally bool
// Color of device screen (red, yellow or black).
color Color
// Modifiable color of border.
border Color
// Width of the panel.
width int
// Height of the panel.
height int
// Model being used.
model Model
// Variant of the panel.
variant uint
// PCB Variant of the panel. Represents a version string as a number (12 -> 1.2).
pcbVariant uint
}
// New opens a handle to an Inky pHAT or wHAT.
func New(p spi.Port, dc gpio.PinOut, reset gpio.PinOut, busy gpio.PinIn, o *Opts) (*Dev, error) {
if o.ModelColor != Black && o.ModelColor != Red && o.ModelColor != Yellow {
return nil, fmt.Errorf("unsupported color: %v", o.ModelColor)
}
c, err := p.Connect(488*physic.KiloHertz, spi.Mode0, 8)
c, err := p.Connect(488*physic.KiloHertz, spi.Mode0, cs0Pin)
if err != nil {
return nil, fmt.Errorf("failed to connect to inky over spi: %v", err)
}
@ -186,42 +96,31 @@ func New(p spi.Port, dc gpio.PinOut, reset gpio.PinOut, busy gpio.PinIn, o *Opts
busy: busy,
color: o.ModelColor,
border: o.BorderColor,
model: o.Model,
variant: o.DisplayVariant,
pcbVariant: o.PCBVariant,
}
switch o.Model {
case PHAT:
d.bounds = image.Rect(0, 0, 104, 212)
d.width = 104
d.height = 212
d.flipVertically = true
case PHAT2:
d.bounds = image.Rect(0, 0, 122, 250)
d.width = 122
d.height = 250
d.flipVertically = true
case WHAT:
d.bounds = image.Rect(0, 0, 400, 300)
d.width = 400
d.height = 300
}
return d, nil
// Prefer the passed in values via Opts.
if o.Width == 0 && o.Height == 0 {
d.width = o.Width
d.height = o.Height
}
// Dev is a handle to an Inky.
type Dev struct {
c conn.Conn
// Maximum number of bytes allowed to be sent as a single I/O on c.
maxTxSize int
// Low when sending a command, high when sending data.
dc gpio.PinOut
// Reset pin, active low.
r gpio.PinOut
// High when device is busy.
busy gpio.PinIn
// Size of this model's display.
bounds image.Rectangle
// Whether this model needs the image flipped vertically.
flipVertically bool
// Color of device screen (red, yellow or black).
color Color
// Modifiable color of border.
border Color
d.bounds = image.Rect(0, 0, d.width, d.height)
return d, nil
}
// SetBorder changes the border color. This will not take effect until the next Draw().
@ -241,10 +140,32 @@ func (d *Dev) SetModelColor(c Color) error {
// String implements conn.Resource.
func (d *Dev) String() string {
index := int(d.variant)
if index < len(displayVariantMap) {
return displayVariantMap[index]
}
return "Inky pHAT"
}
// Halt implements conn.Resource
func (d *Dev) Height() int {
return d.height
}
func (d *Dev) Width() int {
return d.width
}
// SetFlipVertically flips the image horizontally.
func (d *Dev) SetFlipVertically(f bool) {
d.flipVertically = f
}
// SetFlipHorizontally flips the image horizontally.
func (d *Dev) SetFlipHorizontally(f bool) {
d.flipHorizontally = f
}
// Halt implements conn.Resource.
func (d *Dev) Halt() error {
return nil
}
@ -461,19 +382,3 @@ func pack(bits []bool) ([]byte, error) {
}
return ret, nil
}
func readEep(bus i2c.Bus) ([]byte, error) {
// Inky uses SMBus, specify read registry with data
write := []byte{0x00, 0x00}
data := make([]byte, 29)
if err := bus.Tx(0x50, write, data); err != nil {
return nil, err
}
return data, nil
}
var _ display.Drawer = &Dev{}
var _ conn.Resource = &Dev{}

@ -0,0 +1,120 @@
// Copyright 2023 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 (
"encoding/binary"
"fmt"
"periph.io/x/conn/v3/i2c"
)
var (
displayVariantMap = [...]string{
"",
"Red pHAT (High-Temp)",
"Yellow wHAT",
"Black wHAT",
"Black pHAT",
"Yellow pHAT",
"Red wHAT",
"Red wHAT (High-Temp)",
"Red wHAT",
"",
"Black pHAT (SSD1608)",
"Red pHAT (SSD1608)",
"Yellow pHAT (SSD1608)",
"",
"7-Colour (UC8159)",
"7-Colour 640x400 (UC8159)",
"7-Colour 640x400 (UC8159)",
"Black wHAT (SSD1683)",
"Red wHAT (SSD1683)",
"Yellow wHAT (SSD1683)",
}
)
// Opts is the options to specify which device is being controlled and its
// default settings.
type Opts struct {
// Boards's width and height.
Width int
Height int
// Model being used.
Model Model
// Model color.
ModelColor Color
// Initial border color. Will be set on the first Draw().
BorderColor Color
// Board information.
PCBVariant uint
DisplayVariant uint
}
// DetectOpts tries to read the device opts from EEPROM.
func DetectOpts(bus i2c.Bus) (*Opts, error) {
// Read data from EEPROM
data, err := readEep(bus)
if err != nil {
return nil, fmt.Errorf("failed to detect Inky board: %v", err)
}
options := new(Opts)
options.Width = int(binary.LittleEndian.Uint16(data[0:]))
options.Height = int(binary.LittleEndian.Uint16(data[2:]))
switch data[4] {
case 1:
options.ModelColor = Black
options.BorderColor = Black
case 2:
options.ModelColor = Red
options.BorderColor = Red
case 3:
options.ModelColor = Yellow
options.BorderColor = Yellow
case 4:
options.ModelColor = Multi
options.BorderColor = Color(WhiteImpression)
default:
return nil, fmt.Errorf("failed to get ops: color %v not supported", data[4])
}
// PCB Variant is stored as a number in the eeprom but is actually corresponds a version string (12 -> 1.2)
options.PCBVariant = uint(data[5])
switch data[6] {
case 1, 4, 5:
options.Model = PHAT
case 10, 11, 12:
options.Model = PHAT2
case 2, 3, 6, 7, 8:
options.Model = WHAT
case 14:
options.Model = IMPRESSION57
case 15, 16:
options.Model = IMPRESSION4
default:
return nil, fmt.Errorf("failed to get ops: display type %v not supported", data[6])
}
options.DisplayVariant = uint(data[6])
return options, nil
}
func readEep(bus i2c.Bus) ([]byte, error) {
// Inky uses SMBus, specify read registry with data
write := []byte{0x00, 0x00}
data := make([]byte, 29)
if err := bus.Tx(0x50, write, data); err != nil {
return nil, err
}
return data, nil
}

@ -0,0 +1,111 @@
// Copyright 2023 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
//go:generate stringer -type=Model,Color,ImpressionColor -output types_string.go
import (
"fmt"
)
// Model lists the supported e-ink display models.
type Model int
// Supported Model.
const (
PHAT Model = iota
WHAT
PHAT2
IMPRESSION4
IMPRESSION57
)
// Set sets the Model to a value represented by the string s. Set implements the flag.Value interface.
func (m *Model) Set(s string) error {
switch s {
case "PHAT":
*m = PHAT
case "PHAT2":
*m = PHAT2
case "WHAT":
*m = WHAT
case "IMPRESSION4":
*m = IMPRESSION4
case "IMPRESSION57":
*m = IMPRESSION57
default:
return fmt.Errorf("unknown model %q: expected PHAT, PHAT2, WHAT, IMPRESSION4 or IMPRESSION57", s)
}
return nil
}
// Color is used to define which model of inky is being used, and also for
// setting the border color.
type Color int
// Valid Color.
const (
Black Color = iota
Red
Yellow
White
Multi
)
// Set sets the Color to a value represented by the string s. Set implements the flag.Value interface.
func (c *Color) Set(s string) error {
switch s {
case "black":
*c = Black
case "red":
*c = Red
case "yellow":
*c = Yellow
case "white":
*c = White
default:
return fmt.Errorf("unknown color %q: expected either black, red, yellow or white", s)
}
return nil
}
// ImpressionColor is used to define colors used by Inky Impression models.
type ImpressionColor uint8
const (
BlackImpression ImpressionColor = iota
WhiteImpression
GreenImpression
BlueImpression
RedImpression
YellowImpression
OrangeImpression
CleanImpression
)
// Set sets the ImpressionColor to a value represented by the string s. Set implements the flag.Value interface.
func (c *ImpressionColor) Set(s string) error {
switch s {
case "black":
*c = BlackImpression
case "white":
*c = WhiteImpression
case "green":
*c = GreenImpression
case "blue":
*c = BlueImpression
case "red":
*c = RedImpression
case "yellow":
*c = YellowImpression
case "orange":
*c = OrangeImpression
case "clean":
*c = CleanImpression
default:
return fmt.Errorf("unknown color %q: expected either black, white. green, blue, red, yellow, orange or clean", s)
}
return nil
}

@ -0,0 +1,72 @@
// Code generated by "stringer -type=Model,Color,ImpressionColor -output types_string.go"; DO NOT EDIT.
package inky
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[PHAT-0]
_ = x[WHAT-1]
_ = x[PHAT2-2]
_ = x[IMPRESSION4-3]
_ = x[IMPRESSION57-4]
}
const _Model_name = "PHATWHATPHAT2IMPRESSION4IMPRESSION57"
var _Model_index = [...]uint8{0, 4, 8, 13, 24, 36}
func (i Model) String() string {
if i < 0 || i >= Model(len(_Model_index)-1) {
return "Model(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Model_name[_Model_index[i]:_Model_index[i+1]]
}
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Black-0]
_ = x[Red-1]
_ = x[Yellow-2]
_ = x[White-3]
_ = x[Multi-4]
}
const _Color_name = "BlackRedYellowWhiteMulti"
var _Color_index = [...]uint8{0, 5, 8, 14, 19, 24}
func (i Color) String() string {
if i < 0 || i >= Color(len(_Color_index)-1) {
return "Color(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Color_name[_Color_index[i]:_Color_index[i+1]]
}
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[BlackImpression-0]
_ = x[WhiteImpression-1]
_ = x[GreenImpression-2]
_ = x[BlueImpression-3]
_ = x[RedImpression-4]
_ = x[YellowImpression-5]
_ = x[OrangeImpression-6]
_ = x[CleanImpression-7]
}
const _ImpressionColor_name = "BlackImpressionWhiteImpressionGreenImpressionBlueImpressionRedImpressionYellowImpressionOrangeImpressionCleanImpression"
var _ImpressionColor_index = [...]uint8{0, 15, 30, 45, 59, 72, 88, 104, 119}
func (i ImpressionColor) String() string {
if i >= ImpressionColor(len(_ImpressionColor_index)-1) {
return "ImpressionColor(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ImpressionColor_name[_ImpressionColor_index[i]:_ImpressionColor_index[i+1]]
}
Loading…
Cancel
Save