summaryrefslogtreecommitdiff
path: root/cmd/orca
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/orca')
-rw-r--r--cmd/orca/display.go108
-rw-r--r--cmd/orca/main.go159
2 files changed, 177 insertions, 90 deletions
diff --git a/cmd/orca/display.go b/cmd/orca/display.go
new file mode 100644
index 0000000..5bd4f87
--- /dev/null
+++ b/cmd/orca/display.go
@@ -0,0 +1,108 @@
+package main
+
+import (
+ "embed"
+ "image"
+ "image/color"
+ "image/draw"
+ _ "image/png"
+ "io"
+ "io/fs"
+ "os"
+
+ "golang.org/x/image/font"
+ "golang.org/x/image/font/opentype"
+ "golang.org/x/image/font/sfnt"
+ "golang.org/x/image/math/fixed"
+)
+
+// openSFNT opens the specified font file
+// It keeps the file open indefinitely for lazy loading when the font is used.
+// It never attempts to close the file and is meant only for loading fonts permanently at init time.
+func openSFNT(fs fs.FS, path string) *sfnt.Font {
+ f, err := fs.Open(path)
+ if err != nil {
+ panic(err)
+ }
+ font, err := sfnt.ParseReaderAt(f.(io.ReaderAt))
+ if err != nil {
+ panic(err)
+ }
+ return font
+}
+
+func openImage(fs fs.FS, path string) image.Image {
+ f, err := fs.Open(path)
+ if err != nil {
+ panic(err)
+ }
+ img, _, err := image.Decode(f)
+ if err != nil {
+ panic(err)
+ }
+ return img
+}
+
+//go:embed *.ttf *.png
+var embedFS embed.FS
+var qtFonts = os.DirFS("/usr/lib/fonts")
+
+var (
+ dejaVuSans = openSFNT(qtFonts, "DejaVuSans.ttf")
+ notoSans_Regular = openSFNT(embedFS, "NotoSans-Regular.ttf")
+ notoSans_Bold = openSFNT(embedFS, "NotoSans-Bold.ttf")
+)
+
+var (
+ orcaImg = openImage(embedFS, "orca.png")
+ belowImg = openImage(embedFS, "below.png")
+)
+
+type justify int
+
+const (
+ _ justify = iota
+ justifyLeft
+ justifyCenter
+ justifyRight
+)
+
+func drawText(img draw.Image, sfnt *sfnt.Font, size float64, just justify, c color.Color, dot fixed.Point26_6, text string) {
+ face, err := opentype.NewFace(sfnt, &opentype.FaceOptions{
+ Size: size,
+ DPI: 72,
+ Hinting: font.HintingNone,
+ })
+ if err != nil {
+ panic(err)
+ }
+ defer face.Close()
+ drawer := font.Drawer{
+ Dst: img,
+ Src: &image.Uniform{c},
+ Face: face,
+ Dot: dot,
+ }
+ _, adv := drawer.BoundString(text)
+ var offset fixed.Int26_6
+ switch just {
+ case justifyCenter:
+ offset = adv / 2
+ case justifyRight:
+ offset = adv
+ }
+ drawer.Dot.X -= offset
+ drawer.DrawString(text)
+}
+
+func drawDisplay(img draw.Image, s displayState) {
+ draw.Draw(img, img.Bounds(), &image.Uniform{color.RGBA{34, 31, 32, 255}}, image.Point{}, draw.Src)
+ drawText(img, dejaVuSans, 20, justifyLeft, color.White, fixed.P(50, 25), s.now.Format("Jan 02, 2006"))
+ drawText(img, dejaVuSans, 20, justifyRight, color.White, fixed.P(750, 25), s.now.Format("3:04 pm"))
+ drawText(img, notoSans_Regular, 16, justifyCenter, color.White, fixed.P(400, 25), "V1234567-D98765")
+ draw.Draw(img, orcaImg.Bounds().Add(image.Point{400 - orcaImg.Bounds().Dx()/2, 75}), orcaImg, image.Point{}, draw.Over)
+ if s.cvend.ready {
+ drawText(img, notoSans_Bold, 48, justifyCenter, color.White, fixed.P(400, 330), "Tap below")
+ draw.Draw(img, belowImg.Bounds().Add(image.Point{400 - belowImg.Bounds().Dx()/2, 380}), belowImg, image.Point{}, draw.Over)
+ }
+}
diff --git a/cmd/orca/main.go b/cmd/orca/main.go
index 79c5eab..f840d22 100644
--- a/cmd/orca/main.go
+++ b/cmd/orca/main.go
@@ -1,125 +1,104 @@
package main
import (
- "embed"
"flag"
"image"
- "image/color"
- "image/draw"
- _ "image/png"
- "io"
- "io/fs"
"log"
"os"
"time"
- "golang.org/x/image/font"
- "golang.org/x/image/font/opentype"
- "golang.org/x/image/font/sfnt"
- "golang.org/x/image/math/fixed"
+ "pm3.dev/cvend"
"pm3.dev/fb"
+ "pm3.dev/ipp"
)
-// openSFNT opens the specified font file
-// It keeps the file open indefinitely for lazy loading when the font is used.
-// It never attempts to close the file and is meant only for loading fonts permanently at init time.
-func openSFNT(fs fs.FS, path string) *sfnt.Font {
- f, err := fs.Open(path)
- if err != nil {
- panic(err)
- }
- font, err := sfnt.ParseReaderAt(f.(io.ReaderAt))
- if err != nil {
- panic(err)
- }
- return font
+type cvendState struct {
+ ready bool
}
-func openImage(fs fs.FS, path string) image.Image {
- f, err := fs.Open(path)
- if err != nil {
- panic(err)
- }
- img, _, err := image.Decode(f)
- if err != nil {
- panic(err)
- }
- return img
+type displayState struct {
+ now time.Time
+ cvend cvendState
}
-//go:embed *.ttf *.png
-var embedFS embed.FS
-var qtFonts = os.DirFS("/usr/lib/fonts")
+func main() {
+ flag.Parse()
+ log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime | log.Lmicroseconds)
+ log.Println(os.Args[0], "start")
-var (
- dejaVuSans = openSFNT(qtFonts, "DejaVuSans.ttf")
- notoSans_Regular = openSFNT(embedFS, "NotoSans-Regular.ttf")
- notoSans_Bold = openSFNT(embedFS, "NotoSans-Bold.ttf")
-)
+ displayStateCh := make(chan displayState)
+ go displayTask(displayStateCh)
-var (
- orcaImg = openImage(embedFS, "orca.png")
- belowImg = openImage(embedFS, "below.png")
-)
+ displayState := displayState{
+ now: time.Now(),
+ }
+ displayStateCh <- displayState
-type justify int
+ cvendStateCh := make(chan cvendState)
+ go cvendTask(cvendStateCh)
-const (
- _ justify = iota
- justifyLeft
- justifyCenter
- justifyRight
-)
+ tickerCh := wallTicker(time.Minute).C
-func drawText(img draw.Image, sfnt *sfnt.Font, size float64, just justify, c color.Color, dot fixed.Point26_6, text string) {
- face, err := opentype.NewFace(sfnt, &opentype.FaceOptions{
- Size: size,
- DPI: 72,
- Hinting: font.HintingNone,
- })
- if err != nil {
- panic(err)
- }
- defer face.Close()
- drawer := font.Drawer{
- Dst: img,
- Src: &image.Uniform{c},
- Face: face,
- Dot: dot,
- }
- _, adv := drawer.BoundString(text)
- var offset fixed.Int26_6
- switch just {
- case justifyCenter:
- offset = adv / 2
- case justifyRight:
- offset = adv
+ for {
+ select {
+ case now := <-tickerCh:
+ displayState.now = now
+ case cvendState := <-cvendStateCh:
+ displayState.cvend = cvendState
+ }
+ displayStateCh <- displayState
}
- drawer.Dot.X -= offset
- drawer.DrawString(text)
}
-func main() {
- flag.Parse()
- log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime | log.Lmicroseconds)
- log.Println(os.Args[0], "start")
+// wallTicker returns a ticker that fires whenever time.Now().Truncate(d) changes
+func wallTicker(d time.Duration) *time.Ticker {
+ first := time.Until(time.Now().Add(d).Truncate(d))
+ ticker := time.NewTicker(first)
+ go func() {
+ time.Sleep(first)
+ ticker.Reset(d)
+ }()
+ return ticker
+}
+func displayTask(stateCh <-chan displayState) {
fb, err := fb.Open()
if err != nil {
log.Fatalf("open fb: %v", err)
}
defer fb.Close()
- for {
- now := time.Now()
+ for state := range stateCh {
+ start := time.Now()
img := image.NewRGBA(fb.Bounds())
- draw.Draw(img, img.Bounds(), &image.Uniform{color.RGBA{34, 31, 32, 255}}, image.Point{}, draw.Src)
- drawText(img, dejaVuSans, 20, justifyLeft, color.White, fixed.P(50, 25), now.Format("Jan 02, 2006"))
- drawText(img, dejaVuSans, 20, justifyRight, color.White, fixed.P(750, 25), now.Format("3:04 pm"))
- drawText(img, notoSans_Regular, 16, justifyCenter, color.White, fixed.P(400, 25), "V1234567-D98765")
- draw.Draw(img, orcaImg.Bounds().Add(image.Point{400 - orcaImg.Bounds().Dx()/2, 75}), orcaImg, image.Point{}, draw.Over)
- drawText(img, notoSans_Bold, 48, justifyCenter, color.White, fixed.P(400, 330), "Tap below")
- draw.Draw(img, belowImg.Bounds().Add(image.Point{400 - belowImg.Bounds().Dx()/2, 380}), belowImg, image.Point{}, draw.Over)
+ drawDisplay(img, state)
fb.WriteRGBA(img)
+ dur := time.Now().Sub(start)
+ log.Printf("display update %s %+v", dur, state)
+ }
+
+}
+
+func cvendTask(out chan<- cvendState) {
+ var state cvendState
+ var cv ipp.Session
+ var err error
+ cv, err = cvend.OpenIPP(func(msgType byte, msgData []byte) {
+ switch msgType {
+ case 0x05: // StatusReply
+ if !state.ready {
+ state.ready = true
+ out <- state
+ }
+ default:
+ cvend.LogIPP(msgType, msgData)
+ }
+ })
+ if err != nil {
+ panic(err)
+ }
+ for {
+ cv.SendIPP(0x04, nil) // Status
+ time.Sleep(1 * time.Second)
}
}