commit ae312a04575c5c33a73ef951fca686e91c1ba2c0 Author: Andrey Egorov Date: Tue Aug 20 15:14:10 2024 +0300 Initial. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b9161d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +out/ +go.sum +.git/ +*.swp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ce98226 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +export GOOS=linux +export GOARCH=arm +export GOARM=6 +export CGO_ENABLED=0 + +build: + @go build -o out/out main.go diff --git a/display/display.go b/display/display.go new file mode 100644 index 0000000..a4208c6 --- /dev/null +++ b/display/display.go @@ -0,0 +1,33 @@ +package display + +import ( + "fmt" + "image" + "io" + "log" + + "golang.org/x/image/font" +) + +type Display interface { + GetImg() *image.Gray + GetFont() font.Face + Clear() error + PutText(x, y int, text string) error + + io.Closer +} + +type DisplayModel int + +const ( + SSD1306 DisplayModel = iota +) + +func New(logger *log.Logger, model DisplayModel) (Display, error) { + switch model { + case SSD1306: + return newSsd1306(logger) + } + return nil, fmt.Errorf("invalid display model") +} diff --git a/display/ssd1336.go b/display/ssd1336.go new file mode 100644 index 0000000..fa634b1 --- /dev/null +++ b/display/ssd1336.go @@ -0,0 +1,112 @@ +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 +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..72fbdbe --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module display-test + +go 1.22.5 + +require ( + golang.org/x/image v0.1.0 + periph.io/x/conn/v3 v3.7.1 + periph.io/x/devices/v3 v3.7.1 + periph.io/x/host/v3 v3.8.2 +) diff --git a/main.go b/main.go new file mode 100644 index 0000000..8e22679 --- /dev/null +++ b/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "display-test/display" + "fmt" + "log" +) + +func main() { + log.Println("CGSG forever!!!") + + if err := mainE(); err != nil { + log.Println("MAIN finished with error:", err.Error()) + } + log.Println("END") +} + +func mainE() error { + d, err := display.New(log.New(log.Writer(), "display", log.LstdFlags), display.SSD1306) + if err != nil { + return fmt.Errorf("new display: %w", err) + } + defer d.Close() + + for { + d.Clear() + d.PutText(0, d.GetFont().Metrics().Height.Ceil(), "Satelites: 0") + d.PutText(0, d.GetFont().Metrics().Height.Ceil()*2, "Coords: 0N 0E") + } +}