# :electric_plug: CAN Go

[![PkgGoDev][pkg-badge]][pkg]
[![GoReportCard][report-badge]][report]
[![Codecov][codecov-badge]][codecov]

[pkg-badge]: https://pkg.go.dev/badge/github.com/Fisker-Inc/project-ai-can-go
[pkg]: https://pkg.go.dev/github.com/Fisker-Inc/project-ai-can-go
[report-badge]: https://goreportcard.com/badge/github.com/Fisker-Inc/project-ai-can-go
[report]: https://goreportcard.com/report/github.com/Fisker-Inc/project-ai-can-go
[codecov-badge]: https://codecov.io/gh/einride/can-go/branch/master/graph/badge.svg
[codecov]: https://codecov.io/gh/einride/can-go

CAN toolkit for Go programmers.

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

[socketcan]: https://www.kernel.org/doc/Documentation/networking/can.txt

## 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`.

3. There will still be leftover Chinese characters in the `.dbc` file, I chose to just remove them.
4. 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`

```go
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.

```go
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.

```go
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:

```go
// 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:

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

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

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

```
