Files
cloud-services/pkg/dbc/models/can_message.go

144 lines
3.6 KiB
Go

package models
import (
"fmt"
"fiskerinc.com/modules/dbc/state"
"fiskerinc.com/modules/common"
"fiskerinc.com/modules/digitaltwin"
)
type CANMessageInterface interface {
AddSignal(signal CANSignal) CANMessageInterface
GetID() int
GetLength() int
ParseState(keyvaluesOut map[string]interface{}, vin string, timestampUSec int, incomingSignals []common.CANSignal, cached digitaltwin.DigitalTwinCacheInterface) error
Signal(position int, name string, convert func(value float64) interface{}) CANMessageInterface
}
// NewCANMessage creates a top level instance for parsing a command. The id is the can signal in which individual signals exists
// length is the number of messages inside the message, i.e. 1318 TBOX_0x526 has 2 different signals: TBOX_GPSLongi and TBOX_GPSLati
func NewCANMessage(id int, length int) CANMessageInterface {
return &CANMessage{
id: id,
length: length,
}
}
type CANMessage struct {
id int
length int
signals map[int]CANSignal
diagnostic map[int]DiagnosticSignal
}
func (c *CANMessage) GetID() int {
return c.id
}
func (c *CANMessage) GetLength() int {
return c.length
}
// position is the index of the signal in its list. Starting at zero
func (c *CANMessage) Signal(position int, name string, convert func(value float64) interface{}) CANMessageInterface {
c.AddSignal(NewCANSignal(position, name, convert))
return c
}
func (c *CANMessage) AddSignal(signal CANSignal) CANMessageInterface {
m := c.getSignalsMap()
if _, ok := m[signal.Position]; ok {
panic(fmt.Sprintf("signal position %d already exists", signal.Position))
}
m[signal.Position] = signal
return c
}
func (c *CANMessage) Diagnostic(position int, name string, alert float64) CANMessageInterface {
c.AddDiagnostic(NewDiagnosticSignal(position, name, alert))
return c
}
func (c *CANMessage) AddDiagnostic(signal DiagnosticSignal) CANMessageInterface {
m := c.getDiagnosticMap()
if _, ok := m[signal.Position]; ok {
panic(fmt.Sprintf("diagnositic position %d already exists", signal.Position))
}
m[signal.Position] = signal
return c
}
func (c *CANMessage) getDiagnosticMap() map[int]DiagnosticSignal {
if c.diagnostic == nil {
c.diagnostic = map[int]DiagnosticSignal{}
}
return c.diagnostic
}
func (c *CANMessage) getSignalsMap() map[int]CANSignal {
if c.signals == nil {
c.signals = map[int]CANSignal{}
}
return c.signals
}
// cached: Checks if the new signal has the same value as it did the last time, if so don't update it
func (c *CANMessage) ParseState(keyvaluesOut map[string]interface{}, vin string, timestampUSec int, incomingSignals []common.CANSignal, cached digitaltwin.DigitalTwinCacheInterface) error {
var can CANSignal
var ok bool
s := c.getSignalsMap()
for i, signal := range incomingSignals {
if can, ok = s[i]; !ok {
continue
}
if can.Name != signal.Name {
return IncorrectSignalError(can.Name, signal.Name)
}
val := can.ParseState(incomingSignals[i])
if cached != nil && cached.Exists(vin, signal.Name, val) {
continue
}
keyvaluesOut[signal.Name] = val
// Added updated time for each signals. Key format -> "${signal_name}:updated"
updatedAt, _ := state.SerializeTimestampUSec(timestampUSec)
keyvaluesOut[fmt.Sprintf("%s:%s", signal.Name, "updated")] = updatedAt
}
return nil
}
/*
func (c *CANMessage) DiagnosticAlert(vin string, timestampUSec int, signals []common.CANSignal) ([]DiagnosticSignal, error) {
var flags []DiagnosticSignal
m := c.getDiagnosticMap()
for i, signal := range signals {
if diag, ok := m[i]; !ok {
continue
}
if diag.Name != signal.Name {
return nil, IncorrectSignalError(diag.Name, signal.Name)
}
append(flags, diag)
}
return nil, nil
}
*/