package printer import "time" type PrintState int const ( StateIdle PrintState = iota StateSDPrinting StateHostPrinting StatePaused StateError ) func (p PrintState) String() string { switch p { case StateIdle: return "IDLE" case StateSDPrinting: return "SD PRINTING" case StateHostPrinting: return "PRINTING" case StatePaused: return "PAUSED" case StateError: return "ERROR" default: return "?" } } type TempPair struct { Current float64 Target float64 } type SDFile struct { Name string // 8.3 short filename, what M23 takes LongName string // long filename if firmware reports one Size int64 } type State struct { Connected bool Online bool Firmware string Port string Baud int PrintState PrintState ErrorMsg string Temps map[string]TempPair SDByte int64 SDTotal int64 SDFilename string SDStart time.Time FeedratePct int FlowPct int FanPct int BabystepZ float64 // SD card listing. SDListing is true while M20 output is being // collected; SDFiles is the most recently completed listing. SDFiles []SDFile SDListing bool } func NewState() State { return State{ Temps: map[string]TempPair{}, FeedratePct: 100, FlowPct: 100, FanPct: 0, PrintState: StateIdle, } } func (s *State) Progress() float64 { if s.SDTotal <= 0 { return 0 } p := float64(s.SDByte) / float64(s.SDTotal) if p > 1 { return 1 } return p } func (s *State) ETA() (time.Duration, bool) { if s.PrintState != StateSDPrinting || s.SDByte <= 0 || s.SDStart.IsZero() { return 0, false } elapsed := nowFn().Sub(s.SDStart) if elapsed < 5*time.Second { return 0, false } rate := float64(s.SDByte) / elapsed.Seconds() if rate <= 0 { return 0, false } remaining := float64(s.SDTotal - s.SDByte) if remaining < 0 { remaining = 0 } return time.Duration(remaining/rate) * time.Second, true } // indirection so tests can fix time var ( nowFn = time.Now zeroTime = time.Time{} )