Buggy impl

main
KeeganForelight 2 years ago
parent 42332990ed
commit 25fb0d86fc

@ -141,3 +141,6 @@ This just feels *wrong*
- maybe go back to the unified package? Not quite clear what the purpose of seperate is beyond convience
- although... the idea of the device manager as a reusable peice makes enough sense to potentially keep it as a seperate package
- I'll stick with the seperate for now and keep it unless it becomes unworkable
### I2C Changes
The i2c bus is locked at the device level, so I am going to rewrite the bs to just use a function with no struct and remove the whole passing of structs garbage

@ -1,34 +0,0 @@
package controller
import (
"FRMS/internal/pkg/manager"
"sync"
)
// base controller manager
type Manager interface {
Start() error
Exit() error
IsActive() int
}
func NewManager(max int) Manager {
return manager.New(max)
}
type ControllerManager struct {
Manager
sync.Mutex
Enabled bool // turn controller on or off
}
func NewControllerManager() *ControllerManager {
m := NewManager(0) // no connections
return &ControllerManager{Manager: m}
}
func (c *ControllerManager) Start(addr int) error {
return c.Manager.Start()
}

@ -0,0 +1,85 @@
package device
import (
"FRMS/internal/pkg/i2c"
"encoding/hex"
"errors"
"strconv"
"strings"
"time"
)
// atlas helpers to fulfill sensor manager functions
type Atlas struct {
// delays passed by caller
CalDelay int
ReadDelay int
}
func (a *Atlas) Calibrate(bus, addr int, cal string) error {
// calibrate sensor
if a.CalDelay == 0 {
return errors.New("Cal delay unset, please check config")
}
if _, err := i2c.SendCmd(bus, addr, cal); err != nil {
return err
}
time.Sleep(time.Duration(a.CalDelay) * time.Millisecond) // sleep
_, err := i2c.SendCmd(bus, addr, "") // read for success
// return the err if there is any
return err
}
var ErrReadFail = errors.New("atlas read failure")
func (a *Atlas) TakeReading(bus, addr int) (float64, error) {
// take reading function
if _, err := i2c.SendCmd(bus, addr, "R"); err != nil {
// read command
return 0, err
}
if a.ReadDelay == 0 {
return 0, errors.New("Read Delay unset, please check config")
}
sleep := time.Duration(a.ReadDelay) * time.Millisecond
time.Sleep(sleep) // sleep between reads
data, err := i2c.SendCmd(bus, addr, "")
if err != nil {
return 0, ErrReadFail
}
// fmt data from 0x... to proper
var final string
split := strings.Split(data, " ")
for i, v := range split {
// loop over chars
if i == 0 && v != "0x01" {
// reading failed
return 0, ErrReadFail
}
// trimming bs
trimmed := strings.TrimLeft(v, "0x ")
trimmed = strings.TrimRight(trimmed, " \n")
if trimmed != "ff" && i != 0 {
final += trimmed
}
}
// return as a float
var b []byte
if b, err = hex.DecodeString(final); err != nil {
return 0, err
}
return strconv.ParseFloat(string(b), 32)
}
// for config
func (a *Atlas) GetCalDelay() int {
return a.CalDelay
}
func (a *Atlas) GetReadDelay() int {
return a.ReadDelay
}

@ -0,0 +1,22 @@
package device
import (
"sync"
)
// base controller manager
type ControllerManager struct {
*DeviceManager
sync.Mutex
Enabled bool // turn controller on or off
}
func NewControllerManager() *ControllerManager {
return &ControllerManager{}
}
func (c *ControllerManager) SetDeviceManager(d *DeviceManager) {
c.DeviceManager = d
}

@ -0,0 +1,41 @@
package device
// do sensor and methods
import (
"sync"
)
type DOManager struct {
// do sensor manager
*SensorManager
*Atlas
sync.RWMutex
}
func NewDOManager() *DOManager {
// atlas delays
a := &Atlas{
CalDelay: 1300,
ReadDelay: 600,
}
sm := NewSensorManager()
m := &DOManager{
Atlas: a,
SensorManager: sm,
}
return m
}
func (m *DOManager) Start() error {
// start sensor manager
return m.SensorManager.Start(m.Atlas.TakeReading)
}
func (m *DOManager) String() string {
// TODO
return ""
}

