82 lines
2.4 KiB
Go
82 lines
2.4 KiB
Go
package statusupdate
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"errors"
|
|
"strings"
|
|
"sync"
|
|
|
|
"src.dualinventive.com/go/lib/dilog"
|
|
)
|
|
|
|
// StatusDecoder decodes cp3000 status messages
|
|
type StatusDecoder struct {
|
|
mu sync.RWMutex
|
|
prevUpdateState *StatusUpdate
|
|
resetFields StatUpdateField
|
|
logger dilog.Logger
|
|
}
|
|
|
|
// NewStatusDecoder creates a new status decoder. The initial parameter is already set.
|
|
func NewStatusDecoder(logger dilog.Logger, fields StatUpdateField) *StatusDecoder {
|
|
return &StatusDecoder{
|
|
prevUpdateState: &StatusUpdate{
|
|
Fields: fields,
|
|
},
|
|
resetFields: fields,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// Decode decodes the cp3000 status message
|
|
func (d *StatusDecoder) Decode(args []string) error {
|
|
r := csv.NewReader(strings.NewReader(args[1]))
|
|
r.Comma = ','
|
|
r.LazyQuotes = true
|
|
record, err := r.Read()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(record) != 22 {
|
|
return errors.New("wrong record count for statusupdate")
|
|
}
|
|
|
|
// This decoder is based on the original TCP-server implemetation,
|
|
// a status message can contains all fields but some may miss.
|
|
// no errors are checked since the checksum is complete and we know
|
|
// we have 22 fields at this point, this MUST be a generic status update
|
|
// ---- SAME AS LEGACY ---- >:-D
|
|
s := &StatusUpdate{}
|
|
|
|
// IMPORTANT the order here is important
|
|
records := decodeState(d.logger, s, StatUpdateAll, record)
|
|
records = decodeWCPUState(d.logger, s, StatUpdateAll, records)
|
|
records = decodeAutocal(d.logger, s, StatUpdateAll, records)
|
|
records = decodeRMS(d.logger, s, StatUpdateAll, records)
|
|
records = decodeBA(d.logger, s, StatUpdateAll, records)
|
|
records = decodeBatSelected(d.logger, s, StatUpdateAll, records)
|
|
records = decodeBatt1Level(d.logger, s, StatUpdateAll, records)
|
|
records = decodeBatt2Level(d.logger, s, StatUpdateAll, records)
|
|
records = decodeTempOnBoard(d.logger, s, StatUpdateAll, records)
|
|
records = decodeTempNTC(d.logger, s, StatUpdateAll, records)
|
|
records = decodeGSM(d.logger, s, StatUpdateAll, records)
|
|
decodeGPS(d.logger, s, StatUpdateAll, records)
|
|
|
|
// The GPS is updated every 30 minutes we want to send all sensor
|
|
// every once in a while, so we abuse the GPS-time :-)
|
|
if d.prevUpdateState.GPSTime != s.GPSTime {
|
|
s.Fields = d.resetFields
|
|
}
|
|
d.mu.Lock()
|
|
d.prevUpdateState = s
|
|
d.mu.Unlock()
|
|
return nil
|
|
}
|
|
|
|
// StatusUpdate returns the last known status update
|
|
func (d *StatusDecoder) StatusUpdate() *StatusUpdate {
|
|
d.mu.RLock()
|
|
defer d.mu.RUnlock()
|
|
return d.prevUpdateState
|
|
}
|