diff --git a/epd/epd.go b/epd/epd.go index 3fb2d62..9472624 100644 --- a/epd/epd.go +++ b/epd/epd.go @@ -45,48 +45,9 @@ func New() (*EPD, error) { partFlag: 1, } - if err := epd.resetPin.Out(gpio.Low); err != nil { - return nil, fmt.Errorf("setting reset pin to low: %w", err) - } - if err := epd.dcPin.Out(gpio.Low); err != nil { - return nil, fmt.Errorf("setting dc pin to low: %w", err) - } - if err := epd.csPin.Out(gpio.Low); err != nil { - return nil, fmt.Errorf("setting cs pin to low: %w", err) - } - if err := epd.pwrPin.Out(gpio.High); err != nil { - return nil, fmt.Errorf("setting pwr pin to low: %w", err) - } - - var err error - - if epd.spiReg, err = spireg.Open("0"); err != nil { - return nil, fmt.Errorf("opening SPI: %w", err) - } - - c, err := epd.spiReg.Connect(4*physic.MegaHertz, spi.Mode0, 8) - if err != nil { - return nil, fmt.Errorf("connecting to SPI: %w", err) - } - - epd.spi = c - return epd, nil } -func (e *EPD) turnOff() error { - log.Println("turning off...") - if err := e.spiReg.Close(); err != nil { - return fmt.Errorf("closing SPI: %w", err) - } - - e.resetPin.Out(gpio.Low) - e.dcPin.Out(gpio.Low) - e.pwrPin.Out(gpio.Low) - - return nil -} - func (e *EPD) reset() { e.resetPin.Out(gpio.High) time.Sleep(200 * time.Millisecond) @@ -97,7 +58,6 @@ func (e *EPD) reset() { } func (e *EPD) sendCommand(cmd byte) { - log.Printf("sending command 0x%02X\n", cmd) e.dcPin.Out(gpio.Low) e.csPin.Out(gpio.Low) if _, err := e.spiWrite([]byte{cmd}); err != nil { @@ -116,7 +76,6 @@ func (e *EPD) sendData(data byte) { } func (e *EPD) sendDataSlice(data []byte) { - log.Printf("sending data slice %v\n", len(data)) e.dcPin.Out(gpio.High) toSend := len(data) const maxSize = 4096 @@ -164,8 +123,44 @@ func (e *EPD) readBusy() { time.Sleep(200 * time.Millisecond) } -func (e *EPD) Init() { +func (e *EPD) turnOn() error { + log.Println("turning on") + if err := e.resetPin.Out(gpio.Low); err != nil { + return fmt.Errorf("setting reset pin to low: %w", err) + } + if err := e.dcPin.Out(gpio.Low); err != nil { + return fmt.Errorf("setting dc pin to low: %w", err) + } + if err := e.csPin.Out(gpio.Low); err != nil { + return fmt.Errorf("setting cs pin to low: %w", err) + } + if err := e.pwrPin.Out(gpio.High); err != nil { + return fmt.Errorf("setting pwr pin to low: %w", err) + } + + var err error + + if e.spiReg, err = spireg.Open("0"); err != nil { + return fmt.Errorf("opening SPI: %w", err) + } + + c, err := e.spiReg.Connect(4*physic.MegaHertz, spi.Mode0, 8) + if err != nil { + return fmt.Errorf("connecting to SPI: %w", err) + } + + e.spi = c + + return nil +} + +func (e *EPD) Init() error { log.Println("initializing EPD") + + if err := e.turnOn(); err != nil { + return fmt.Errorf("turning on: %w", err) + } + e.reset() e.sendCommand(0x01) @@ -192,10 +187,17 @@ func (e *EPD) Init() { e.sendCommand(0x60) e.sendData(0x22) + + return nil } -func (e *EPD) InitFast() { +func (e *EPD) InitFast() error { log.Println("initializing Fast EPD") + + if err := e.turnOn(); err != nil { + return fmt.Errorf("turning on: %w", err) + } + e.reset() e.sendCommand(0x00) @@ -216,13 +218,13 @@ func (e *EPD) InitFast() { e.sendCommand(0x50) e.sendDataSlice([]byte{0x11, 0x07}) + + return nil } func (e *EPD) Clear() { log.Println("clearing epd") e.Fill(White) - - //e.Refresh() } func (e *EPD) Refresh() { @@ -233,7 +235,7 @@ func (e *EPD) Refresh() { } func (e *EPD) Sleep() error { - log.Println("sleeping...") + log.Println("sleeping display...") e.sendCommand(0x02) e.readBusy() @@ -248,6 +250,19 @@ func (e *EPD) Sleep() error { return nil } +func (e *EPD) turnOff() error { + log.Println("turning off...") + if err := e.spiReg.Close(); err != nil { + return fmt.Errorf("closing SPI: %w", err) + } + + e.resetPin.Out(gpio.Low) + e.dcPin.Out(gpio.Low) + e.pwrPin.Out(gpio.Low) + + return nil +} + type Color int const ( @@ -270,7 +285,6 @@ func (e *EPD) Fill(c Color) { } func (e *EPD) Send(black image.Image, red image.Image) { - log.Println("drawing...") if black != nil { log.Println("sending black") e.sendCommand(0x10) // write bw data diff --git a/go.mod b/go.mod index 0668192..4d408f7 100644 --- a/go.mod +++ b/go.mod @@ -11,4 +11,9 @@ require ( golang.org/x/image v0.20.0 ) -require github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 +require ( + github.com/carlmjohnson/requests v0.24.2 + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 +) + +require golang.org/x/net v0.27.0 // indirect diff --git a/go.sum b/go.sum index cd20eae..3df8a82 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/carlmjohnson/requests v0.24.2 h1:JDakhAmTIKL/qL/1P7Kkc2INGBJIkIFP6xUeUmPzLso= +github.com/carlmjohnson/requests v0.24.2/go.mod h1:duYA/jDnyZ6f3xbcF5PpZ9N8clgopubP2nK5i6MVMhU= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= @@ -8,6 +10,8 @@ github.com/llgcode/ps v0.0.0-20210114104736-f4b0c5d1e02e h1:ZAvbj5hI/G/EbAYAcj4y github.com/llgcode/ps v0.0.0-20210114104736-f4b0c5d1e02e/go.mod h1:1l8ky+Ew27CMX29uG+a2hNOKpeNYEQjjtiALiBlFQbY= golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw= golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= periph.io/x/conn/v3 v3.7.0 h1:f1EXLn4pkf7AEWwkol2gilCNZ0ElY+bxS4WE2PQXfrA= periph.io/x/conn/v3 v3.7.0/go.mod h1:ypY7UVxgDbP9PJGwFSVelRRagxyXYfttVh7hJZUHEhg= periph.io/x/host/v3 v3.8.2 h1:ayKUDzgUCN0g8+/xM9GTkWaOBhSLVcVHGTfjAOi8OsQ= diff --git a/img.go b/img.go index 66340e2..fbf50f0 100644 --- a/img.go +++ b/img.go @@ -1,36 +1,38 @@ package main import ( + "context" + "fmt" "github.com/Crocmagnon/display-epaper/epd" + "github.com/Crocmagnon/display-epaper/transports" "github.com/llgcode/draw2d" "github.com/llgcode/draw2d/draw2dimg" "image" "image/color" ) -func getBlack() (*image.RGBA, error) { +func getBlack(ctx context.Context, transportsClient *transports.Client) (*image.RGBA, error) { + passages, err := transportsClient.GetTCLPassages(ctx, 290) + if err != nil { + return nil, fmt.Errorf("getting passages: %w", err) + } + img := newWhite() gc := draw2dimg.NewGraphicContext(img) + gc.SetFillRule(draw2d.FillRuleWinding) gc.SetFillColor(color.RGBA{0, 0, 0, 255}) gc.SetStrokeColor(color.RGBA{0, 0, 0, 255}) - gc.SetLineWidth(2) - text(gc, "Hello, world", 18, 110, 50) - - return img, nil -} - -func getRed() (*image.RGBA, error) { - img := newBlack() - gc := draw2dimg.NewGraphicContext(img) - gc.SetFillColor(color.RGBA{0, 0, 0, 255}) - gc.SetStrokeColor(color.RGBA{255, 255, 255, 255}) - gc.SetLineWidth(2) - - rect(gc, 10, 10, 50, 50) - rect(gc, 60, 10, 100, 50) + for i, passage := range passages.Passages { + x := float64(10 + i*100) + text(gc, passage.Ligne, 15, x, 20) + for j, delay := range passage.Delays { + y := float64(20 + (j+1)*30) + text(gc, delay, 15, x, y) + } + } return img, nil } @@ -38,6 +40,8 @@ func getRed() (*image.RGBA, error) { func text(gc *draw2dimg.GraphicContext, s string, size, x, y float64) { gc.SetFontData(draw2d.FontData{Name: fontName}) gc.SetFontSize(size) + gc.FillStringAt(s, x, y) + gc.SetLineWidth(2) gc.StrokeStringAt(s, x, y) } diff --git a/main.go b/main.go index 881fe67..54fcc34 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,14 @@ package main import ( + "context" + "github.com/Crocmagnon/display-epaper/transports" "github.com/golang/freetype/truetype" "github.com/llgcode/draw2d" _ "golang.org/x/image/bmp" "golang.org/x/image/font/gofont/goregular" "log" + "os" ) const fontName = "default" @@ -13,6 +16,8 @@ const fontName = "default" func main() { log.Println("starting...") + ctx := context.Background() + font, err := truetype.Parse(goregular.TTF) if err != nil { log.Fatalf("loading font: %v\n", err) @@ -21,7 +26,11 @@ func main() { fontCache.Store(draw2d.FontData{Name: fontName}, font) draw2d.SetFontCache(fontCache) - if err := run(); err != nil { + transportsClient := transports.New(nil, transports.Config{ + Authorization: os.Getenv("TRANSPORTS_AUTHORIZATION"), + }) + + if err := run(ctx, transportsClient); err != nil { log.Fatal("error: ", err) } diff --git a/run_darwin_arm64.go b/run_darwin_arm64.go index 111d89f..dad8a65 100644 --- a/run_darwin_arm64.go +++ b/run_darwin_arm64.go @@ -1,23 +1,19 @@ package main import ( + "context" + "github.com/Crocmagnon/display-epaper/transports" "github.com/llgcode/draw2d/draw2dimg" "log" ) -func run() error { - img, err := getBlack() +func run(ctx context.Context, transportsClient *transports.Client) error { + img, err := getBlack(ctx, transportsClient) if err != nil { log.Fatal(err) } draw2dimg.SaveToPngFile("out/black.png", img) - img, err = getRed() - if err != nil { - log.Fatal(err) - } - draw2dimg.SaveToPngFile("out/red.png", img) - log.Println("done") return nil diff --git a/run_linux_arm64.go b/run_linux_arm64.go index 1b56a1a..61c4976 100644 --- a/run_linux_arm64.go +++ b/run_linux_arm64.go @@ -1,13 +1,16 @@ package main import ( + "context" "fmt" "github.com/Crocmagnon/display-epaper/epd" + "github.com/Crocmagnon/display-epaper/transports" "log" "periph.io/x/host/v3" + "time" ) -func run() error { +func run(ctx context.Context, transportsClient *transports.Client) error { _, err := host.Init() if err != nil { return fmt.Errorf("initializing host: %w", err) @@ -18,30 +21,45 @@ func run() error { return fmt.Errorf("initializing epd: %w", err) } - display.Init() - //display.InitFast() - display.Clear() - display.Refresh() + for { + select { + case <-ctx.Done(): + log.Println("stopping because of context") + return ctx.Err() + default: + } - black, err := getBlack() + err = loop(ctx, display, transportsClient) + if err != nil { + log.Printf("error looping: %v\n", err) + } + + log.Println("time.Sleep(30s)") + time.Sleep(30 * time.Second) + } +} + +func loop(ctx context.Context, display *epd.EPD, transportsClient *transports.Client) error { + defer func() { + if err := display.Sleep(); err != nil { + log.Printf("error sleeping: %v\n", err) + } + }() + + err := display.Init() + if err != nil { + return fmt.Errorf("initializing display: %w", err) + } + + display.Clear() + + black, err := getBlack(ctx, transportsClient) if err != nil { return fmt.Errorf("getting black: %w", err) } - red, err := getRed() - if err != nil { - return fmt.Errorf("getting red: %w", err) - } - - display.Send(black, red) - - log.Println("sleeping...") - - if err := display.Sleep(); err != nil { - return fmt.Errorf("sleeping: %w", err) - } - - log.Println("done") + display.Send(black, nil) + display.Refresh() return nil } diff --git a/transports/transports.go b/transports/transports.go new file mode 100644 index 0000000..538430c --- /dev/null +++ b/transports/transports.go @@ -0,0 +1,56 @@ +package transports + +import ( + "context" + "fmt" + "github.com/carlmjohnson/requests" + "net/http" +) + +type Stop struct { + ID int `json:"id"` + Name string `json:"name"` +} + +type Passage struct { + Ligne string `json:"ligne"` + Delays []string `json:"delais"` + Destination Stop `json:"destination"` +} + +type Passages struct { + Passages []Passage `json:"passages"` + Stop Stop `json:"stop"` +} + +type Config struct { + Authorization string +} + +type Client struct { + client *http.Client + config Config +} + +func New(httpClient *http.Client, config Config) *Client { + if httpClient == nil { + httpClient = &http.Client{} + } + return &Client{ + client: httpClient, + config: config, + } +} + +func (c *Client) GetTCLPassages(ctx context.Context, stop int) (res *Passages, err error) { + err = requests.URL("https://tcl.augendre.info"). + Pathf("/stop/%v", stop). + Header("Authorization", c.config.Authorization). + Client(c.client). + ToJSON(&res). + Fetch(ctx) + if err != nil { + return nil, fmt.Errorf("calling api: %w", err) + } + return res, nil +}