gocanopen is an implementation of the CANopen protocol (CiA 301) written in pure golang. It aims to be simple and efficient. This package can be used for master usage but also supports creating regular CANopen nodes.
All the main components of CiA 301 are supported, these include :
- SDO server/client
- NMT master/slave
- HB producer/consumer
- TPDO/RPDO
- EMERGENCY producer/consumer
- SYNC producer/consumer
- TIME producer/consumer
Partial support also exists for CiA 309, specifically :
- HTTP gateway
gocanopen does not require the use of an external tool to generate some source code from an EDS file. EDS files can be loaded dynamically from disk to create local nodes with default supported objects. The library comes with a default embedded EDS file, which can be used when creating nodes.
Currently this package supports the following transceivers:
- socketcan
- kvaser
- virtualcan here
In order to use kvaser, canlib should be downloaded & installed. Specific compile flags are needed :
- CFLAGS: -g -Wall -I/path_to_kvaser/canlib/include
- LDFLAGS: -L/path_to_kvaser/canlib
More transceivers can be added by creating your own driver and implementing the following interface :
type Bus interface {
Connect(...any) error // Connect to the actual bus
Disconnect() error // Disconnect from bus
Send(frame Frame) error // Send a frame on the bus
Subscribe(callback FrameListener) error // Subscribe to all can frames
}
Feel free to contribute to add specific drivers, we will find a way to integrate them in this repo.
This repo contains two implementation examples : socketcan.go
, and virtual.go
used for testing.
Examples can be found in /examples
Basic setup example :
package main
import (
"fmt"
"github.com/samsamfire/gocanopen/pkg/network"
"github.com/samsamfire/gocanopen/pkg/od"
)
func main() {
network := network.NewNetwork(nil)
err := network.Connect("socketcan", "can0", 500_000)
if err != nil {
panic(err)
}
defer network.Disconnect()
// Add a remote node to the network, either by providing an EDS file
// Or downloading from the node. We use here a default OD available with the library
node, err := network.AddRemoteNode(0x10, od.Default())
if err != nil {
panic(err)
}
// Read standard entry containing device name (0x1008)
value, err := node.Configurator().ReadManufacturerDeviceName()
if err != nil {
fmt.Printf("error reading node %v device name : %v\n", node.GetID(), err)
} else {
fmt.Printf("node %v device name is %v\n", node.GetID(), value)
}
// Perform a network scan to detect other nodes...
res, err := network.Scan(1000)
if err != nil {
panic(err)
}
fmt.Println("scanned the following nodes : ", res)
}
- Improve documentation & examples
- More testing
- API improvements
Testing is done :
- With unit testing
- Testing against an other implementation in python
Tests are done with virtualcan
server, which can be used easily with github actions.
More tests are always welcome if you believe that some part of the spec is not properly tested.
For running tests, install the required packages pip install -r ./tests/requirements.txt
Run the tests with : pytest -v
The application uses slog for logging. Example logger setup with Debug level :
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
network := network.NewNetwork(nil)
network.SetLogger(logger)