NodeJS SocketCAN Module
This module provides a NodeJS interface to the SocketCAN driver for Linux.
This module is meant to serve as a drop-in replacement for can-usb-com
, allowing a SocketCAN-compatible adapter to be used in place of GridConnect CAN-USB-COM.
This module was developed to be used with Copperhill Technologies' PiCAN2 hat for the Raspberry Pi.
This is also compatible with Kvaser CAN adapters that are supported by the kvaser_usb
Linux kernel module. This is typically available out of the box in desktop Linux distributions such as Ubuntu, but must be built separately in Raspbian / Raspberry Pi OS. A script is included to perform this task automatically; see the relevant section below for more information.
Getting Started
The following assumes that NodeJS is already installed. This module was developed using Node v12.18.4 for Raspberry Pi OS (Debian GNU/Linux) 10.6.
To install this module, run:
npm install @csllc/cs-socketcan
The following is a sample script that opens the CAN port, writes a single message to the bus, and listens for and prints received messages from the bus.
const Can = require('@csllc\cs-socketcan');
let board = new Can({
canRate: 250000,
});
board.list()
.then(function(ports) {
board.on('write', function(msg) {
console.log('Write: ', msg);
});
board.on('data', function(msg) {
console.log('Msg: ', msg.id.toString(16), msg.buf);
});
console.log('opening ', ports[0].path);
return board.open(ports[0].path);
})
.then(function() {
board.write({ id: 0x10EF8001, ext: true, buf: Buffer.from([0x45, 0x00, 0x00, 0x04, 0x00, 0x00]) });
})
.catch(function(err) {
// Something went wrong...
console.error(err);
board.close();
process.exit(-1);
});
Examples
JavaScript examples are available in the examples
folder.
Configuration
The constructor accepts an object that specifies the desired configuration. The CAN adapter is set up before the open
method resolves, so once it is complete, the CAN interface is ready for use.
The default options are shown in the following example. Any of them may be omitted from the constructor's option object to use their default value.
let can = new Can({
// bit rate on the CAN bus
canRate: 250000,
// useful for testing, each sent packet is also received
loopback: false,
});
Streaming
cs-socketcan
extends the NodeJS stream interface, so it can be piped into other stream instances.
Filtering
cs-socketcan
does not currently support message filtering.
JavaScript Events
The module emits the following events:
-
open
when the serial port is successfully opened -
error
if an error occurs -
data
when an incoming CAN bus frame is received -
write
when an outgoing CAN bus frame is sent to the device (the event is emitted before the frame is actually sent on the bus) -
close
when the port is closed
To listen for the events, use the typical NodeJS EventEmitter pattern:
can.on('open', function(){
console.log( 'CAN bus opened');
})
can.on('data', function(msg){
console.log( msg );
})
can.on('close', function(err){
if( err && err.disconnected ) {
console.log( 'CAN bus disconnected' );
}
else {
console.log( 'CAN bus closed by application' );
}
})
can.on('error', function(err){
console.log( 'CAN bus error: ', err );
})
API
This module's API functions generally return Promises, which are resolved or rejected when a request is complete.
Refer to the documentation on Promises for details on how to chain requests together, detect errors, etc.
Refer to the socketcan
and node-can
documentation for more information on the components used in this module.
Using Kvaser Adapters on Rasbperry Pi
SocketCAN works with Kvaser CAN adapters that are supported by the kvaser_usb
Linux kernel module. This module is not part of the Raspberry Pi OS (formerly Raspbian) Linux distribution, but can be built from source and installed separately.
The whole build and install process can be performed by running the script:
$ /path/to/node-modules/@csllc/cs-socketcan/tools/rpi-kvaser-usb.sh
This script identifies the currently running Raspberry Pi firmware and kernel versions, retrieves the corresponding kernel source archive, builds the kernel with kvaser_usb
as a dynamically loaded module, and installs and loads the module. The last steps are run with sudo
to elevate priveleges, and will prompt for a password.
Currently the script rebuilds the entire kernel, and not simply the missing module alone. This requires approximately 2 GB of free space and takes about 4 hours to complete on a Raspberry Pi 3 Model B.
The script can be run with a mounted external drive as its working directory if free space on the SD card isn't sufficient.
Development
Before updating or modifying this package, please
- Lint any changes using
eslint
. - Confirm that unit tests pass, noting the exceptions described in the next section.
In order to run unit tests (npm test
), at least one PCAN-USB device must be connected to the computer.
The pingpong
test is currently configured to use cs-socketcan
for one adapter, and can-usb-com
for the other. These must be connected via a properly terminated bus.
Do not run any tests on a bus with active traffic, since receiving unexpected CAN packets may confuse the tests.
Functionality Limitations
- No hardware loopback support - loopback is implemented in this module by pushing messages back into the stream in the
write()
method - This module does not implement message filtering