package reactor import ( "FRMS/internal/pkg/device" pb "FRMS/internal/pkg/grpc" "FRMS/internal/pkg/i2c" "FRMS/internal/pkg/manager" "fmt" "sync" "time" "github.com/spf13/viper" ) // Created by rlc to manage devices // device manager type DeviceManager interface { Start() error Stop() error IsActive() manager.Status } func NewDeviceManager(bus, addr int, config *viper.Viper) (DeviceManager, error) { return device.New(bus, addr, config) } // device coordinator itself type DeviceCoordinator struct { // base level manager for heartbeat Bus int // i2c bus Manager Config *viper.Viper managersMu sync.RWMutex DeviceManagers map[int]DeviceManager } func NewDeviceCoordinator(config *viper.Viper) (*DeviceCoordinator, error) { dm := make(map[int]DeviceManager) m, err := NewManager(0) return &DeviceCoordinator{ Manager: m, DeviceManagers: dm, Config: config, }, err } func (c *DeviceCoordinator) Start(bus int) error { var err error if err = c.Manager.Start(); err != nil { return err } // i2c bus c.Bus = bus go c.Monitor() return err } func (c *DeviceCoordinator) Monitor() { // monitor I2C for new devices ch := make(chan struct{}) go c.HeartBeat(ch, 10, 0, time.Second) for range ch { // on notification (10s) devs, err := i2c.GetConnected(c.Bus) if err != nil { panic(err) } // update list go c.UpdateManagers(devs) } } func (c *DeviceCoordinator) UpdateManagers(active map[int]bool) { // updates managers c.managersMu.Lock() defer c.managersMu.Unlock() for addr, dm := range c.DeviceManagers { _, ok := active[addr] if ok && dm.IsActive() == manager.Inactive { // active and dm not if err := dm.Start(); err != nil { panic(err) } } else if !ok && dm.IsActive() == manager.Active { // not active and dm is if err := dm.Stop(); err != nil { panic(err) } } // remove from map delete(active, addr) } for addr, _ := range active { // no manager, create one fmt.Printf("New device %d!\n", addr) dm, err := NewDeviceManager(c.Bus, addr, c.Config) if err != nil { panic(err) } if err := dm.Start(); err != nil { panic(err) } c.DeviceManagers[addr] = dm } } func (c *DeviceCoordinator) GetDeviceInfo() ([]*pb.Device, error) { // gets device info for monitoring c.managersMu.RLock() defer c.managersMu.RUnlock() var devices []*pb.Device for addr, dm := range c.DeviceManagers { // looping over devices devices = append(devices, &pb.Device{ Addr: int32(addr), Status: pb.Status(dm.IsActive()), }) } return devices, nil }