package can import ( "fmt" "os" "sync" "github.com/evilsocket/islazy/str" "go.einride.tech/can/pkg/descriptor" ) type DBC struct { sync.RWMutex path string db *descriptor.Database } func (dbc *DBC) Loaded() bool { dbc.RLock() defer dbc.RUnlock() return dbc.db != nil } func (dbc *DBC) LoadFile(mod *CANModule, path string) error { input, err := os.ReadFile(path) if err != nil { return fmt.Errorf("can't read %s: %v", path, err) } return dbc.LoadData(mod, path, input) } func (dbc *DBC) LoadData(mod *CANModule, name string, input []byte) error { dbc.Lock() defer dbc.Unlock() mod.Debug("compiling %s ...", name) result, err := dbcCompile(name, input) if err != nil { return fmt.Errorf("can't compile %s: %v", name, err) } for _, warning := range result.Warnings { mod.Warning("%v", warning) } dbc.path = name dbc.db = result.Database mod.Info("%s loaded", name) return nil } func (dbc *DBC) Parse(mod *CANModule, msg *Message) bool { dbc.RLock() defer dbc.RUnlock() // did we load any DBC database? if dbc.db == nil { return false } // if the database contains this message id if message, found := dbc.db.Message(msg.Frame.ID); found { msg.Name = message.Name // find source full info in DBC nodes sourceName := message.SenderNode sourceDesc := "" if sender, found := dbc.db.Node(message.SenderNode); found { sourceName = sender.Name sourceDesc = sender.Description } // add CAN source if new _, msg.Source = mod.Session.CAN.AddIfNew(sourceName, sourceDesc, msg.Frame.Data[:]) // parse signals for _, signal := range message.Signals { var value string if signal.Length <= 32 && signal.IsFloat { value = fmt.Sprintf("%f", signal.UnmarshalFloat(msg.Frame.Data)) } else if signal.Length == 1 { value = fmt.Sprintf("%v", signal.UnmarshalBool(msg.Frame.Data)) } else if signal.IsSigned { value = fmt.Sprintf("%d", signal.UnmarshalSigned(msg.Frame.Data)) } else { value = fmt.Sprintf("%d", signal.UnmarshalUnsigned(msg.Frame.Data)) } msg.Signals[signal.Name] = str.Trim(fmt.Sprintf("%s %s", value, signal.Unit)) } return true } return false } func (dbc *DBC) MessagesBySender(senderId string) []*descriptor.Message { dbc.RLock() defer dbc.RUnlock() fromSender := make([]*descriptor.Message, 0) if dbc.db == nil { return fromSender } for _, msg := range dbc.db.Messages { if msg.SenderNode == senderId { fromSender = append(fromSender, msg) } } return fromSender } func (dbc *DBC) MessageById(frameID uint32) *descriptor.Message { dbc.RLock() defer dbc.RUnlock() if dbc.db == nil { return nil } if message, found := dbc.db.Message(frameID); found { return message } return nil } func (dbc *DBC) Messages() []*descriptor.Message { dbc.RLock() defer dbc.RUnlock() if dbc.db == nil { return nil } return dbc.db.Messages } func (dbc *DBC) AvailableMessages() []string { avail := []string{} for _, msg := range dbc.Messages() { avail = append(avail, fmt.Sprintf("%d (%s)", msg.ID, msg.Name)) } return avail } func (dbc *DBC) Senders() []string { dbc.RLock() defer dbc.RUnlock() senders := make([]string, 0) if dbc.db == nil { return senders } uniq := make(map[string]bool) for _, msg := range dbc.db.Messages { uniq[msg.SenderNode] = true } for sender, _ := range uniq { senders = append(senders, sender) } return senders }