package main import ( "flag" "image" "log" "os" "time" "pm3.dev/cvend" "pm3.dev/fb" "pm3.dev/ipp" ) type cvendState struct { ready bool } type displayState struct { now time.Time cvend cvendState } func main() { flag.Parse() log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime | log.Lmicroseconds) log.Println(os.Args[0], "start") displayStateCh := make(chan displayState) go displayTask(displayStateCh) displayState := displayState{ now: time.Now(), } displayStateCh <- displayState cvendStateCh := make(chan cvendState) go cvendTask(cvendStateCh) tickerCh := wallTicker(time.Minute).C for { select { case now := <-tickerCh: displayState.now = now case cvendState := <-cvendStateCh: displayState.cvend = cvendState } displayStateCh <- displayState } } // 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 state := range stateCh { start := time.Now() img := image.NewRGBA(fb.Bounds()) 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) } }