package state import ( "context" "log" "sync" "alox.tool/api" "alox.tool/eventbus" "alox.tool/uart" ) type ESPStateHandler struct { RWMutex sync.RWMutex Master MasterESP } type ESPVersion struct { Version uint16 Buildhash [7]byte } type BaseESP struct { ClientId byte IsUpdating bool UpdateProgress float32 Version ESPVersion RunningPartition int MAC [6]byte } type MasterESP struct { BaseESP Slaves map[byte]*SlaveESP } type SlaveESP struct { BaseESP SlotAvailable bool SlotUsed bool Bitmask uint32 LageX float32 LageY float32 LastPing uint32 LastSuccessfullPing uint32 } func New() *ESPStateHandler { return &ESPStateHandler{ RWMutex: sync.RWMutex{}, Master: NewMasterESP(), } } func NewMasterESP() MasterESP { return MasterESP{ BaseESP: BaseESP{ ClientId: 0, IsUpdating: false, UpdateProgress: 0, Version: ESPVersion{ Version: 0, Buildhash: [7]byte{}, }, RunningPartition: 0, MAC: [6]byte{}, }, Slaves: map[byte]*SlaveESP{}, } } func NewSlaveESP() *SlaveESP { return &SlaveESP{ BaseESP: BaseESP{ ClientId: 0, IsUpdating: false, UpdateProgress: 0, Version: ESPVersion{ Version: 0, Buildhash: [7]byte{}, }, RunningPartition: 0, MAC: [6]byte{}, }, SlotAvailable: false, SlotUsed: false, Bitmask: 0, LageX: 0, LageY: 0, LastPing: 0, LastSuccessfullPing: 0, } } func (s *ESPStateHandler) Start(ctx context.Context, bus eventbus.EventBus) { go func() { RXC := bus.Subscribe(api.TopicUARTRx) defer bus.Unsubscribe(api.TopicUARTRx, RXC) for { select { case <-ctx.Done(): return case msg := <-RXC: val, ok := msg.(api.Frame) if !ok { log.Printf("val is not type api.Frame its %T", val) continue } log.Printf("[%d] Frame: %X, % X", val.Time, val.ID, val.Data) s.processFrame(val) } } }() } func (s *ESPStateHandler) processFrame(val api.Frame) { s.RWMutex.Lock() defer s.RWMutex.Unlock() switch val.ID { case api.CmdEcho: log.Printf("Echo %v", val) case api.CmdVersion: v, err := uart.ParseFrameVersion(val) if err != nil { log.Printf("Could not Parse Version %v", err) return } log.Printf("Version Info %d %s", v.Version, v.Buildhash) // Update State s.Master.Version.Version = v.Version s.Master.Version.Buildhash = v.Buildhash case api.CmdClientInfo: v, err := uart.ParseFrameClientInfo(val) if err != nil { log.Printf("Could not Parse Client Info %v", err) return } for _, c := range v { log.Printf("Client ID %d", c.ClientID) log.Printf("\tIsAvailable %d", c.IsAvailable) log.Printf("\tLastPing %d", c.LastPing) log.Printf("\tLastSuccessfulPing %d", c.LastSuccessfulPing) log.Printf("\tSlotIsUsed %d", c.SlotIsUsed) log.Printf("\tVersion %d", c.Version) log.Printf("\tMACAddr % X", c.MACAddr) _, ok := s.Master.Slaves[c.ClientID] if !ok { s.Master.Slaves[c.ClientID] = NewSlaveESP() } s.Master.Slaves[c.ClientID].SlotAvailable = c.IsAvailable != 0 s.Master.Slaves[c.ClientID].SlotUsed = c.SlotIsUsed != 0 s.Master.Slaves[c.ClientID].LastPing = c.LastPing s.Master.Slaves[c.ClientID].LastSuccessfullPing = c.LastSuccessfulPing s.Master.Slaves[c.ClientID].Version.Version = c.Version s.Master.Slaves[c.ClientID].MAC = c.MACAddr } case api.CmdClientInput: v, err := uart.ParseFrameClientInput(val) if err != nil { log.Printf("Could not Parse Client Input %v", err) return } for _, c := range v { log.Printf("Client ID %d", c.ClientID) log.Printf("\tX %f", c.X) log.Printf("\tY %f", c.Y) log.Printf("\tBitmask %08b", c.InputMask) _, ok := s.Master.Slaves[c.ClientID] if !ok { s.Master.Slaves[c.ClientID] = NewSlaveESP() } s.Master.Slaves[c.ClientID].LageX = c.X s.Master.Slaves[c.ClientID].LageY = c.Y s.Master.Slaves[c.ClientID].Bitmask = c.InputMask } } }