Files
cloud-services/pkg/can-go/README.md

5.6 KiB

🔌 CAN Go

PkgGoDev GoReportCard Codecov

CAN toolkit for Go programmers.

can-go makes use of the Linux SocketCAN abstraction for CAN communication. (See the SocketCAN documentation for more details).

Modifications to the Original Repo

Original repo: https://github.com/jshiv/can-go/tree/623b1140d54a845026249a5bbbaf23f44c614173.

Comment out the value descriptor generation code within can-go/internal/generate/file.go, lines 128-141. This code creates compile errors due to duplicate values within the .dbc file provided.

DBC Go Code Library Generation

  1. Place .dbc file into orig/ folder.
  2. Run scripts/main.go:
go run scripts/main.go

This will translate all Chinese variable values within the file to English. Any non-alphanumeric characters are also removed. NOTE The default read file is labelled orig/121-N60AB_ADASBUS_Matrix_CANFD_V2.3.dbc and the default write file is labelled dbc/n60.dbc.

  1. There will still be leftover Chinese characters in the .dbc file, I chose to just remove them.
  2. Generate Go code from cleaned .dbc file:
can-go> go run cmd/cantool/main.go generate data/dbc dbc

Examples

Decoding CAN messages

Decoding CAN messages from byte arrays can be done using can.Payload

func main() {
    // DBC file
    var dbcFile = []byte(`
    VERSION ""
    NS_ :
    BS_:
    BU_: DBG DRIVER IO MOTOR SENSOR

    BO_ 1530 DisconnectState: 14 MOTOR
     SG_ LockCountRearRight : 91|20@0+ (1,0) [0|1048575] ""  IO
     SG_ DisconnectStateRearRight : 95|4@0+ (1,0) [0|5] ""  IO
     SG_ CurrentRearRight : 79|16@0+ (1,0) [0|65535] ""  IO
     SG_ DisconnectStateRearRightTarget : 64|1@0+ (1,0) [0|1] ""  IO
     SG_ TargetSpeedRearRight : 63|15@0+ (0.125,-2048) [-2048|2047.875] "rad/s"  IO
     SG_ LockCountRearLeft : 35|20@0+ (1,0) [0|1048575] ""  IO
     SG_ DisconnectStateRearLeft : 39|4@0+ (1,0) [0|5] ""  IO
     SG_ CurrentRearLeft : 23|16@0+ (1,0) [0|65535] ""  IO
     SG_ DisconnectStateRearLeftTarget : 8|1@0+ (1,0) [0|1] ""  IO
     SG_ TargetSpeedRearLeft : 7|15@0+ (0.125,-2048) [-2048|2047.875] "rad/s"  IO

    VAL_ 1530 DisconnectStateRearRight 0 "Undefined" 1 "Locked" 2 "Unlocked" 3 "Locking" 4 "Unlocking" 5 "Faulted" ;
    VAL_ 1530 DisconnectStateRearLeft 0 "Undefined" 1 "Locked" 2 "Unlocked" 3 "Locking" 4 "Unlocking" 5 "Faulted" ;
    `)

    // Create payload from hex string
    byteStringHex := "8000000420061880000005200600"
    p, _ := can.PayloadFromHex(byteStringHex)

    // Load example dbc file
    c, _ := generate.Compile("test.dbc", dbcFile)
    db := *c.Database

    // Decode message frame ID 1530
    message, _ := db.Message(uint32(1530))
    decodedSignals := message.Decode(&p)
    for _, signal := range decodedSignals {
        fmt.Printf("Signal: %s, Value: %f, Description: %s\n", signal.Signal.Name, signal.Value, signal.Description)
    }
}
Signal: TargetSpeedRearLeft, Value: 0.000000, Description:
Signal: DisconnectStateRearLeftTarget, Value: 0.000000, Description:
Signal: CurrentRearLeft, Value: 4.000000, Description:
Signal: LockCountRearLeft, Value: 1560.000000, Description:
Signal: DisconnectStateRearLeft, Value: 2.000000, Description: Unlocked
Signal: TargetSpeedRearRight, Value: 0.000000, Description:
Signal: DisconnectStateRearRightTarget, Value: 0.000000, Description:
Signal: CurrentRearRight, Value: 5.000000, Description:
Signal: LockCountRearRight, Value: 1536.000000, Description:
Signal: DisconnectStateRearRight, Value: 2.000000, Description: Unlocked

Receiving CAN frames

Receiving CAN frames from a socketcan interface.

func main() {
    // Error handling omitted to keep example simple
    conn, _ := socketcan.DialContext(context.Background(), "can", "can0")

    recv := socketcan.NewReceiver(conn)
    for recv.Receive() {
        frame := recv.Frame()
        fmt.Println(frame.String())
    }
}

Sending CAN frames/messages

Sending CAN frames to a socketcan interface.

func main() {
	// Error handling omitted to keep example simple

	conn, _ := socketcan.DialContext(context.Background(), "can", "can0")

	frame := can.Frame{}
	tx := socketcan.NewTransmitter(conn)
    _ = tx.TransmitFrame(context.Background(), frame)
}

Generating Go code from a DBC file

It is possible to generate Go code from a .dbc file.

$ go run github.com/Fisker-Inc/project-ai-can-go/cmd/cantool generate <dbc file root folder> <output folder>

In order to generate Go code that makes sense, we currently perform some validations when parsing the DBC file so there may need to be some changes on the DBC file to make it work

After generating Go code we can marshal a message to a frame:

// import etruckcan "github.com/myproject/myrepo/gen"

auxMsg := etruckcan.NewAuxiliary().SetHeadLights(etruckcan.Auxiliary_HeadLights_LowBeam)
frame := auxMsg.Frame()

Or unmarshal a frame to a message:

// import etruckcan "github.com/myproject/myrepo/gen"

// Error handling omitted for simplicity
_ := recv.Receive()
frame := recv.Frame()

var auxMsg *etruckcan.Auxiliary
_ = auxMsg.UnmarshalFrame(frame)