@ -1,150 +1,69 @@
package device
import (
"FRMS/internal/pkg/manager"
"fmt"
"sync"
"time"
"github.com/spf13/viper"
)
type SubManager interface {
Start(int) error
// base device manager
type Manager interface {
// core manager
Start() error
Exit() error
IsActive() int
String() string // printing info about the sub manager
LoadConfig(*viper.Viper, string)
// for config bs
GetDefaultName() string
HeartBeat(chan struct{}, int, int, time.Duration)
}
type NameChan struct {
Ch chan string
func NewManager() Manager {
// no timeouts needed
return manager.New(0)
}
// base device manager
type DeviceManager struct {
SubManager
// across controllers/sensors
Address int `mapstructure:"address"`
Name string `mapstructure:"name"`
infoMu sync.RWMutex
Config *viper.Viper
ConfigPrefix string
// for device agnostic fields/methods
Address int `mapstructure:"address"`
Bus int // i2c bus
// mutable
infoMu sync.RWMutex
Name string `mapstructure:"name"`
defaultName string
// base manager
Manager
// config
Config *viper.Viper
}
func NewDeviceManager(addr int, config *viper.Viper, configPrefix string, i2c I2CClient) (*DeviceManager, error) {
// validate prefix
s, err := NewSubManager(addr, i2c)
func NewDeviceManager(bus, addr int, config *viper.Viper, defaultName string) *DeviceManager {
// new base dm
m := NewManager()
dm := &DeviceManager{
SubManager: s,
Config: config,
Address: addr,
ConfigPrefix: configPrefix,
Address: addr,
Bus: bus,
defaultName: defaultName,
Manager: m,
Config: config,
}
return dm, err
return dm
}
func (m *DeviceManager) LoadConfig() error {
// setting default name
mainKey := fmt.Sprintf("%sdevices.%d", m.ConfigPrefix, m.Address)
mainKey := fmt.Sprintf("devices.%d", m.Address)
nameKey := fmt.Sprintf("%s.name", mainKey)
if !m.Config.IsSet(nameKey) {
m.Config.Set(nameKey, m.SubManager.GetDefaultName())
m.Config.Set(nameKey, m.defaultName)
}
m.Config.UnmarshalKey(mainKey, m)
m.SubManager.LoadConfig(m.Config, mainKey)
return nil
}
func (m *DeviceManager) Start() error {
// load config and then start
var err error
// load config
if err = m.LoadConfig(); err != nil {
return err
}
// start
if err = m.SubManager.Start(m.Address); err != nil {
return err
}
return err
return m.Manager.Start()
}
// dev info grpc handlers
// func (m *DeviceManager) Name(stream pb.DeviceInfo_StatusServer) error {
// // this might be scuffed
// }
// I think I can use grpc streams to do better
// func (m *DeviceManger) GetName(ctx context.Context, req *pb.DeviceName) (*pb.DeviceName, error) {
// // gets name
// var name string
// var err error
// // quick lock
// m.infoMu.RLock()
// name = m.Name
// m.infoMu.RUnlock()
// if name == "" {
// name = m.GetDefaultName()
// err = m.UpdateName(name)
// }
// response := &pb.DeviceName{Address: int32(m.Address), Name: name}
// return response, err
// }
// func (m *DeviceManger) SetName(ctx context.Context, req *pb.DeviceName) (*pb.DeviceName, error) {
// // handles incoming req
// response := &pb.DeviceName{Address: int32(m.Address)}
// err := m.UpdateName()
// return response, err
// }
// func (m *DeviceManager) UpdateName(name string) error {
// // updates name/config
// m.infoMu.Lock()
// defer m.infoMu.Unlock()
// nameKey := fmt.Sprintf("%s.devices.%d.name", m.ConfigPrefix, m.Address)
// m.Config.SetKey(nameKey, name)
// return nil
// }
// func (m *DeviceManger) GetStatus(ctx context.Context, req *pb.DeviceStatus) (*pb.DeviceStatus, error) {
// }
// func (m *DeviceManger) SetStatus(ctx context.Context, req *pb.DeviceStatus) (*pb.DeviceStatus, error) {
// }
// monitoring grpc
// func (m *DeviceManager) GetDevice() (*pb.Device, error) {
// // turns info into pb.Device for monitoring grpc
// }
// func (m *DeviceManger) UpdateDevice(*pb.Device) error {
// // unpacks pb.Device to update itself
// }

@ -1,35 +1,48 @@
package device
import (
"FRMS/internal/pkg/controller"
"FRMS/internal/pkg/sensor"
"errors"
"fmt"
"github.com/spf13/viper"
)
/*
Returns the correct manager for sensor/controller
*/
// Returns the correct manager for sensor/controller
type Device interface {
Start() error
Exit() error
IsActive() int
SetDeviceManager(*DeviceManager)
}
func NewSubManager(addr int, i2c I2CClient) (SubManager, error) {
func New(bus, addr int, config *viper.Viper) (Device, error) {
// returns correct device manager by ID
var m SubManager
var err error
var defaultName string
var m Device
switch addr {
case 97:
// DO
m = sensor.NewDOManager(i2c)
defaultName = "DO Sensor"
m = NewDOManager()
case 99:
// pH
m = sensor.NewPHManager(i2c)
defaultName = "pH Sensor"
m = NewPHManager()
case 102:
// RTD
m = sensor.NewRTDManager(i2c)
defaultName = "RTD Sensor"
m = NewRTDManager()
case 256:
// PWM
m = controller.NewPWMManager()
defaultName = "PWM Controller"
m = NewPWMManager()
default:
err = errors.New(fmt.Sprintf("Error: device id %d unrecognized!", addr))
}
// setting device manager
dm := NewDeviceManager(bus, addr, config, defaultName)
m.SetDeviceManager(dm)
return m, err
}

@ -0,0 +1,40 @@
package device
// do sensor and methods
import (
"sync"
)
type PHManager struct {
// do sensor manager
*SensorManager
*Atlas
sync.RWMutex
}
func NewPHManager() *PHManager {
// atlas delays
a := &Atlas{
CalDelay: 900,
ReadDelay: 900,
}
sm := NewSensorManager()
m := &PHManager{
Atlas: a,
SensorManager: sm,
}
return m
}
func (m *PHManager) Start() error {
// start sensor manager
return m.SensorManager.Start(m.Atlas.TakeReading)
}
func (m PHManager) String() string {
// TODO
return ""
}

@ -1,12 +1,9 @@
package controller
package device
// do sensor and methods
import (
"fmt"
"sync"
"github.com/spf13/viper"
)
type PWMManager struct {
@ -29,14 +26,6 @@ func (m *PWMManager) GetFrequency() (int, error) {
return m.Frequency, nil
}
func (m *PWMManager) LoadConfig(config *viper.Viper, key string) {
fmt.Printf("config\n")
}
func (m *PWMManager) GetDefaultName() string {
return "pwm controller"
}
func (m *PWMManager) String() string {
// TODO
return ""

@ -0,0 +1,38 @@
package device
// do sensor and methods
import (
"sync"
)
type RTDManager struct {
// do sensor manager
*Atlas
*SensorManager
sync.RWMutex
}
func NewRTDManager() *RTDManager {
// atlas delays
a := &Atlas{
CalDelay: 600,
ReadDelay: 600,
}
sm := NewSensorManager()
m := &RTDManager{
Atlas: a,
SensorManager: sm,
}
return m
}
func (m *RTDManager) Start() error {
return m.SensorManager.Start(m.Atlas.TakeReading)
}
func (m *RTDManager) String() string {
// TODO
return ""
}

@ -0,0 +1,88 @@
package device
import (
"errors"
"fmt"
"sync"
"time"
)
type SensorManager struct {
SampleRate int `mapstructure:"sample_rate"` // in (ms)
// sampling
sampleMu sync.RWMutex
LatestSample float32
*DeviceManager `mapstructure:",squash"`
}
func NewSensorManager() *SensorManager {
s := &SensorManager{}
return s
}
func (s *SensorManager) SetDeviceManager(d *DeviceManager) {
s.DeviceManager = d
}
type takeReading func(int, int) (float64, error)
func (s *SensorManager) Start(f takeReading) error {
// loading config
if err := s.LoadConfig(); err != nil {
return err
}
// starting
if err := s.DeviceManager.Start(); err != nil {
return err
}
// starting monitoring
go s.Monitor(f)
return nil
}
func (s *SensorManager) LoadConfig() error {
// setting keys
mainKey := fmt.Sprintf("devices.%d", s.Address)
sampleKey := fmt.Sprintf("%s.sample_rate", mainKey)
if !s.Config.IsSet(sampleKey) {
// no sample rate, default to 10s
s.Config.Set(sampleKey, 10000)
}
// loading lower
s.DeviceManager.LoadConfig()
s.Config.UnmarshalKey(mainKey, s)
return nil
}
func (s *SensorManager) Monitor(f takeReading) {
ch := make(chan struct{}) // hb chan
go s.HeartBeat(ch, s.SampleRate, 2000, time.Millisecond)
var reading float64
var err error
for range ch {
if reading, err = f(s.Bus, s.Address); err != nil {
if !errors.Is(err, ErrReadFail) {
// unknown error, panic
panic(err)
}
fmt.Printf("Reading failed, skipping!\n")
}
// update sample
if !errors.Is(err, ErrReadFail) {
fmt.Printf("Got %f\n", reading)
s.sampleMu.Lock()
s.LatestSample = float32(reading)
s.sampleMu.Unlock()
}
}
}

@ -1,52 +1,22 @@
package I2C
package i2c
// file has general wrappers to interact with i2c-tools
import (
"FRMS/internal/pkg/logging"
"FRMS/internal/pkg/system"
"bytes"
"encoding/hex"
"errors"
"fmt"
_ "log"
"os/exec"
"strconv"
"strings"
"sync"
"github.com/spf13/viper"
)
type I2CClient struct {
Bus int `mapstructure:"bus"`
sync.Mutex
}
func NewClient(config *viper.Viper) (*I2CClient, error) {
var err error
var bus int
client := &I2CClient{}
if !config.IsSet("i2c.bus") {
// no bus
if bus, err = system.GetBus(); err != nil {
return client, err
}
config.Set("i2c.bus", bus)
}
err = config.UnmarshalKey("i2c", client)
return client, err
}
func (b *I2CClient) GetConnected() (map[int]bool, error) {
/*
Returns all the connected devices by address
I can def improve this
*/
b.Lock()
defer b.Unlock()
func GetConnected(b int) (map[int]bool, error) {
// Returns all the connected devices by address
// might just do this in bash and make it easier
bus := strconv.Itoa(b)
devices := make(map[int]bool) // only keys
bus := strconv.Itoa(b.Bus)
cmd := exec.Command("i2cdetect", "-y", "-r", bus)
var out bytes.Buffer
var errs bytes.Buffer
@ -85,13 +55,11 @@ func (b *I2CClient) GetConnected() (map[int]bool, error) {
return devices, nil
}
func (b *I2CClient) SendCmd(addr int, command string) (string, error) {
b.Lock()
defer b.Unlock()
// formatting parameters
func SendCmd(b, addr int, command string) (string, error) {
// sends an arbituary commnd over specified bus to int
// might make a base script for this too
var cmd *exec.Cmd
bus := strconv.Itoa(b.Bus)
bus := strconv.Itoa(b)
operation := "r20" // default read
frmt_cmd := "" // empty cmd
if command != "" {
@ -113,31 +81,8 @@ func (b *I2CClient) SendCmd(addr int, command string) (string, error) {
cmd.Stderr = &errs
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
logging.Debug(logging.DError, "I2C error getting data! %v", errs.String())
fmt.Println(errs.String())
logging.Debug(logging.DError, "I2C error getting data! %v", err)
return "", err
}
outString := out.String()
if outString == "" {
return outString, nil
}
split := strings.Split(outString, " ") //getting chars 0x12 0x2f etc
var final string
for i, v := range split {
if i == 0 && v != "0x01" {
// atlas check
return "", errors.New(fmt.Sprintf("Command %s not recognized!", command))
}
trimmed := strings.TrimLeft(v, "0x ") // trimming extra bs in front of num
trimmed = strings.TrimRight(trimmed, " \n") // trimming back
if trimmed != "ff" && i != 0 {
// remove padding
final += trimmed
}
}
ret, err := hex.DecodeString(final)
// return
return string(ret), err
return out.String(), nil
}

@ -3,7 +3,6 @@ package reactor
// file describes reactor level coordinator and associated implementation
import (
"FRMS/internal/pkg/device"
pb "FRMS/internal/pkg/grpc"
"FRMS/internal/pkg/influxdb"
"FRMS/internal/pkg/logging"
@ -41,27 +40,18 @@ func NewDBClient(config *viper.Viper) (DBClient, error) {
return influxdb.NewDBClient(config)
}
// device coordinator
type DeviceCoordinator interface {
Start() error
// in grpc format
GetDeviceInfo() ([]*pb.Device, error)
}
func NewDeviceCoordinator(config *viper.Viper) DeviceCoordinator {
return device.NewCoordinator(config)
}
type Server struct {
Ip string `mapstructure:"ip"`
Port int `mapstructure:"port"`
}
type Info struct {
type ReactorInfo struct {
Name string `mapstructure:"name,omitempty"`
ID int `mapstructure:"id,omitempty"`
Model string `mapstructure:"model,omitempty"`
HB int `mapstructure:"heartbeat"`
Bus int `mapstructure:"bus"`
Server
}
@ -69,13 +59,13 @@ type ReactorCoordinator struct {
Manager // base manager
Config *viper.Viper // config
Info `mapstructure:",squash"`
ReactorInfo `mapstructure:",squash"`
Database DBClient
pb.MonitoringClient // grpc embedding
DeviceCoordinator // struct for locking
*DeviceCoordinator // struct for locking
Err chan error
}
@ -111,7 +101,7 @@ func (c *ReactorCoordinator) Start() {
c.Err <- err
}
if err = c.DeviceCoordinator.Start(); err != nil {
if err = c.DeviceCoordinator.Start(c.ReactorInfo.Bus); err != nil {
c.Err <- err
}
@ -154,6 +144,16 @@ func (c *ReactorCoordinator) LoadConfig() error {
c.Config.Set("reactor.model", model)
}
// check i2c bus
if !c.Config.IsSet("reactor.bus") {
// get from hw
var bus int
if bus, err = system.GetBus(); err != nil {
return err
}
c.Config.Set("reactor.bus", bus)
}
// all good, unmarhsaling
c.Config.UnmarshalKey("reactor", c)

@ -1,9 +1,9 @@
package device
package reactor
import (
"FRMS/internal/pkg/I2C"
"FRMS/internal/pkg/device"
pb "FRMS/internal/pkg/grpc"
"FRMS/internal/pkg/manager"
"FRMS/internal/pkg/i2c"
"fmt"
"sync"
"time"
@ -13,61 +13,48 @@ import (
// Created by rlc to manage devices
// basic manager to embed
type Manager interface {
// device manager
type DeviceManager interface {
Start() error
Exit() error
// create a heartbeat to send to chan at intervals
HeartBeat(chan struct{}, int, int, time.Duration)
IsActive() int
}
func NewManager() Manager {
// dont need timeout functionality
return manager.New(0)
}
// I2C client for locking
type I2CClient interface {
// i2c client w/ locking
GetConnected() (map[int]bool, error) // gets connected addresses
SendCmd(int, string) (string, error)
}
func NewI2CClient(config *viper.Viper) (I2CClient, error) {
return I2C.NewClient(config)
func NewDeviceManager(bus, addr int, config *viper.Viper) (DeviceManager, error) {
return device.New(bus, addr, config)
}
// device coordinator itself
type DeviceCoordinator struct {
I2C I2CClient
// base level manager for heartbeat
Bus int // i2c bus
Manager
Config *viper.Viper
managersMu sync.RWMutex
Managers map[int]*DeviceManager
managersMu sync.RWMutex
DeviceManagers map[int]DeviceManager
}
func NewCoordinator(config *viper.Viper) *DeviceCoordinator {
dm := make(map[int]*DeviceManager)
m := NewManager()
func NewDeviceCoordinator(config *viper.Viper) *DeviceCoordinator {
dm := make(map[int]DeviceManager)
m := NewManager(0)
c := &DeviceCoordinator{
Manager: m,
Managers: dm,
Config: config,
Manager: m,
DeviceManagers: dm,
Config: config,
}
return c
}
func (c *DeviceCoordinator) Start() error {
func (c *DeviceCoordinator) Start(bus int) error {
var err error
if err = c.Manager.Start(); err != nil {
return err
}
// i2c bus
c.Bus = bus
if c.I2C, err = NewI2CClient(c.Config); err != nil {
return err
}
go c.Monitor()
return err
}
@ -79,7 +66,7 @@ func (c *DeviceCoordinator) Monitor() {
for range ch {
// on notification (10s)
devs, err := c.I2C.GetConnected()
devs, err := i2c.GetConnected(c.Bus)
if err != nil {
panic(err)
}
@ -93,7 +80,7 @@ func (c *DeviceCoordinator) UpdateManagers(active map[int]bool) {
c.managersMu.Lock()
defer c.managersMu.Unlock()
for addr, dm := range c.Managers {
for addr, dm := range c.DeviceManagers {
_, ok := active[addr]
if ok && dm.IsActive() == 0 {
@ -101,7 +88,7 @@ func (c *DeviceCoordinator) UpdateManagers(active map[int]bool) {
if err := dm.Start(); err != nil {
panic(err)
}
} else if dm.IsActive() == 1 {
} else if !ok && dm.IsActive() == 1 {
// not active and dm is
if err := dm.Exit(); err != nil {
panic(err)
@ -115,7 +102,7 @@ func (c *DeviceCoordinator) UpdateManagers(active map[int]bool) {
// no manager, create one
fmt.Printf("New device %d!\n", addr)
dm, err := NewDeviceManager(addr, c.Config, "", c.I2C)
dm, err := NewDeviceManager(c.Bus, addr, c.Config)
if err != nil {
panic(err)
}
@ -124,7 +111,7 @@ func (c *DeviceCoordinator) UpdateManagers(active map[int]bool) {
panic(err)
}
c.Managers[addr] = dm
c.DeviceManagers[addr] = dm
}
}
@ -135,7 +122,7 @@ func (c *DeviceCoordinator) GetDeviceInfo() ([]*pb.Device, error) {
var devices []*pb.Device
for addr, dm := range c.Managers {
for addr, dm := range c.DeviceManagers {
// looping over devices
devices = append(devices, &pb.Device{
Addr: int32(addr),

@ -1,67 +0,0 @@
package sensor
import (
"errors"
"strconv"
"time"
)
// atlas helpers to aid with sensors
type I2CClient interface {
SendCmd(int, string) (string, error)
}
type Atlas struct {
// helper struct to embedd
I2C I2CClient
// delays unmarshalled
CalDelay int `mapstructure:"cal"`
ReadDelay int `mapstructure:"read"`
}
func (a *Atlas) Calibrate(addr int, cal string) error {
// calibrate sensor
if a.CalDelay == 0 {
return errors.New("Cal delay unset, please check config")
}
if _, err := a.I2C.SendCmd(addr, cal); err != nil {
return err
}
time.Sleep(time.Duration(a.CalDelay) * time.Millisecond) // sleep
_, err := a.I2C.SendCmd(addr, "") // read for success
// return the err if there is any
return err
}
func (a *Atlas) Read(addr int) (float32, error) {
// take reading function
if _, err := a.I2C.SendCmd(addr, "R"); err != nil {
// read command
//fmt.Printf("Error writing! %s", err)
return 0, err
}
if a.ReadDelay == 0 {
return 0, errors.New("Read Delay unset, please check config")
}
sleep := time.Duration(a.ReadDelay) * time.Millisecond
time.Sleep(sleep) // sleep between reads
data, err := a.I2C.SendCmd(addr, "")
if err != nil {
return 0, err
}
f, err := strconv.ParseFloat(data, 32)
return float32(f), err
}
// for config
func (a *Atlas) GetCalDelay() int {
return a.CalDelay
}
func (a *Atlas) GetReadDelay() int {
return a.ReadDelay
}

@ -1,43 +0,0 @@
package sensor
// do sensor and methods
import (
"fmt"
"sync"
"github.com/spf13/viper"
)
type DOManager struct {
// do sensor manager
*Atlas
*SensorManager `mapstructure:",squash"`
sync.RWMutex
}
func NewDOManager(i2c I2CClient) *DOManager {
a := &Atlas{I2C: i2c}
sm := NewSensorManager(a.Read)
m := &DOManager{
SensorManager: sm,
Atlas: a,
}
return m
}
func (m *DOManager) LoadConfig(config *viper.Viper, key string) {
config.UnmarshalKey(key, m)
fmt.Printf("DO: %v\n", m.Atlas)
}
func (m *DOManager) GetDefaultName() string {
return "DO Sensor"
}
func (m *DOManager) String() string {
// TODO
return ""
}

@ -1,75 +0,0 @@
package sensor
import (
"FRMS/internal/pkg/manager"
"fmt"
"sync"
"time"
)
type Manager interface {
Start() error
Exit() error
IsActive() int
HeartBeat(chan struct{}, int, int, time.Duration)
}
func NewManager(max int) Manager {
return manager.New(max)
}
type Reading struct {
sync.RWMutex
Latest float32
New func(int) (float32, error)
}
type SensorManager struct {
SampleRate int `mapstructure:"samplerate"` // in (ms)
Manager
*Reading
}
func NewSensorManager(f func(int) (float32, error)) *SensorManager {
m := NewManager(0) // no timeout
r := &Reading{New: f}
s := &SensorManager{
Manager: m,
Reading: r,
}
return s
}
func (s *SensorManager) Start(addr int) error {
if err := s.Manager.Start(); err != nil {
return err
}
fmt.Printf("Sensor %d: %v\n", addr, s)
// starting monitoring
go s.Monitor(addr)
return nil
}
func (s *SensorManager) Monitor(addr int) {
ch := make(chan struct{}) // hb chan
if s.SampleRate == 0 {
s.SampleRate = 5000
}
go s.HeartBeat(ch, s.SampleRate, 1000, time.Millisecond)
for range ch {
go s.TakeReading(addr)
}
}
func (r *Reading) TakeReading(addr int) {
sample, err := r.New(addr)
if err != nil {
panic(err)
}
fmt.Printf("got sample: %v\n", sample)
r.Lock()
defer r.Unlock()
r.Latest = sample
}

@ -1,42 +0,0 @@
package sensor
// do sensor and methods
import (
"fmt"
"sync"
"github.com/spf13/viper"
)
type PHManager struct {
// do sensor manager
*Atlas
*SensorManager `mapstructure:",squash"`
sync.RWMutex
}
func NewPHManager(i2c I2CClient) *PHManager {
a := &Atlas{I2C: i2c}
sm := NewSensorManager(a.Read)
m := &PHManager{
SensorManager: sm,
Atlas: a,
}
return m
}
func (s *PHManager) LoadConfig(config *viper.Viper, key string) {
config.UnmarshalKey(key, s)
fmt.Printf("PH: %v\n", s.Atlas)
}
func (s *PHManager) GetDefaultName() string {
return "pH Sensor"
}
func (s PHManager) String() string {
// TODO
return ""
}

@ -1,41 +0,0 @@
package sensor
// do sensor and methods
import (
"fmt"
"sync"
"github.com/spf13/viper"
)
type RTDManager struct {
// do sensor manager
*Atlas
*SensorManager `mapstructure:",squash"`
sync.RWMutex
}
func NewRTDManager(i2c I2CClient) *RTDManager {
a := &Atlas{I2C: i2c}
sm := NewSensorManager(a.Read)
m := &RTDManager{
SensorManager: sm,
Atlas: a,
}
return m
}
func (s *RTDManager) LoadConfig(config *viper.Viper, key string) {
config.UnmarshalKey(key, s)
fmt.Printf("RTD: %v\n", s.Atlas)
}
func (s *RTDManager) GetDefaultName() string {
return "RTD Sensor"
}
func (s *RTDManager) String() string {
// TODO
return ""
}
Loading…
Cancel
Save