Commit 7fa46ce4 authored by Eric S. Raymond's avatar Eric S. Raymond

Factor out the hardware class so lcdtest can use it.

parent f7d0b2c6
......@@ -5,7 +5,7 @@
// mirrored by the simulator module, which allows us to test-jig the
// policy logic without talking to hardware.
package main
package hardware
import (
"log"
......@@ -19,6 +19,7 @@ import (
"gobot.io/x/gobot/platforms/beaglebone"
"hd44780"
"sbd"
)
/* Interconnect types */
......@@ -29,6 +30,38 @@ const (
GPIO
)
type SensorType int
const (
INVALID SensorType = iota /* so it won't show in maps */
AC /* AC monitor - returns voltage-current */
DC /* DC Monitor - returns voltage-current */
BMS /* Battery Management System */
BTN /* Button */
)
/* Encapsulate the hardware sensors */
type SensorTake struct {
Type SensorType
ID string
Timestamp time.Time
/* AC and DC load sensors */
Volts int
Amps int
/* Battery management */
Bms *sbd.SBDMessage
/* Buttons */
ButtonMask int
}
func (s * SensorTake) ButtonSet(n uint, v bool) {
s.ButtonMask |= (1 << n)
}
func (s * SensorTake) ButtonGet(n uint) bool {
return (s.ButtonMask & (1 << n)) != 0
}
/*
* Hardware configuration.
*
......@@ -82,7 +115,7 @@ func init() {
/* There could be other variants in the future */
}
var HardwareConfiguration *HardwareConfig = &UPSide1
var Configuration *HardwareConfig = &UPSide1
type HardwareType struct {
sensorIndex int /* where we are in the master sensor list */
......@@ -93,13 +126,13 @@ type HardwareType struct {
func (s *HardwareType) Init() {
s.sensorNames = make([]string, 0)
for _, v := range HardwareConfiguration.Sensors {
for _, v := range Configuration.Sensors {
s.sensorNames = append(s.sensorNames, v.Name)
}
s.adaptor = beaglebone.NewAdaptor()
d, err := i2c.Open(&i2c.Devfs{Dev: HardwareConfiguration.DisplayDevice}, HardwareConfiguration.DisplayAddress)
d, err := i2c.Open(&i2c.Devfs{Dev: Configuration.DisplayDevice}, Configuration.DisplayAddress)
if err != nil { log.Fatal(err) }
lcd, err := hd44780.NewLcd(d, hd44780.LCD_20x4)
if err != nil { log.Fatal(err) }
......@@ -120,7 +153,7 @@ func (s *HardwareType) SensorList() []string {
}
func (s *HardwareType) PollSensor(st *SensorTake) bool {
if s.sensorIndex > len(HardwareConfiguration.Sensors) {
if s.sensorIndex > len(Configuration.Sensors) {
return false
}
s.sensorIndex++
......@@ -131,7 +164,7 @@ func (s *HardwareType) PollSensor(st *SensorTake) bool {
}
func (s *HardwareType) SensorClass(id string) SensorType {
for _, v := range HardwareConfiguration.Sensors {
for _, v := range Configuration.Sensors {
if v.Name == id {
return v.SensorType
}
......
......@@ -5,16 +5,14 @@ import (
"log"
"time"
"hd44780"
"golang.org/x/exp/io/i2c"
)
// Keep these synced with the daemon's hardware config
const LCDDevice = "/dev/i2c-2"
const LCDAddress = 0x26
"hardware"
"hd44780"
)
func main() {
i2c, err := i2c.Open(&i2c.Devfs{Dev: LCDDevice}, LCDAddress)
i2c, err := i2c.Open(&i2c.Devfs{Dev: hardware.Configuration.Device}, hardware.Configuration.DisplayAddress)
if err != nil { log.Fatal(err) }
// Free I2C connection on exit
defer i2c.Close()
......
......@@ -8,6 +8,8 @@ import (
"log"
"strings"
"time"
"hardware"
)
/*
......@@ -62,7 +64,7 @@ func percentify(n int) string {
func (ob *Observables) onMainsExplanation(status string) string {
lv := stringify(ob.LineVoltage, 3)
ow := stringify(ob.OutputAmps * HardwareConfiguration.DCVoltage, 3)
ow := stringify(ob.OutputAmps * hardware.Configuration.DCVoltage, 3)
mf := clockify(ob.TimeToFull)
//me := clockify(ob.TimeToEmpty)
cp := percentify(ob.ChargePercentage)
......@@ -74,7 +76,7 @@ func (ob *Observables) onMainsExplanation(status string) string {
func (ob *Observables) onBatteryExplanation(status string) string {
lv := stringify(ob.LineVoltage, 3)
ow := stringify(ob.OutputAmps * HardwareConfiguration.DCVoltage, 3)
ow := stringify(ob.OutputAmps * hardware.Configuration.DCVoltage, 3)
//mf := clockify(ob.TimeToFull)
me := clockify(ob.TimeToEmpty)
cp := percentify(ob.ChargePercentage)
......
......@@ -17,6 +17,8 @@ import (
"strconv"
"strings"
"time"
"hardware"
)
var sbdc sbd.SBDContext
......@@ -24,12 +26,12 @@ var sbdc sbd.SBDContext
type SimulatorType struct {
Reader *bufio.Reader
exhausted bool
sensors map[string]SensorType
sensors map[string]hardware.SensorType
sensorSeq []string
}
func (s *SimulatorType) registerSensor(id string, t SensorType) {
if s.sensors[id] == INVALID {
func (s *SimulatorType) registerSensor(id string, t hardware.SensorType) {
if s.sensors[id] == hardware.INVALID {
s.sensorSeq = append(s.sensorSeq, id)
}
s.sensors[id] = t
......@@ -37,7 +39,7 @@ func (s *SimulatorType) registerSensor(id string, t SensorType) {
func (s *SimulatorType) Init() {
s.Reader = bufio.NewReader(os.Stdin)
s.sensors = make(map[string]SensorType)
s.sensors = make(map[string]hardware.SensorType)
s.sensorSeq = make([]string, 0)
}
......@@ -55,9 +57,9 @@ func popField(text string) (string, string) {
return fld, text
}
func (s *SimulatorType) PollSensor(take *SensorTake) bool {
func (s *SimulatorType) PollSensor(take *hardware.SensorTake) bool {
// Parse the next line of simulated sensor data
take.Type = INVALID
take.Type = hardware.INVALID
line, isP, err := s.Reader.ReadLine()
if err == io.EOF {
......@@ -96,30 +98,30 @@ func (s *SimulatorType) PollSensor(take *SensorTake) bool {
switch class {
case "ac":
take.Type = AC
take.Type = hardware.AC
i, err := fmt.Sscanf(text, "%d amps", &take.Amps)
if err != nil || i != 1 {
fmt.Fprintf(os.Stderr, "malformed ac event line")
return true
}
s.registerSensor(id, AC)
s.registerSensor(id, hardware.AC)
case "dc":
take.Type = DC
take.Type = hardware.DC
i, err := fmt.Sscanf(text, "%d volts %d amps", &take.Volts, &take.Amps)
if err != nil || i != 2 {
fmt.Fprintf(os.Stderr, "malformed dc event line")
return true
}
s.registerSensor(id, DC)
s.registerSensor(id, hardware.DC)
case "bms":
take.Type = BMS
take.bms = sbdc.Unmarshal(text)
s.registerSensor(id, BMS)
take.Type = hardware.BMS
take.Bms = sbdc.Unmarshal(text)
s.registerSensor(id, hardware.BMS)
case "btn":
var bi uint
var bv bool
take.Type = BTN
s.registerSensor(id, BTN)
take.Type = hardware.BTN
s.registerSensor(id, hardware.BTN)
fmt.Sscanf(take.ID, "btn%d %t", &bi)
fmt.Sscanf(text, "%t", &bv)
take.ButtonSet(bi, bv)
......@@ -128,7 +130,7 @@ func (s *SimulatorType) PollSensor(take *SensorTake) bool {
return true
}
func (s *SimulatorType) SensorClass(id string) SensorType {
func (s *SimulatorType) SensorClass(id string) hardware.SensorType {
return s.sensors[id]
}
......
......@@ -12,10 +12,11 @@ import (
"log"
"os"
"reflect"
"sbd"
"strings"
"time"
"github.com/BurntSushi/toml"
"hardware"
)
const version = "0.1"
......@@ -43,38 +44,6 @@ func (p *policyConfig) HostControl() string {
return fmt.Sprintf("ctrl%d", p.HostPair)
}
/* Encapsulate the hardware sensors */
type SensorType int
const (
INVALID SensorType = iota /* so it won't show in maps */
AC /* AC monitor - returns voltage-current */
DC /* DC Monitor - returns voltage-current */
BMS /* Battery Management System */
BTN /* Button */
)
type SensorTake struct {
Type SensorType
ID string
Timestamp time.Time
/* AC and DC load sensors */
Volts int
Amps int
/* Battery management */
bms *sbd.SBDMessage
/* Buttons */
ButtonMask int
}
func (s * SensorTake) ButtonSet(n uint, v bool) {
s.ButtonMask |= (1 << n)
}
func (s * SensorTake) ButtonGet(n uint) bool {
return (s.ButtonMask & (1 << n)) != 0
}
const Unknown int = -1
func IsKnown(n int) bool {
......@@ -131,8 +100,8 @@ type PowerPlane interface {
Init()
Continue() bool
SensorList() []string
PollSensor(*SensorTake) bool
SensorClass(string) SensorType
PollSensor(*hardware.SensorTake) bool
SensorClass(string) hardware.SensorType
Display(string)
ShutdownHost()
ShutdownUPS()
......@@ -141,7 +110,7 @@ type PowerPlane interface {
Wait(time.Duration)
}
var UPSide PowerPlane = &Hardware
var UPSide PowerPlane = &hardware.Hardware
func init() {
PolicyConfiguration = policyConfig{
......@@ -221,12 +190,12 @@ func main() {
// Walk through all sensors
Present.OutputAmps = 0
for {
var take SensorTake
var take hardware.SensorTake
if !UPSide.PollSensor(&take) {
break
}
if take.Type == INVALID {
if take.Type == hardware.INVALID {
continue
}
takeReduce(&take, &Present)
......@@ -247,15 +216,15 @@ func main() {
* Data reduction and policy logic starts here.
*/
func takeReduce(take *SensorTake, ob *Observables) {
func takeReduce(take *hardware.SensorTake, ob *Observables) {
switch take.Type {
case AC:
case hardware.AC:
if ob.OutputAmps == Unknown {
ob.OutputAmps = 0
}
ob.OutputAmps += take.Amps
ob.LoadMap[take.ID] = int(take.Amps)
case DC:
case hardware.DC:
if strings.HasPrefix(take.ID, "mains") {
ob.LineVoltage = int(take.Volts)
} else {
......@@ -265,23 +234,23 @@ func takeReduce(take *SensorTake, ob *Observables) {
ob.OutputAmps += take.Amps
}
ob.LoadMap[take.ID] = int(take.Amps)
case BMS:
switch take.bms.MessageType {
case hardware.BMS:
switch take.Bms.MessageType {
case "AverageTimeToEmpty":
ob.TimeToEmpty = time.Duration(int(take.bms.UnsignedIntArg))
ob.TimeToEmpty = time.Duration(int(take.Bms.UnsignedIntArg))
ob.TimeToEmpty *= time.Minute
case "RelativeStateOfCharge":
ob.ChargePercentage = int(take.bms.UnsignedIntArg)
ob.ChargePercentage = int(take.Bms.UnsignedIntArg)
if ob.ChargePercentage >= 100 && time.Duration(ob.TimeToEmpty) != time.Duration(Unknown) {
ob.MaximumDwellTime = time.Duration(int(ob.TimeToEmpty))
}
case "AverageTimeToFull":
ob.TimeToFull = time.Duration(int(take.bms.UnsignedIntArg))
ob.TimeToFull = time.Duration(int(take.Bms.UnsignedIntArg))
ob.TimeToFull *= time.Minute
case "AbsoluteStateOfCharge":
ob.LifePercentage = int(take.bms.UnsignedIntArg)
ob.LifePercentage = int(take.Bms.UnsignedIntArg)
}
case BTN:
case hardware.BTN:
ob.ButtonMask |= take.ButtonMask
}
}
......@@ -290,7 +259,7 @@ func takeReduce(take *SensorTake, ob *Observables) {
* goodVoltage tells us whether we have good voltage fron the mains
*/
func (ob *Observables) goodVoltage() bool {
res := float32(ob.LineVoltage) >= PolicyConfiguration.VoltageThreshold * float32(HardwareConfiguration.DCVoltage)
res := float32(ob.LineVoltage) >= PolicyConfiguration.VoltageThreshold * float32(hardware.Configuration.DCVoltage)
return res
}
......@@ -373,7 +342,7 @@ func EnableAllOutlets() {
if id == "mains" {
continue
}
if UPSide.SensorClass(id) == AC || UPSide.SensorClass(id) == DC {
if UPSide.SensorClass(id) == hardware.AC || UPSide.SensorClass(id) == hardware.DC {
UPSide.OutletControl(id, true)
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment