einride/can-go

question on DBC file parsing

samsamfire opened this issue · 2 comments

Hi,
I was looking for a go package that could parse DBC files and I stumbled upon this package.
In the docs I can see that it's possible to generate some go code from a DBC file, which sounds great but I am looking for a way for parsing some can data & converting it via a DBC to a human readable format.
The purpose of this would be to create a telegraf plugin to parse raw can data and converting it for visualizations & logging.

It seems that the parsed DBC data is inside a []Defs slice, ideally it would be great to have some sort of map for directly converting CAN IDs, I don't know if this is possible in this implementation ?

Thanks a lot !

Hi @samsamfire,

If I understand you correctly, you have binary CAN data which you want to convert to a human readable format using a DBC file. Using this library you do it in two steps:

  1. Parse your binary CAN data into can.Frame structs.
  2. Use the generated go code from the DBC file to parse the can.Frame structs into DBC messages.

The generated go code that you get when using a DBC file contains functions for unmarshalling CAN frames to DBC messages. The prerequisite is that you have parsed your binary CAN frames into can.Frame structs. If you can do that, then you can use the (md *MessageDescriptor) UnmarshalFrame(f can.Frame) function generated from the DBC file to convert a CAN frame to a message in the DBC, which automatically converts to the correct type based on ID. Take a look inside the testdata folder in this repo, where you can see an example DBC and its generated code. For reference, here's the can.Frame struct and the UnmarshalFrame that I'm talking about. I hope this helps 🙂

type Frame struct {
	// ID is the CAN ID
	ID uint32
	// Length is the number of bytes of data in the frame.
	Length uint8
	// Data is the frame data.
	Data Data
	// IsRemote is true for remote frames.
	IsRemote bool
	// IsExtended is true for extended frames, i.e. frames with 29-bit IDs.
	IsExtended bool
}
// UnmarshalFrame unmarshals the provided example CAN frame.
func (md *MessagesDescriptor) UnmarshalFrame(f can.Frame) (generated.Message, error) {
	switch f.ID {
	case md.EmptyMessage.ID:
		var msg EmptyMessage
		if err := msg.UnmarshalFrame(f); err != nil {
			return nil, fmt.Errorf("unmarshal example frame: %w", err)
		}
		return &msg, nil
	case md.DriverHeartbeat.ID:
		var msg DriverHeartbeat
		if err := msg.UnmarshalFrame(f); err != nil {
			return nil, fmt.Errorf("unmarshal example frame: %w", err)
		}
		return &msg, nil
	case md.MotorCommand.ID:
		var msg MotorCommand
		if err := msg.UnmarshalFrame(f); err != nil {
			return nil, fmt.Errorf("unmarshal example frame: %w", err)
		}
		return &msg, nil
	...
        ...
        ...
	default:
		return nil, fmt.Errorf("unmarshal example frame: ID not in database: %d", f.ID)
	}
}