diff --git a/cmd/server/main.go b/cmd/server/main.go index 94d7260..6758774 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -26,7 +26,9 @@ func NewCoordinator(ch chan error) coordinator { } func LoadConfig(fname string) Config { - config.Load(fname) + if err := config.Load(fname); err != nil { + panic(err) + } return config.LoadConfig() } diff --git a/internal/configs/reactor.yaml b/internal/configs/reactor.yaml new file mode 100644 index 0000000..4e92dbf --- /dev/null +++ b/internal/configs/reactor.yaml @@ -0,0 +1,5 @@ +reactor: + sensors: + address: 112 # decimal + name: "DO Sensor" + diff --git a/internal/pkg/config/reactor.go b/internal/pkg/config/reactor.go new file mode 100644 index 0000000..f227709 --- /dev/null +++ b/internal/pkg/config/reactor.go @@ -0,0 +1,26 @@ +package config + +// pacakge serves to store/load config files for reactor + +import ( + "sync" +) + +type ReactorConf struct { + Reactor ReactorConfig `mapstructure:"reactor"` + Devices map[int]DeviceConfig `mapstructure:"devices"` + sync.RWMutex +} + +type DeviceConfig struct { + Address uint32 `mapstructure:"address"` + Interval uint32 `mapstructure:"interval"` + Name string `mapstructure:"name"` +} + +// loaded in other file +func (c *ReactorConf) GetURL() (string, error) { + c.RLock() + defer c.RUnlock() + return c.Reactor.URL, nil +} diff --git a/internal/pkg/config/server.go b/internal/pkg/config/server.go index 27da7e6..a1b5001 100644 --- a/internal/pkg/config/server.go +++ b/internal/pkg/config/server.go @@ -17,7 +17,7 @@ import ( //"bytes" ) -type Config struct { +type ServerConf struct { Server ServerConfig `mapstructure:"server"` Reactors map[string]ReactorConfig `mapstructure:"reactors"` sync.RWMutex @@ -34,21 +34,36 @@ type ServerConfig struct { type ReactorConfig struct { Token string `mapstructure:"db-token"` Bucket string `mapstructure:"db-bucket"` - Name string - Id uint32 + URL string `mapstructure:"db-url",omitempty` // only needed by reactor + Name string `mapstructure:"name",omitempty` // not always set + Id uint32 `mapstructure:"id"` } -var C *Config +type Config interface { + Store() error +} + +var C Config -func Load(fname string) { +func Load(fname string) error { // read stored configs - C = &Config{} + //C = &ServerConf{} + switch fname { + case "server": + C = &ServerConf{} + case "reactor": + C = &ReactorConf{} + default: + return fmt.Errorf("%s not recognized", fname) + } + logging.Debug(logging.DStart, "Loading config for %s", fname) viper.SetConfigName(fname) viper.SetConfigType("yaml") - viper.AddConfigPath("/etc/frms/config") // - // defaults - viper.SetDefault("server.db-org", "ForeLight") - viper.SetDefault("server.db-url", "http://192.168.100.2:8086") + viper.AddConfigPath("/etc/frms/config") + // defaults which we don't want to set nessecarily + //viper.SetDefault("server.db-org", "ForeLight") + //viper.SetDefault("server.db-url", "http://192.168.100.2:8086") + //viper.SetDefault("reactor.db-url", "http://192.168.100.2:8086") // unmarshalling err := viper.ReadInConfig() // the fact i never did this is infuriating if err != nil { @@ -65,23 +80,23 @@ func Load(fname string) { // unmarshalled at this point } -func LoadConfig() *Config { +func LoadConfig() Config { return C } -func (c *Config) GetURL() (string, error) { +func (c *ServerConf) GetURL() (string, error) { c.RLock() defer c.RUnlock() return C.Server.URL, nil } -func (c *Config) GetOrg() (string, error) { +func (c *ServerConf) GetOrg() (string, error) { c.RLock() defer c.RUnlock() return c.Server.Orginization, nil } -func (c *Config) GetPort(port string) (int, error) { +func (c *ServerConf) GetPort(port string) (int, error) { c.RLock() defer c.RUnlock() portString, ok := c.Server.Ports[port] @@ -94,46 +109,46 @@ func (c *Config) GetPort(port string) (int, error) { return portString, nil } -func (c *Config) GetServerToken() (string, error) { +func (c *ServerConf) GetServerToken() (string, error) { c.RLock() defer c.RUnlock() return c.Server.Token, nil } -func (c *Config) GetReactorClient(id uint32) (string, string, error) { +func (c *ServerConf) GetReactorClient(id uint32) (string, string, error) { c.RLock() defer c.RUnlock() idString := strconv.FormatUint(uint64(id), 10) if r, ok := c.Reactors[idString]; ok { return r.Bucket, r.Token, nil } - return "", "", fmt.Errorf("Reactor %v config doesnt exist!", id) + return "", "", fmt.Errorf("reactor %v config doesnt exist", id) } // setters -func (c *Config) UpdateURL(url string) error { +func (c *ServerConf) UpdateURL(url string) error { c.Lock() defer c.Unlock() if url == "" { - return errors.New("String cannot be empty!") + return errors.New("string cannot be empty") } c.Server.URL = url viper.Set("server.db-url", url) return viper.WriteConfigAs(viper.ConfigFileUsed()) } -func (c *Config) UpdateOrg(org string) error { +func (c *ServerConf) UpdateOrg(org string) error { c.Lock() defer c.Unlock() if org == "" { - return errors.New("String cannot be empty!") + return errors.New("string cannot be empty") } c.Server.Orginization = org viper.Set("server.db-org", org) return viper.WriteConfigAs(viper.ConfigFileUsed()) } -func (c *Config) UpdatePort(pName string, port int) error { +func (c *ServerConf) UpdatePort(pName string, port int) error { c.Lock() defer c.Unlock() if port < 1024 || port > 65535 { @@ -149,7 +164,7 @@ func (c *Config) UpdatePort(pName string, port int) error { return viper.WriteConfigAs(viper.ConfigFileUsed()) } -func (c *Config) UpdateServerToken(token string) error { +func (c *ServerConf) UpdateServerToken(token string) error { c.Lock() defer c.Unlock() if token == "" { @@ -160,7 +175,7 @@ func (c *Config) UpdateServerToken(token string) error { return viper.WriteConfigAs(viper.ConfigFileUsed()) } -func (c *Config) UpdateReactorClient(id uint32, bucket, token string) error { +func (c *ServerConf) UpdateReactorClient(id uint32, bucket, token string) error { c.Lock() c.Unlock() sid := strconv.FormatUint(uint64(id), 10) @@ -181,6 +196,6 @@ func (c *Config) UpdateReactorClient(id uint32, bucket, token string) error { return viper.WriteConfigAs(viper.ConfigFileUsed()) } -func (c *Config) Store() error { +func (c *ServerConf) Store() error { return viper.WriteConfigAs(viper.ConfigFileUsed()) } diff --git a/internal/pkg/sensor/manager.go b/internal/pkg/sensor/manager.go index 5350a8e..12e5270 100644 --- a/internal/pkg/sensor/manager.go +++ b/internal/pkg/sensor/manager.go @@ -1,114 +1,114 @@ package sensor import ( - _"fmt" - "time" - "sync" - "strings" - _ "FRMS/internal/pkg/I2C" - "log" + _ "FRMS/internal/pkg/I2C" + _ "fmt" + "log" + "strings" + "sync" + "time" ) type Manager struct { - *Dev - I2CDevice - *Active - Hb time.Duration + *Dev + I2CDevice + *Active + Hb time.Duration } type Active struct { - sync.Mutex - bool - int + sync.Mutex + bool + int } type Dev struct { - // last known values - Addr int - Type string - Status string // could be more efficient but to hell with it - Data string + // last known values + Addr int + Type string + Status string // could be more efficient but to hell with it + Data string } type I2CDevice interface { - // basic device info - GetAddr() int - GetStatus() string - GetType() string - GetData() string + // basic device info + GetAddr() int + GetStatus() string + GetType() string + GetData() string } -func NewDeviceManager(i2c I2CDevice) *Manager { - m := &Manager{Hb:time.Duration(1*time.Second)} - m.I2CDevice = i2c - m.Active = &Active{} - m.Dev = &Dev{Addr:i2c.GetAddr(),Type:i2c.GetType(),Status:i2c.GetStatus(),Data:i2c.GetData()} - return m +func NewDeviceManager(i2c I2CDevice) *Manager { + m := &Manager{Hb: time.Duration(1 * time.Second)} + m.I2CDevice = i2c + m.Active = &Active{} + m.Dev = &Dev{Addr: i2c.GetAddr(), Type: i2c.GetType(), Status: i2c.GetStatus(), Data: i2c.GetData()} + return m } func (m *Manager) Start() { - // goal is to start a long running monitoring routine - if !m.Activate() { - log.Fatal("Manager already running!") - } // atomically activated if this runs - // go m.Monitor() + // goal is to start a long running monitoring routine + if !m.Activate() { + log.Fatal("Manager already running!") + } // atomically activated if this runs + // go m.Monitor() } func (m *Manager) Exit() { - if !m.Deactivate() { - log.Fatal("Manager already exited!") - } + if !m.Deactivate() { + log.Fatal("Manager already exited!") + } } func (m *Manager) GetType() string { - return m.Type + return m.Type } func (m *Manager) GetStatus() string { - m.Status = m.I2CDevice.GetStatus() - if m.IsActive() && strings.Contains(m.Status,"KILLED") { - m.Exit() - } - return m.Status + m.Status = m.I2CDevice.GetStatus() + if m.IsActive() && strings.Contains(m.Status, "KILLED") { + m.Exit() + } + return m.Status } func (m *Manager) GetData() string { - m.Data = m.I2CDevice.GetData() - return m.Data + m.Data = m.I2CDevice.GetData() + return m.Data } func (m *Manager) GetAddr() int { - return m.Addr + return m.Addr } // atomic activation and deactivation func (a *Active) Activate() bool { - // returns true if success, false otherwise - a.Lock() - defer a.Unlock() - if a.bool { // already active - return false - } else { - a.bool = true - a.int = 0 - return a.bool - } + // returns true if success, false otherwise + a.Lock() + defer a.Unlock() + if a.bool { // already active + return false + } else { + a.bool = true + a.int = 0 + return a.bool + } } func (a *Active) Deactivate() bool { - // returns true if success false otherise - a.Lock() - defer a.Unlock() - if a.bool { - a.bool = false - return true - } else { // already deactivated - return a.bool // false - } + // returns true if success false otherise + a.Lock() + defer a.Unlock() + if a.bool { + a.bool = false + return true + } else { // already deactivated + return a.bool // false + } } func (a *Active) IsActive() bool { - a.Lock() - defer a.Unlock() - return a.bool + a.Lock() + defer a.Unlock() + return a.bool } diff --git a/internal/pkg/sensor/mappings.go b/internal/pkg/sensor/mappings.go new file mode 100644 index 0000000..8ffc353 --- /dev/null +++ b/internal/pkg/sensor/mappings.go @@ -0,0 +1,36 @@ +package sensor + +import ( + "fmt" + "sync" +) + +/* + this file serves as a map that the sensor library can use to determine which manager to call +*/ + +type NewManager interface { + // serves as interface to restrict managers can be relocated +} + +type DM struct { + DeviceManagers map[uint]NewManager + sync.Mutex +} + +func NewManagerDirectory() *DM { + m := map[uint]NewManager{ + // map to set functions up + 112: NewDOManager(), + } + return &DM{DeviceManagers: m} +} + +func (d *DM) GetManager(addr uint) (NewManager, error) { + d.Lock() + defer d.Unlock() + if m, ok := d.DeviceManagers[addr]; ok { + return m, nil + } + return &DM{}, fmt.Errorf("No manager found for address %d!", addr) +} diff --git a/notes b/notes index 6a4f4ce..bf54896 100644 --- a/notes +++ b/notes @@ -922,3 +922,33 @@ should also probably wrap these in a seperate struct does it make more sensor to load different configs for each entity or justhave one monolithic config (probably load for each one and then let it update itself) going to have the init script set up the + +Welcome back + +#TODO 8/31 + +Goals: + - Add a config parser to load/store device manager struct + - start figuring out what a generic config package looks like + - figure out how to load different sensor functions dynamically + +Basic reactor workflow overview +1) On boot, scan I2C bus to find active devices +2) For every device shown as active, spawn a sensor manager from the assocaited config +3) on disconnect, shut the dm down and save current settings to config + + + + + + + + + + + + + + + +