Python API for an Open Source USB to CAN-BUS Interface. Can4Python offers a bunch of functionalities in order to send and receive CAN-Messages. This implementation uses a Teensy4.0 Board, connected to a MCP2562FD CAN FD transreceiver at CAN3 on the hardware side, as well as the FlexCAN_T4 library on the software side. In theory also other Controllers could be used with little changes in the main *.ino file, if they are Arduino compatible and offer a CAN-Bus interface.
- Visual Studio 2017 or later with the workloads mentioned in this article
- Boost 1.65.0 and environment variables BOOST_ROOT and BOOST_LIBRARYDIR set
- Visual C++ 2015.3 v140 toolset installed (via Visual Studio installer → Modify / Individual Components)
Image sources: PJRC and Microchip
Can4Python uses the Teensy RawHID interface for the USB Communication. In order to send USB packets with a size of 255 Bytes modify the file %ARDUINO_IDE_INSTALLDIR%\hardware\teensy\avr\cores\teensy4\usb_desc.h accordingly:
...
#elif defined(USB_RAWHID)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0486
#define RAWHID_USAGE_PAGE 0xFFAB // recommended: 0xFF00 to 0xFFFF
#define RAWHID_USAGE 0x0200 // recommended: 0x0100 to 0xFFFF
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y','d','u','i','n','o',' ','R','a','w','H','I','D'}
#define PRODUCT_NAME_LEN 18
#define EP0_SIZE 64 /* Original: 64 */
#define NUM_ENDPOINTS 4
#define NUM_USB_BUFFERS 30 /* Original: 12 */
#define NUM_INTERFACE 2 /* Original: 2 */
#define RAWHID_INTERFACE 0 // RawHID
#define RAWHID_TX_ENDPOINT 3 /* Original: 3 */
#define RAWHID_TX_SIZE 255 /* Original: 64*/
#define RAWHID_TX_INTERVAL 1 // TODO: is this ok for 480 Mbit speed
#define RAWHID_RX_ENDPOINT 4
#define RAWHID_RX_SIZE 255 /* Original: 64*/
#define RAWHID_RX_INTERVAL 1 // TODO: is this ok for 480 Mbit speed
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 2
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1 // TODO: is this ok for 480 Mbit speed
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2 // TODO: is this ok for 480 Mbit speed
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_INTERRUPT + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_INTERRUPT /*ENDPOINT_RECEIVE_UNUSED + ENDPOINT_TRANSMIT_INTERRUPT*/
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_INTERRUPT /*ENDPOINT_RECEIVE_INTERRUPT + ENDPOINT_TRANSMIT_UNUSED*/
...
- Run the script init-repo.sh
- Open the file Teensy40.ino with the Arduino Teensy IDE
- Compile and Flash
In order to globally install the Can4Python package, navigate into the CanInterface Folder and run python -m pip install .
in an elevated console.
from Can4Python import CanInterface
import time
can = CanInterface()
can.OpenCan20(0, 500000, False)
can.AddReceiveHandler(0, can.IdentifierFlags.STANDARD_11BIT)
can.StartReceiving(0)
can.SendCanMessage(0, 0x7e0, [0x02, 0x3e, 0x00], 0)
time.sleep(0.5)
resp = can.GetCanMessage(0)
for b in resp['payload']: print(b)
can.CloseCan(0)
Provided functions:
Function | Parameters | Return value | Description |
---|---|---|---|
CanInterface() | - | Class instance | Constructor for CanInterface class |
GetDeviceCount() | - | (int) Number of connected Devices | Get the number of connected USB to CAN Devices |
EnableTransreceiver(devIndex) | (int) devIndex: Index of device | (bool) Success | Enables the CAN transreceiver |
DisableTransreceiver(devIndex) | (int) devIndex: Index of device | (bool) Success | Disables the CAN transreceiver |
OpenCan20(devIndex, baudrate, listenOnly) |
(int) devIndex: Index of device (int) baudrate: CAN Baudrate (bool) listenOnly: Listen only mode |
(bool) Success | Opens the CAN Device with CAN 2.0 settings |
OpenCanFD(devIndex, arbitrationBaudrate, dataBaudrate, listenOnly, samplePoint, propDelay, busLength) |
(int) devIndex: Index of device (int) arbitrationBaudrate: Arbitration Baudrate (int) dataBaudrate: Data Baudrate (bool) listenOnly: Listen only mode (float) samplePoint: Sample Point setting (float) propDelay: Bus propagation delay (float) busLength: Bus length |
(bool) Success | Opens the CAN Device with CAN FD settings |
CloseCan(devIndex) | (int) devIndex: Index of device | (bool) Success | Closes CAN communication |
StartReceiving(devIndex) | (int) devIndex: Index of device | - | Start receiving CAN Messages with device |
StopReceiving(devIndex) | (int) devIndex: Index of device | - | Stop receiving CAN Messages with device |
SendCanMessage(devIndex, messageId, payload, messageFlags) |
(int) devIndex: Index of device (int) messageId: CAN arbitration Identifier (array) payload: Payload (int) messageFlags: Message flags for enabling Bitrate Switch, Extended Datalength or Extended Identifier |
(bool) Success | Send CAN Messages with device |
SendCanMessageAsync(devIndex, messageId, payload, messageFlags) |
(int) devIndex: Index of device (int) messageId: CAN arbitration Identifier (array) payload: Payload (int) messageFlags: Message flags for enabling Bitrate Switch, Extended Datalength or Extended Identifier |
(bool) Success | Send CAN Messages with device asynchronly |
GetCanMessage(devIndex) | (int) devIndex: Index of device | (dict {"identifier": ..., "payload": ..., "messageFlags": ..., "timestamp": ...}) Received CAN Message or empty object | Get one CAN Message from the receive Buffer |
AddReceiveHandler(devIndex, messageId, identifierFlags) |
(int) devIndex: Index of device (int) messageId: CAN arbitration Identifier (int) identifierFlags: Identifier flags |
(int) Handler ID | Adds an receive handler on the device which takes CAN Messages with the given Identifier and Message Flags (e.g. only 11Bit) |
AddReceiveHandler(devIndex, lowerMessageId, higherMessageId, identifierFlags) |
(int) devIndex: Index of device (int) lowerMessageId: Lower CAN arbitration Identifier (int) higherMessageId: Higher CAN arbitration Identifier (int) identifierFlags: Identifier flags |
(int) Handler ID | Adds an receive handler on the device which takes CAN Messages with the given Identifier range and Message Flags (e.g. only 11Bit) |
AddReceiveHandler(devIndex, identifierFlags) |
(int) devIndex: Index of device (int) identifierFlags: Identifier flags |
(int) Handler ID | Adds an receive handler on the device which takes all CAN Message with the given Identifier Flags (e.g. only 11Bit) |
RemoveReceiveHandler(devIndex, handlerId = -1) |
(int) devIndex: Index of device (int, optional) handlerId: Receive Handler ID |
(bool) Success | Removes the receive handler specified with the ID or all if -1 is used as ID |
IdentifierFlags values:
- STANDARD_11BIT
- EXTENDED_29BIT
MessageFlags values:
- USE_EDL
- USE_BRS
- USE_EXT