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

159 lines
4.2 KiB
Go

package dbc
import (
"encoding/base64"
"math"
"strings"
"fiskerinc.com/modules/common"
"fiskerinc.com/modules/dbc/diagnostics"
"fiskerinc.com/modules/dbc/state"
"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"
)
func NewDBC(d *descriptor.Database, f diagnostics.Flags, s map[int]state.StateFunc) DBCInterface {
return &DBC{database: d, diagnosticFlags: f, stateFuncs: s}
}
type DBCInterface interface {
GetActiveDiagnosticFlags(vin string, msg *kafka_grpc.GRPC_CANFrame) ([]common.CANSignal, bool, error)
GetStateFunc(id int) (state.StateFunc, bool)
GenerateCANSignals(vin string, msg *kafka_grpc.GRPC_CANFrame) ([]common.CANSignal, error)
GenerateCANSignalsMap(vin string, msg *kafka_grpc.GRPC_CANFrame) (map[string]common.CANSignal, error)
DecodeMessage(msg *kafka_grpc.GRPC_CANFrame) ([]descriptor.DecodedSignal, error)
GetDBCHash() string
SetDBCHash(string)
GetDatabase() *descriptor.Database
}
type DBC struct {
database *descriptor.Database
hash string
diagnosticFlags diagnostics.Flags
stateFuncs map[int]state.StateFunc
}
func (d *DBC) GetStateFunc(id int) (state.StateFunc, bool) {
f, ok := d.stateFuncs[id]
return f, ok
}
// GenerateCANSignals parses raw can bus message (encoded in base64) to ECU data
func (d *DBC) GenerateCANSignals(vin string, msg *kafka_grpc.GRPC_CANFrame) ([]common.CANSignal, error) {
decodedSignals, err := d.DecodeMessage(msg)
if err != nil {
return nil, err
}
signals := make([]common.CANSignal, 0, len(decodedSignals))
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
}
// GenerateCANSignalSets parses raw can bus message (encoded in base64) to ECU
func (d *DBC) GenerateCANSignalsMap(vin string, msg *kafka_grpc.GRPC_CANFrame) (map[string]common.CANSignal, error) {
var signals map[string]common.CANSignal
decodedSignals, err := d.DecodeMessage(msg)
if err != nil {
return signals, err
}
signals = make(map[string]common.CANSignal, len(decodedSignals))
for _, signal := range decodedSignals {
signals[signal.Signal.Name] = 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 *DBC) 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 *DBC) DecodeMessage(msg *kafka_grpc.GRPC_CANFrame) ([]descriptor.DecodedSignal, error) {
var decodedSignals []descriptor.DecodedSignal
if msg.ID >= 2048 || msg.ID < 0 {
return decodedSignals, errors.Errorf("message id %v out of bounds", msg.ID)
}
message, ok := d.database.Message(uint32(msg.ID))
if !ok {
return decodedSignals, errors.Errorf(
"message id %v not found in %s, version: %s",
msg.ID, d.database.SourceFile, d.database.Version)
}
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 *DBC) GetDBCHash() string {
return d.hash
}
func (d *DBC) GetDatabase() *descriptor.Database {
return d.database
}
func (d *DBC) SetDBCHash(hash string) {
d.hash = hash
}