package display import ( "fmt" "image" "image/color" "log" "sync" "golang.org/x/image/font" "golang.org/x/image/font/inconsolata" "golang.org/x/image/math/fixed" "periph.io/x/conn/v3/i2c" "periph.io/x/conn/v3/i2c/i2creg" "periph.io/x/devices/v3/ssd1306" "periph.io/x/host/v3" ) type displaySsd1306 struct { mutex sync.Mutex logger *log.Logger font font.Face bus i2c.BusCloser dev *ssd1306.Dev img *image.Gray } func newSsd1306(logger *log.Logger) (Display, error) { if _, err := host.Init(); err != nil { return nil, fmt.Errorf("drivers init: %w(may be i2c is disabled)", err) } // Setup device bus, err := i2creg.Open("") if err != nil { return nil, fmt.Errorf("open i2c bus: %w", err) } opts := ssd1306.Opts{ W: 128, H: 32, Rotated: false, Sequential: true, SwapTopBottom: false, } dev, err := ssd1306.NewI2C(bus, &opts) if err != nil { return nil, fmt.Errorf("create i2c: %w", err) } // Create image img := image.NewGray(image.Rect(0, 0, dev.Bounds().Dx(), dev.Bounds().Dy())) return &displaySsd1306{ logger: logger, font: inconsolata.Regular8x16, bus: bus, dev: dev, img: img, }, nil } func (d *displaySsd1306) GetImg() *image.Gray { d.mutex.Lock() defer d.mutex.Unlock() return d.img } func (d *displaySsd1306) GetFont() font.Face { return d.font } func (d *displaySsd1306) Clear() error { d.mutex.Lock() defer d.mutex.Unlock() for i := range d.img.Pix { d.img.Pix[i] = 0 } return nil } func (d *displaySsd1306) PutText(x, y int, text string) error { d.mutex.Lock() defer d.mutex.Unlock() // Create font drawer col := color.Gray{255} point := fixed.Point26_6{X: fixed.I(x), Y: fixed.I(y)} drawer := &font.Drawer{ Dst: d.img, Src: image.NewUniform(col), Face: d.font, Dot: point, } drawer.DrawString(text) d.dev.Draw(d.img.Bounds(), d.img, image.Point{}) return nil } func (d *displaySsd1306) Close() error { d.mutex.Lock() defer d.mutex.Unlock() if err := d.bus.Close(); err != nil { d.logger.Println("Close i2c bus:", err.Error()) } return nil }