Skip to content

Python API for an Open Source USB to CAN-BUS Interface.

License

Notifications You must be signed in to change notification settings

dstuemk/Can4Python

Repository files navigation

Can4Python

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.

Prerequisites

  • 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)

Example Wiring

Wiring Image sources: PJRC and Microchip

Prepare Hardware

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*/ 
...
  1. Run the script init-repo.sh
  2. Open the file Teensy40.ino with the Arduino Teensy IDE
  3. Compile and Flash

Install the Python package

In order to globally install the Can4Python package, navigate into the CanInterface Folder and run python -m pip install . in an elevated console.

Example Script

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)

CanInterface Documentation

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

Releases

No releases published

Packages

No packages published

Languages