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 } */