Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
186
pkg/dbc/models/dbc_version.go
Normal file
186
pkg/dbc/models/dbc_version.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"fiskerinc.com/modules/common"
|
||||
"fiskerinc.com/modules/digitaltwin"
|
||||
"fiskerinc.com/modules/grpc/kafka_grpc"
|
||||
|
||||
can "github.com/Fisker-Inc/project-ai-can-go"
|
||||
"github.com/Fisker-Inc/project-ai-can-go/pkg/descriptor"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type DBCVersionInterface interface {
|
||||
AddMsg(msg CANMessageInterface) DBCVersionInterface
|
||||
DecodeMessage(msg *kafka_grpc.GRPC_CANFrame) ([]descriptor.DecodedSignal, error)
|
||||
GenerateCANSignals(vin string, msg *kafka_grpc.GRPC_CANFrame) ([]common.CANSignal, error)
|
||||
GetActiveDiagnosticFlags(vin string, msg *kafka_grpc.GRPC_CANFrame) ([]common.CANSignal, bool, error)
|
||||
SetDiagnosticFlags(flags map[int]map[string]float64) DBCVersionInterface
|
||||
ParseState(id int, keyvaluesOut map[string]interface{}, vin string, timestampUSec int, incomingSignals []common.CANSignal, cached digitaltwin.DigitalTwinCacheInterface) error
|
||||
GetDatabase() *descriptor.Database
|
||||
Hash() string
|
||||
}
|
||||
|
||||
func NewDBCVersion(dbc *descriptor.Database, hash string) DBCVersionInterface {
|
||||
if len(hash) < 3 {
|
||||
panic("NewDBCVersion hash cannot be less than 3 characters")
|
||||
}
|
||||
|
||||
return &DBCVersion{
|
||||
dbc: dbc,
|
||||
hash: hash,
|
||||
}
|
||||
}
|
||||
|
||||
type DBCVersion struct {
|
||||
state map[int]CANMessageInterface
|
||||
dbc *descriptor.Database
|
||||
diagnosticFlags map[int]map[string]float64
|
||||
hash string
|
||||
}
|
||||
|
||||
func (d *DBCVersion) AddMsg(msg CANMessageInterface) DBCVersionInterface {
|
||||
m := d.getMsgMap()
|
||||
if _, ok := m[msg.GetID()]; ok {
|
||||
panic(fmt.Sprintf("CAN message %d already exists", msg.GetID()))
|
||||
}
|
||||
|
||||
m[msg.GetID()] = msg
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DBCVersion) getMsgMap() map[int]CANMessageInterface {
|
||||
if d.state == nil {
|
||||
d.state = map[int]CANMessageInterface{}
|
||||
}
|
||||
|
||||
return d.state
|
||||
}
|
||||
|
||||
func (d *DBCVersion) ParseState(id int, keyvaluesOut map[string]interface{}, vin string, timestampUSec int, incomingSignals []common.CANSignal, cached digitaltwin.DigitalTwinCacheInterface) error {
|
||||
m := d.getMsgMap()
|
||||
var msg CANMessageInterface
|
||||
var ok bool
|
||||
|
||||
if msg, ok = m[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if i := len(incomingSignals); i != msg.GetLength() {
|
||||
return IncorrectSignalsLength(id, msg.GetLength(), i)
|
||||
}
|
||||
|
||||
err := msg.ParseState(keyvaluesOut, vin, timestampUSec, incomingSignals, cached)
|
||||
|
||||
// TODO run options here
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *DBCVersion) GenerateCANSignals(vin string, msg *kafka_grpc.GRPC_CANFrame) ([]common.CANSignal, error) {
|
||||
var signals []common.CANSignal
|
||||
|
||||
decodedSignals, err := d.DecodeMessage(msg)
|
||||
if err != nil {
|
||||
return signals, err
|
||||
}
|
||||
|
||||
for _, signal := range decodedSignals {
|
||||
signals = append(signals, common.CANSignal{
|
||||
VIN: vin,
|
||||
Timestamp: float64(msg.Epoch) * math.Pow(10, -6),
|
||||
ID: int(msg.ID),
|
||||
Name: signal.Signal.Name,
|
||||
Value: signal.Value,
|
||||
})
|
||||
}
|
||||
|
||||
return signals, nil
|
||||
}
|
||||
|
||||
func (d *DBCVersion) DecodeMessage(msg *kafka_grpc.GRPC_CANFrame) ([]descriptor.DecodedSignal, error) {
|
||||
var decodedSignals []descriptor.DecodedSignal
|
||||
|
||||
if msg.ID >= 2048 || msg.ID < 0 {
|
||||
if GetInvalidCANIDCache().Exists(d.hash, msg.ID) {
|
||||
return decodedSignals, nil
|
||||
}
|
||||
return decodedSignals, errors.Errorf("message id %v out of bounds", msg.ID)
|
||||
}
|
||||
|
||||
message, ok := d.dbc.Message(uint32(msg.ID))
|
||||
if !ok {
|
||||
if GetInvalidCANIDCache().Exists(d.hash, msg.ID) {
|
||||
return decodedSignals, nil
|
||||
}
|
||||
|
||||
return decodedSignals, errors.Errorf(
|
||||
"message id %v not found in %s, version: %s",
|
||||
msg.ID, d.dbc.SourceFile, d.hash)
|
||||
}
|
||||
|
||||
strippedData := strings.TrimRight(string(msg.Value), "=")
|
||||
data, err := base64.RawStdEncoding.DecodeString(strippedData)
|
||||
if err != nil {
|
||||
return decodedSignals, errors.WithStack(err)
|
||||
}
|
||||
|
||||
p := can.Payload{Data: data}
|
||||
decodedSignals = message.Decode(&p)
|
||||
return decodedSignals, nil
|
||||
}
|
||||
|
||||
func (d *DBCVersion) GetActiveDiagnosticFlags(vin string, msg *kafka_grpc.GRPC_CANFrame) ([]common.CANSignal, bool, error) {
|
||||
var flags []common.CANSignal
|
||||
|
||||
diagnosticSignals, ok := d.diagnosticFlags[int(msg.ID)]
|
||||
if !ok {
|
||||
return flags, false, nil
|
||||
}
|
||||
|
||||
decodedSignals, err := d.DecodeMessage(msg)
|
||||
if err != nil {
|
||||
return flags, false, err
|
||||
}
|
||||
|
||||
flags = make([]common.CANSignal, 0)
|
||||
for _, signal := range decodedSignals {
|
||||
faultVal, ok := diagnosticSignals[signal.Signal.Name]
|
||||
|
||||
if !ok {
|
||||
continue
|
||||
} else if signal.Value != faultVal {
|
||||
continue
|
||||
}
|
||||
|
||||
flags = append(flags, common.CANSignal{
|
||||
VIN: vin,
|
||||
Timestamp: float64(msg.Epoch) * math.Pow(10, -6),
|
||||
ID: int(msg.ID),
|
||||
Name: signal.Signal.Name,
|
||||
Value: signal.Value,
|
||||
})
|
||||
}
|
||||
|
||||
return flags, len(flags) != 0, nil
|
||||
}
|
||||
|
||||
func (d *DBCVersion) Hash() string {
|
||||
return d.hash
|
||||
}
|
||||
|
||||
// TODO this should be replaced by generated diagnostic alerts from the DBC
|
||||
func (d *DBCVersion) SetDiagnosticFlags(flags map[int]map[string]float64) DBCVersionInterface {
|
||||
d.diagnosticFlags = flags
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DBCVersion) GetDatabase() *descriptor.Database {
|
||||
return d.dbc
|
||||
}
|
||||
Reference in New Issue
Block a user