Version: | 2.1.3 |
---|---|
Web: | http://openxcplatform.com |
Documentation: | http://openxcplatform.com/cantranslator |
Source: | http://github.com/openxc/cantranslator |
If you’ve downloaded a pre-built binary for a specific vehicle, see the Flashing a Pre-compiled Binary section for instructions on how to flash your CAN translator. Most users do not need to set up the full development described in these docs.
Install Git from your distribution’s package manager.
Ubuntu:
$ sudo apt-get install git
Arch Linux:
$ [sudo] pacman -S git
gcc4, patchutils, git, unzip, python, python-argparse, check, curl, libsasl2, ca-certificates
$ set -o igncr && export SHELLOPTS
$ export http_proxy=<your proxy> $ export https_proxy=<your proxy>
$ git clone https://github.com/openxc/cantranslator
$ cd cantranslator $ script/bootstrap.sh
The bootstrap.sh script is tested in Cygwin, OS X Mountain Lion, Ubuntu 12.04 and Arch Linux - other operating systems may need to install the dependencies manually.
In order to build the CAN translator firmware from source, you need a few dependencies:
If instead of the chipKIT, you are compiling for the Blueboard (based on the NXP LPC1768/69), instead of MPIDE you will need:
The easiest way to install these dependencies is to use the script/bootstrap.sh script in the cantranslator repository. Run the script in Linux, Cygwin in Windows or OS X and if there are no errors you should be ready to go:
$ script/bootstrap.sh
If there are errors, continue reading in this section to install whatever piece failed manually.
Clone the repository from GitHub:
$ git clone https://github.com/openxc/cantranslator
Some of the library dependencies are included in this repository as git submodules, so before you go further run:
$ git submodule update --init
If this doesn’t print out anything or gives you an error, make sure you cloned this repository from GitHub with git and that you didn’t download a zip file. The zip file is missing all of the git metadata, so submodules will not work.
Building the source for the CAN translator for the chipKIT microcontroller requires MPIDE (the development environment and compiler toolchain for chipKIT provided by Digilent). Installing MPIDE can be a bit quirky on some platforms, so if you’re having trouble take a look at the installation guide for MPIDE.
Although we just installed MPIDE, building via the GUI is not supported. We use GNU Make to compile and upload code to the device. You still need to download and install MPIDE, as it contains the PIC32 compiler.
You need to set an environment variable (e.g. in $HOME/.bashrc) to let the project know where you installed MPIDE (make sure to change these defaults if your system is different!):
# Path to the extracted MPIDE folder (this is correct for OS X)
export MPIDE_DIR=/Applications/Mpide.app/Contents/Resources/Java
Remember that if you use export, the environment variables are only set in the terminal that you run the commands. If you want them active in all terminals (and you probably do), you need to add these export ... lines to the file ~/.bashrc (in Linux) or ~/.bash_profile (in OS X) and start a new terminal.
It also requires some libraries from Microchip that we are unfortunately unable to include or link to as a submodule from the source because of licensing issues:
You can read and accept Microchip’s license and download both libraries on the Digilent download page.
Once you’ve downloaded the .zip file, extract it into the libs directory in this project. It should look like this:
- /Users/me/projects/cantranslator/
---- libs/
-------- chipKITUSBDevice/
chipKitCAN/
... other libraries
If you’re using Mac OS X or Windows, make sure to install the FTDI driver that comes with the MPIDE download. The chipKIT uses a different FTDI chip than the Arduino, so even if you’ve used the Arduino before, you still need to install this driver.
$ pacman -S openocd
Install Homebrew. Then:
$ brew install libftdi libusb
$ brew install --enable-ft2232_libftdi openocd
Remove the Olimex sections from the FTDI kernel module, and then reload it:
$ sudo sed -i "" -e "/Olimex/{N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;d;}" /System/Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist
$ sudo kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext/
$ sudo kextload /System/Library/Extensions/FTDIUSBSerialDriver.kext/
Download the binary version of the toolchain for your platform (Linux, OS X or Windows) from this Launchpad site.
In Arch Linux you can alternatively install the gcc-arm-none-eabi package from the AUR.
The code base currently supports two embeddedd platforms - the chipKIT (based on the Microchip PIC32) and the Blueboard (based on the NXP LPC1768/69). Before you can compile, you will need to define your CAN messages.
The build process works with Linux (tested in Arch Linux and Ubuntu), OS X and Cygwin in Windows.
Note
When running make to compile, try adding the -j4 flag to build jobs in parallel - the speedup can be quite dramatic.
Once the dependencies are installed, attach the chipKIT to your computer with a mini-USB cable, cd into the src subdirectory, build and upload to the device.
$ git submodule init && git submodule update
$ make clean
$ make
$ make flash
If the flash command can’t find your chipKIT, you may need to set the SERIAL_PORT variable if the serial emulator doesn’t show up as /dev/ttyUSB* in Linux, /dev/tty.usbserial* in Mac OS X or com3 in Windows. For example, if the chipKIT shows up as /dev/ttyUSB4:
$ SERIAL_PORT=/dev/ttyUSB4 make flash
and if in Windows it appeared as COM4:
$ SERIAL_PORT=com4 make flash
If the compilation didn’t work:
If you get a lot of errors about undefined refernece to getSignals()' and other functions, you need to make sure you defined your CAN messages - read through CAN Message Definition before trying to compile.
It is possible to use an IDE like Eclipse to edit and compile the project.
If you didn’t set up the environment variables from the Installation section (e.g. MPIDE_HOME), you can also do that from within Eclipse in C/C++ project settings.
There will still be some errors in the Eclipse problem detection, e.g. it doesn’t seem to pick up on the GCC __builtin_* functions, and some of the chipKIT libraries are finicky. This won’t have an effect on the actual build process, just the error reporting.
Support for the NXP LPC17xx, an ARM Cortex M3 microcontroller, is experimental at the moment and the documentation is incomplete. We are building successfully on the NGX Blueboard 1768-H using the Olimex ARM-OCD-USB JTAG programmer.
Once the dependencies are installed, attach a JTAG adapter to your computer and the CAN translator, then compile and flash:
$ make clean
$ PLATFORM=BLUEBOARD make -j4
$ PLATFORM=BLUEBOARD make flash
The config files in this repository assume your JTAG adapter is the Olimex ARM-USB-OCD unit. If you have a different unit, change the first line in conf/flash.cfg to the correct value.
Updates to the CAN translator firmware may be distributed as pre-compiled binaries, e.g. if they are distributed by an OEM who does not wish to make the CAN signals public. If that’s the case for your vehicle, you will have a .hex file and can use the upload_hex.sh script to update your device.
git, curl, libsasl2, ca-certificates
$ echo "set -o igncr && export SHELLOPTS" >> ~/.bashrc && source ~/.bashrc
If you already have Git installed, you can skip ahead to the all platforms section
Install Git from your distribution’s package manager.
Ubuntu:
$ sudo apt-get install git
Arch Linux:
$ [sudo] pacman -S git
$ export http_proxy=<your proxy> $ export https_proxy=<your proxy>
$ git clone https://github.com/openxc/cantranslator
You need to have the mini-USB port on the chipKIT connected to your computer to upload a new firmware. This is different than the micro-USB port that you use to read vehicle data - see the device connections section of the OpenXC website to make sure you have the correct cable attached.
Open a terminal and cd into the cantranslator folder that you cloned with Git. Run the upload_hex.sh script with the .hex file you downloaded:
$ script/upload_hex.sh <firmware file you downloaded>.hex
The upload_hex.sh script attempts to install all required dependencies automatically, and it is tested in Cygwin, OS X Mountain Lion, Ubuntu 12.04 and Arch Linux - other operating systems may need to install the dependencies manually.
If you have more than one virtual serial (COM) port active, you may need to explicitly specify which port to use. Pass the port name as the second argument to the script, e.g. in Linux:
$ script/upload_hex.sh <firmware file you downloaded>.hex /dev/ttyUSB2
and in Windows, e.g. if you needed to use com4 instead of the default com3:
$ script/upload_hex.sh <firmware file you downloaded>.hex com4
Windows notes:
In Windows, this command will only work in Cygwin, not the standard cmd.exe or Powershell.
If you get errors about $'\r': command not found then your Git configuration added Windows-style CRLF line endings. Run this first to ignore the CR:
$ set -o igncr && export SHELLOPTS
If the bootstrap script failed, you will need to install the dependencies manually. You will need:
If you are using Windows or OS X, you need to install the FTDI driver. If you didn’t need to install MPIDE, you can download the driver separately from FTDI.
In order to program the CAN translator, you need an AVR programmer tool. There are a number of options that will work.
With MPIDE
If you have MPIDE installed, that already includes a version of avrdude. You need to set the MPIDE_DIR environment variable in your terminal to point to the folder where you installed MPIDE. Once set, you should be able to use upload_hex.sh.
Without MPIDE
If you do not already have MPIDE installed (and that’s fine, you don’t really need it), you can install a programmer seprately:
Linux - Look for avrdude in your distribution’s package manager.
OS X - Install avrdude with Homebrew.
On Windows, a driver is required to use the CAN translator’s USB interface. A driver is available in the conf/windows-driver folder. The driver supports both 32- and 64-bit Windows. The driver is generated using the libusb-win32 project.
The OpenXC Python library, in particular the openxc-dashboard tool, is useful for testing the CAN translator with a regular computer, to verify the data received from a vehicle before introducing an Android device. Documentation for this tool (and the list of required dependencies) is available on the OpenXC vehicle interface testing page.
The repository includes a rudimentary CAN bus emulator:
$ make clean
$ make emulator
The emulator generates fakes values for many OpenXC signals and sends them over USB as if it were plugged into a live CAN bus.
The non-embedded platform specific code in this repository includes a unit test suite. It’s a good idea to run the test suite before committing any changes to the git repository.
The test suite uses the check library.
$ sudo apt-get install check
$ sudo pacman -S check
cantranslator/src $ make clean && make test -s
To view debugging information, first compile the firmware with the debugging flag:
$ make clean
$ DEBUG=1 make
$ make flash
When compiled with DEBUG=1, two things happen:
Debug symbols are available in the .elf file generated in the build directory.
Log messages will be output over a UART port (no hardware flow control is required)
- On the chipKIT Max32, logging will be on UART2 (Pin 16 - Tx, Pin 17 - Rx) at 115200 baud.
- On the Blueboard LPC1768H, logging will be on UART0 (Pin P0.3 - Rx, Pin P0.2 - Tx) at 115200 baud.
View this output using an FTDI cable and any of the many available serial terminal monitoring programs, e.g. screen, minicom, etc.
You can optionally receive the output data over a serial connection in addition to USB. The data format is the same as USB - a stream of newline separated JSON objects.
In the same way that you can send OpenXC writes over USB using the OUT direction of the USB endpoint, you can send identically formatted messages in the opposite direction on the serial device - from the host to the CAN translator. They’ll be processed in exactly the same way. These write messages are accepted via serial even if USB is connected.
On the chipKIT, UART1A is used for OpenXC output at the 460800 baud rate. Hardware flow control (RTS/CTS) is enabled, so CTS must be pulled low by the receiving device before data will be sent.
UART1A is also used by the USB-Serial connection, so in order to flash the PIC32, the Tx/Rx lines must be disconnected. Ideally we could leave that UART interface for debugging, but there are conflicts with all other exposed UART interfaces when using flow control.
On the NGX Blueboard LPC1768-H, UART1 is used for OpenXC output at the 921600 baud rate. Like on the chipKIT, hardware flow control (RTS/CTS) is enabled, so CTS must be pulled low by the receiving device before data will be sent.
Most users do not need to know the details of the device driver, but for reference it is documented here.
The CAN translator initializes its USB 2.0 controller as a USB device with three endpoints. The Android tablet or computer you connect to the translator acts as the USB host, and must initiate all transfers.
This is the standard USB control transfer endpoint. The CAN transalator has a few control commands:
Version control command: 0x80
The host can retrieve the version of the CAN translator using the 0x80 control request. The data returned is a string containing the software version of the firmware and the configured vehicle platform in the format:
Version: 1.0 (c346)
where 1.0 is the software version and c346 is the configured vehicle.
Reset control command: 0x81
The CAN transceivers can be re-initialized by sending the 0x81 control request. This command was introduced to work around a bug that caused the CAN translator to periodically stop responding. The bug still exists, but there are now workarounds in the code to automatically re-initialize the transceivers if they stop receiving messages.
Endpoint 1 is configured as a bulk transfer endpoint with the IN direction (device to host). OpenXC JSON messages read from the vehicle are sent to the host via IN transactions. When the host is ready to receive, it should issue a request to read data from this endpoint. A larger sized request will allow more messages to be batched together into one USB request and give high overall throughput (with the downside of introducing delay depending on the size of the request).
OpenXC JSON messages created by the host to send to the vehicle (i.e. to write to the CAN bus) are sent via OUT transactions. The CAN translator is prepared to accept writes from the host as soon as it initializes USB, so they can be sent at any time. There is no special demarcation on these messages to indicate they are writes - the fact that they are written in the OUT direction is sufficient. Write messages must be no more than 4 USB packets in size, i.e. 4 * 64 = 256 bytes.
In the same way the CAN translator is pre-configured with a list of CAN signals to read and parse from the CAN bus, it is configured with a whitelist of messages and signals for which to accept writes from the host. If a message is sent with an unlisted ID it is silently ignored.
The CAN translation module code runs on an Arduino-compatible microcontroller connected to one or more CAN buses. It receives either all CAN messages or a filtered subset, performs any unit conversion or factoring required and outputs a generic version to a USB interface.
If you’ve downloaded a pre-built binary for a specific vehicle, see the Flashing a Pre-compiled Binary section for instructions on how to flash your CAN translator. Most users do not need to set up the full development described in these docs.
A Windows driver for the USB interface is available in the conf/windows-driver folder. The driver supports both 32- and 64-bit Windows. The driver is generated using the libusb-win32 project.
If you’ve downloaded a pre-built binary for a specific vehicle, see the Flashing a Pre-compiled Binary section for instructions on how to flash your CAN translator. Most users do not need to set up the full development described in these docs.
Install Git from your distribution’s package manager.
Ubuntu:
$ sudo apt-get install git
Arch Linux:
$ [sudo] pacman -S git
gcc4, patchutils, git, unzip, python, python-argparse, check, curl, libsasl2, ca-certificates
$ set -o igncr && export SHELLOPTS
$ export http_proxy=<your proxy> $ export https_proxy=<your proxy>
$ git clone https://github.com/openxc/cantranslator
$ cd cantranslator $ script/bootstrap.sh
The bootstrap.sh script is tested in Cygwin, OS X Mountain Lion, Ubuntu 12.04 and Arch Linux - other operating systems may need to install the dependencies manually.
In order to build the CAN translator firmware from source, you need a few dependencies:
If instead of the chipKIT, you are compiling for the Blueboard (based on the NXP LPC1768/69), instead of MPIDE you will need:
The easiest way to install these dependencies is to use the script/bootstrap.sh script in the cantranslator repository. Run the script in Linux, Cygwin in Windows or OS X and if there are no errors you should be ready to go:
$ script/bootstrap.sh
If there are errors, continue reading in this section to install whatever piece failed manually.
Clone the repository from GitHub:
$ git clone https://github.com/openxc/cantranslator
Some of the library dependencies are included in this repository as git submodules, so before you go further run:
$ git submodule update --init
If this doesn’t print out anything or gives you an error, make sure you cloned this repository from GitHub with git and that you didn’t download a zip file. The zip file is missing all of the git metadata, so submodules will not work.
Building the source for the CAN translator for the chipKIT microcontroller requires MPIDE (the development environment and compiler toolchain for chipKIT provided by Digilent). Installing MPIDE can be a bit quirky on some platforms, so if you’re having trouble take a look at the installation guide for MPIDE.
Although we just installed MPIDE, building via the GUI is not supported. We use GNU Make to compile and upload code to the device. You still need to download and install MPIDE, as it contains the PIC32 compiler.
You need to set an environment variable (e.g. in $HOME/.bashrc) to let the project know where you installed MPIDE (make sure to change these defaults if your system is different!):
# Path to the extracted MPIDE folder (this is correct for OS X)
export MPIDE_DIR=/Applications/Mpide.app/Contents/Resources/Java
Remember that if you use export, the environment variables are only set in the terminal that you run the commands. If you want them active in all terminals (and you probably do), you need to add these export ... lines to the file ~/.bashrc (in Linux) or ~/.bash_profile (in OS X) and start a new terminal.
It also requires some libraries from Microchip that we are unfortunately unable to include or link to as a submodule from the source because of licensing issues:
You can read and accept Microchip’s license and download both libraries on the Digilent download page.
Once you’ve downloaded the .zip file, extract it into the libs directory in this project. It should look like this:
- /Users/me/projects/cantranslator/
---- libs/
-------- chipKITUSBDevice/
chipKitCAN/
... other libraries
If you’re using Mac OS X or Windows, make sure to install the FTDI driver that comes with the MPIDE download. The chipKIT uses a different FTDI chip than the Arduino, so even if you’ve used the Arduino before, you still need to install this driver.
$ pacman -S openocd
Install Homebrew. Then:
$ brew install libftdi libusb
$ brew install --enable-ft2232_libftdi openocd
Remove the Olimex sections from the FTDI kernel module, and then reload it:
$ sudo sed -i "" -e "/Olimex/{N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;d;}" /System/Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist
$ sudo kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext/
$ sudo kextload /System/Library/Extensions/FTDIUSBSerialDriver.kext/
Download the binary version of the toolchain for your platform (Linux, OS X or Windows) from this Launchpad site.
In Arch Linux you can alternatively install the gcc-arm-none-eabi package from the AUR.
Updates to the CAN translator firmware may be distributed as pre-compiled binaries, e.g. if they are distributed by an OEM who does not wish to make the CAN signals public. If that’s the case for your vehicle, you will have a .hex file and can use the upload_hex.sh script to update your device.
git, curl, libsasl2, ca-certificates
$ echo "set -o igncr && export SHELLOPTS" >> ~/.bashrc && source ~/.bashrc
If you already have Git installed, you can skip ahead to the all platforms section
Install Git from your distribution’s package manager.
Ubuntu:
$ sudo apt-get install git
Arch Linux:
$ [sudo] pacman -S git
$ export http_proxy=<your proxy> $ export https_proxy=<your proxy>
$ git clone https://github.com/openxc/cantranslator
You need to have the mini-USB port on the chipKIT connected to your computer to upload a new firmware. This is different than the micro-USB port that you use to read vehicle data - see the device connections section of the OpenXC website to make sure you have the correct cable attached.
Open a terminal and cd into the cantranslator folder that you cloned with Git. Run the upload_hex.sh script with the .hex file you downloaded:
$ script/upload_hex.sh <firmware file you downloaded>.hex
The upload_hex.sh script attempts to install all required dependencies automatically, and it is tested in Cygwin, OS X Mountain Lion, Ubuntu 12.04 and Arch Linux - other operating systems may need to install the dependencies manually.
If you have more than one virtual serial (COM) port active, you may need to explicitly specify which port to use. Pass the port name as the second argument to the script, e.g. in Linux:
$ script/upload_hex.sh <firmware file you downloaded>.hex /dev/ttyUSB2
and in Windows, e.g. if you needed to use com4 instead of the default com3:
$ script/upload_hex.sh <firmware file you downloaded>.hex com4
Windows notes:
In Windows, this command will only work in Cygwin, not the standard cmd.exe or Powershell.
If you get errors about $'\r': command not found then your Git configuration added Windows-style CRLF line endings. Run this first to ignore the CR:
$ set -o igncr && export SHELLOPTS
If the bootstrap script failed, you will need to install the dependencies manually. You will need:
If you are using Windows or OS X, you need to install the FTDI driver. If you didn’t need to install MPIDE, you can download the driver separately from FTDI.
In order to program the CAN translator, you need an AVR programmer tool. There are a number of options that will work.
With MPIDE
If you have MPIDE installed, that already includes a version of avrdude. You need to set the MPIDE_DIR environment variable in your terminal to point to the folder where you installed MPIDE. Once set, you should be able to use upload_hex.sh.
Without MPIDE
If you do not already have MPIDE installed (and that’s fine, you don’t really need it), you can install a programmer seprately:
Linux - Look for avrdude in your distribution’s package manager.
OS X - Install avrdude with Homebrew.
The code base currently supports two embeddedd platforms - the chipKIT (based on the Microchip PIC32) and the Blueboard (based on the NXP LPC1768/69). Before you can compile, you will need to define your CAN messages.
The build process works with Linux (tested in Arch Linux and Ubuntu), OS X and Cygwin in Windows.
Note
When running make to compile, try adding the -j4 flag to build jobs in parallel - the speedup can be quite dramatic.
Once the dependencies are installed, attach the chipKIT to your computer with a mini-USB cable, cd into the src subdirectory, build and upload to the device.
$ git submodule init && git submodule update
$ make clean
$ make
$ make flash
If the flash command can’t find your chipKIT, you may need to set the SERIAL_PORT variable if the serial emulator doesn’t show up as /dev/ttyUSB* in Linux, /dev/tty.usbserial* in Mac OS X or com3 in Windows. For example, if the chipKIT shows up as /dev/ttyUSB4:
$ SERIAL_PORT=/dev/ttyUSB4 make flash
and if in Windows it appeared as COM4:
$ SERIAL_PORT=com4 make flash
If the compilation didn’t work:
If you get a lot of errors about undefined refernece to getSignals()' and other functions, you need to make sure you defined your CAN messages - read through CAN Message Definition before trying to compile.
It is possible to use an IDE like Eclipse to edit and compile the project.
If you didn’t set up the environment variables from the Installation section (e.g. MPIDE_HOME), you can also do that from within Eclipse in C/C++ project settings.
There will still be some errors in the Eclipse problem detection, e.g. it doesn’t seem to pick up on the GCC __builtin_* functions, and some of the chipKIT libraries are finicky. This won’t have an effect on the actual build process, just the error reporting.
Support for the NXP LPC17xx, an ARM Cortex M3 microcontroller, is experimental at the moment and the documentation is incomplete. We are building successfully on the NGX Blueboard 1768-H using the Olimex ARM-OCD-USB JTAG programmer.
Once the dependencies are installed, attach a JTAG adapter to your computer and the CAN translator, then compile and flash:
$ make clean
$ PLATFORM=BLUEBOARD make -j4
$ PLATFORM=BLUEBOARD make flash
The config files in this repository assume your JTAG adapter is the Olimex ARM-USB-OCD unit. If you have a different unit, change the first line in conf/flash.cfg to the correct value.
On Windows, a driver is required to use the CAN translator’s USB interface. A driver is available in the conf/windows-driver folder. The driver supports both 32- and 64-bit Windows. The driver is generated using the libusb-win32 project.
The OpenXC Python library, in particular the openxc-dashboard tool, is useful for testing the CAN translator with a regular computer, to verify the data received from a vehicle before introducing an Android device. Documentation for this tool (and the list of required dependencies) is available on the OpenXC vehicle interface testing page.
The repository includes a rudimentary CAN bus emulator:
$ make clean
$ make emulator
The emulator generates fakes values for many OpenXC signals and sends them over USB as if it were plugged into a live CAN bus.
The non-embedded platform specific code in this repository includes a unit test suite. It’s a good idea to run the test suite before committing any changes to the git repository.
The test suite uses the check library.
$ sudo apt-get install check
$ sudo pacman -S check
cantranslator/src $ make clean && make test -s
To view debugging information, first compile the firmware with the debugging flag:
$ make clean
$ DEBUG=1 make
$ make flash
When compiled with DEBUG=1, two things happen:
Debug symbols are available in the .elf file generated in the build directory.
Log messages will be output over a UART port (no hardware flow control is required)
- On the chipKIT Max32, logging will be on UART2 (Pin 16 - Tx, Pin 17 - Rx) at 115200 baud.
- On the Blueboard LPC1768H, logging will be on UART0 (Pin P0.3 - Rx, Pin P0.2 - Tx) at 115200 baud.
View this output using an FTDI cable and any of the many available serial terminal monitoring programs, e.g. screen, minicom, etc.
Once the libraries are installed and you run make, you’ll notice that it won’t compile - you’ll get a bunch of errors that look like this:
build-cli/canutil_chipkit.o: In function `initializeCan(CanBus*)':
canutil_chipkit.cpp:(.text._Z13initializeCanP6CanBus+0xb8): undefined reference to `initializeFilterMasks(unsigned long long, int*)'
canutil_chipkit.cpp:(.text._Z13initializeCanP6CanBus+0xcc): undefined reference to `initializeFilters(unsigned long long, int*)'
build-cli/cantranslator.o: In function `receiveWriteRequest(char*)':
cantranslator.cpp:(.text._Z19receiveWriteRequestPc+0x40): undefined reference to `getSignals()'
cantranslator.cpp:(.text._Z19receiveWriteRequestPc+0x48): undefined reference to `getSignalCount()'
cantranslator.cpp:(.text._Z19receiveWriteRequestPc+0x7c): undefined reference to `getCommands()'
cantranslator.cpp:(.text._Z19receiveWriteRequestPc+0x84): undefined reference to `getCommandCount()'
cantranslator.cpp:(.text._Z19receiveWriteRequestPc+0xa4): undefined reference to `getSignals()'
cantranslator.cpp:(.text._Z19receiveWriteRequestPc+0xac): undefined reference to `getSignalCount()'
cantranslator.cpp:(.text._Z19receiveWriteRequestPc+0x118): undefined reference to `getSignals()'
cantranslator.cpp:(.text._Z19receiveWriteRequestPc+0x120): undefined reference to `getSignalCount()'
build-cli/cantranslator.o: In function `initializeAllCan()':
cantranslator.cpp:(.text._Z16initializeAllCanv+0x1c): undefined reference to `getCanBuses()'
cantranslator.cpp:(.text._Z16initializeAllCanv+0x30): undefined reference to `getCanBusCount()'
build-cli/cantranslator.o: In function `_ZL17customUSBCallback9USB_EVENTPvj.clone.0':
cantranslator.cpp:(.text._ZL17customUSBCallback9USB_EVENTPvj.clone.0+0x70): undefined reference to `getMessageSet()'
cantranslator.cpp:(.text._ZL17customUSBCallback9USB_EVENTPvj.clone.0+0x98): undefined reference to `getMessageSet()'
build-cli/cantranslator.o: In function `receiveCan(CanBus*)':
cantranslator.cpp:(.text._Z10receiveCanP6CanBus+0x40): undefined reference to `decodeCanMessage(int, unsigned char*)'
build-cli/cantranslator.o: In function `loop':
cantranslator.cpp:(.text.loop+0x1c): undefined reference to `getCanBuses()'
cantranslator.cpp:(.text.loop+0x30): undefined reference to `getCanBusCount()'
collect2: ld returned 1 exit status
make[1]: *** [build-cli/cantranslator.elf] Error 1
make[1]: Leaving directory `/home/cantranslator/cantranslator'
make: *** [all] Error 2
The open source repository does not include the implementation of the functions declared in signals.h and these are required to compile and program a CAN transaltor. These functions are dependent on the specific vehicle and message set, which is often proprietary information to the automaker.
You have three options to get a working CAN translator:
You must implement the functions defined in the signals.h header file. The documentation of those functions describes the expected effect of each. Implement these in a file called signals.cpp and the code should now compile.
You must know the CAN message formats of the vehicle you want to use with the CAN translator, as you cannot implement these functions without that knowledge.
The code auto-generation script accepts a special JSON input file that defines the CAN messages and signals of interest and rewrites it as C data structures, ready to be downloaded to the device. You must know the CAN message formats of the vehicle you want to use with the CAN translator, as you cannot create these input files without that knowledge.
Once you have one or more input JSON files, run the generate_source.py script to create a complete implementation of signals.cpp for your messages. For example, if your mappings are in signals.json:
$ script/generate_code.py --json signals.json > signals.cpp
If you used the xml_to_json.py script to convert an XML CAN database to JSON, make sure to provide both the converted file along with your mappings:
$ script/generate_code.py --json signals.json --json mappings.json > signals.cpp
Drop the new signals.cpp file in the src folder, and it should now compile. Don’t add anything else to this file - it’s derivative of the master JSON, and should be able to be wiped and recreated at any time.
If you have multiple CAN buses and want to define their signals and messages in separate files, just pass multiple JSON files:
$ script/generate_code.py --json highspeed.json --json mediumspeed.json > signals.cpp
Note that the JSON files are parsed and merged, so if you want to define custom handlers and states separately from the signal definition itself, you can store them in separate files and they will be merged on import.
The code generation script (to generate signals.cpp) requires a JSON file of a specific format as input. The input format is a JSON object like the one found in sample.json.
The root level JSON object maps CAN bus addresses to CAN bus objects, CAN message IDs to CAN message objects in each bus, and CAN signal name to signal object within each message.
The object key for a CAN bus is a hex address that identifies which CAN controller on the microcontroller is attached to the bus. The platforms we are using now only have 2 CAN controllers, but by convention they are identified with 0x101 and 0x102 - these are the only acceptable bus addresses.
speed - The CAN bus speed in Kbps.
messages - A mapping of CAN message objects that are on this bus, the key being the message ID in hex as a string (e.g. 0x90).
commands - A mapping of CAN command objects that should be sent on this bus that should be sent on this bus. The key is the name that will be used over the OpenXC interface.
The attributes of a command object are:
handler - The name of a custom command handler function that should be called with the data when the named command arrives over USB/Bluetooth/etc.
The attributes of a message object are:
name - The name of the CAN message. Optional - just used to be able to reference the original documentation from the mappings file.
handler - The name of a function that will be compiled with the sketch and should be applied to the entire raw message value. No other operations are performed on the data if this type of handler is used. Optional - see the “Custom Handlers” section for more.
signals - A list of CAN signal objects that are in this message, with the official name of the signal as the key. If merging with automatically generated JSON from another database, this value must match exactly - otherwise, it’s an arbitrary name.
The attributes of a signal object within a message are:
generic_name - The name of the associated generic signal name (from the OpenXC specification) that this should be translated to. Optional - if not specified, the signal is read and stored in memory, but not sent to the output bus. This is handy for combining the value of multiple signals into a composite measurement such as steering wheel angle with its sign.
bit_position - The staring bit position of this signal within the message.
bit_size - The width in bits of the signal.
factor - The signal value is multiplied by this if set. Optional.
offset - This is added to the signal value if set. Optional.
value_handler - The return type and name of a function that will be compiled with the sketch and should be applied to the signal’s value after the normal translation. Optional - see the “Custom Handlers” section for more.
ignore - Setting this to true on a signal will silence output of that signal. The translator will not monitor the signal nor store any of its values. This is useful if you are using a custom handler for an entire message, want to silence the normal output of the signals it handles, and you don’t need the translator to keep track of the values of any of the signals separately. If you need to use the previously stored values of any of the signals, you can use the ignoreHandler as a value handler for the signal.
states - For state values, this is a mapping between the desired descriptive enum states (e.g. off) and a list of the corresponding raw state values from the CAN bus (usually an integer). The raw values are specified as a list to accommodate multiple raw states being coalesced into a single final state (e.g. key off and key removed both mapping to just “off”).
send_frequency - Some CAN signals are sent at a very high frequency, likely more often than will ever be useful to an application. This attribute defaults to 1 meaning that 1/1 (i.e. 100%) of the values for this signal will be processed and sent over USB. Increasing the value will reduce the number of messages that are sent - a value of 10 means that only 1/10 messages (i.e. every 10th message) is processed. You don’t want to combine this attribute with send_same or else you risk missing a status change message if wasn’t one of the messages the translator decided to let through.
send_same - By default, all signals are process and sent over USB every time they are received on the CAN bus. By setting this to false, you can force a signal to be sent only if the value has actually changed. This works best with boolean and state based signals.
writable - The only signals read through the OUT channel of the USB device (i.e. from the host device back to the CAN translator) that are actually encoded and written back to the CAN bus are those marked with this flag true. By default, the value will be interpreted as a floating point number.
write_handler - If the signal is writable and is not a plain floating point number (i.e. it is a boolean or state value), you can specify a custom function here to encode the value for a CAN messages. This is only necessary for boolean types at the moment - if your signal has states defined, we assume you need to encode a string state value back to its original numerical value.
Optionally, you can specify completely custom handler functions to process incoming OpenXC messages from the USB host. In the commands section of the JSON object, you can specify the generic name of the OpenXC command and an associated function that matches the CommandHandler function prototype (from canutil.h):
bool (*CommandHandler)(const char* name, cJSON* value, cJSON* event,
CanSignal* signals, int signalCount);
Any message received from the USB host with that name will be passed to your handler - this is useful for situations where there isn’t a 1 to 1 mapping between OpenXC command and CAN signal, e.g. if the left and right turn signal are split into two signals instead of the 1 state-based signal used by OpenXC. You can use the sendCanSignal function in canwrite.h to do the actual data sending on the CAN bus.
The default handler for each signal is a simple passthrough, translating the signal’s ID to an abstracted name (e.g. SteeringWheelAngle) and its value from engineering units to something more usable. Some signals require additional processing that you may wish to do within the translator and not on the host device. Other signals may need to be combined to make a composite signal that’s more meaningful to developers.
An good example is steering wheel angle. For an app developer to get a value that ranges from e.g. -350 to +350, we need to combine two different signals - the angle and the sign. If you want to make this combination happen inside the translator, you can use a custom handler.
You may also need a custom handler to return a value of a type other than float. A handler is provided for dealing with boolean values, the booleanHandler - if you specify that as your signal’s value_handler the resulting JSON will contain true for 1.0 and false for 0.0. If you want to translate integer state values to string names (for parsing as an enum, for example) you will need to write a value handler that returns a char*.
There are two levels of custom handlers:
For this example, we want to modify the value of SteeringWheelAngle by setting the sign positive or negative based on the value of the other signal (StrAnglSign). Every time a CAN signal is received, the new value is stored in memory. Our custom handler handleSteeringWheelAngle will use that to adjust the raw steering wheel angle value. Modify the input JSON file to set the value_handler attribute for the steering wheel angle signal to handleSteeringWheelAngle. If you’re using generate_code.py, the handlers should be saved in src/handlers.h and src/handlers.cpp:
src/handlers.h:
float handleSteeringWheelAngle(CanSignal* signal, CanSignal* signals,
int signalCount, float value, bool* send);
src/handlers.cpp:
float handleSteeringWheelAngle(CanSignal* signal, CanSignal* signals,
int signalCount, float value, bool* send) {
if(signal->lastValue == 0) {
// left turn
value *= -1;
}
return value;
}
The valid return types for value handlers are bool, float and char* - the function prototype must match one of:
char* customHandler(CanSignal* signal, CanSignal* signals, int signalCount,
float value, bool* send);
float customHandler(CanSignal* signal, CanSignal* signals, int signalCount,
float value, bool* send);
bool customhandler(cansignal* signal, cansignal* signals, int signalCount,
float value, bool* send);
where signal is a pointer to the CanSignal this is handling, signals is a an array of all signals, value is the raw value from CAN and send is a flag to indicate if this should be sent over USB.
The bool* send parameter is a pointer to a bool you can flip to false if this signal value need not be sent over USB. This can be useful if you don’t want to keep notifying the same status over and over again, but only in the event of a change in value (you can use the lastValue field on the CanSignal object to determine if this is true).
A known issue with this method is that there is no guarantee that the last value of another signal arrived in the message or before/after the value you’re current modifying. For steering wheel angle, that’s probably OK - for other signals, not so much.
If you need greater precision, you can provide a custom handler for the entire message to guarantee they arrived together. You can generate 0, 1 or many translated messages from one call to your handler function.
void handleSteeringWheelMessage(int messageId, uint64_t data,
CanSignal* signals, int signalCount, Listener* listener);
float steeringWheelAngle = decodeCanSignal(&signals[1], data);
float steeringWheelSign = decodeCanSignal(&signals[2], data);
float finalValue = steeringWheelAngle;
if(steeringWheelSign == 0) {
// left turn
finalValue *= -1;
}
char* message = generateJson(signals[1], finalValue);
sendMessage(usbDevice, (uint64_t*) message, strlen(message));
}
Using a custom message handler will not stop individual messages for each signal from being output. To silence them but still store their values in signal->lastvalue as they come in, specify the special ignoreHandler as the value_handler for signals don’t want to double send. The reason we don’t do this automatically is that not all signals in a message are always handled by the same message handler.
If you use Canoe to store your “gold standard” CAN signal definitions, you may be able to use the included xml_to_json.py script to make your JSON for you. First, export the Canoe .dbc file as XML - you can do this with Vector CANdb++. Next, create a JSON file according to the format defined above, but only define:
Assuming the data exported from Vector is in signals.xml and your minimal mapping file is mapping.json, run the script:
$ ./xml_to_json.py signals.xml mapping.json signals.json
The script scans mapping.json to identify the CAN messages and signals that you want to use from the XML file. It pulls the neccessary details of the messages (bit position, bit size, offset, etc) and outputs the resulting subset as JSON into the output file, signals.json.
The resulting file together with mapping.json will work as input to the code generation script.
See the output format section of the OpenXC website for details.
You can optionally receive the output data over a serial connection in addition to USB. The data format is the same as USB - a stream of newline separated JSON objects.
In the same way that you can send OpenXC writes over USB using the OUT direction of the USB endpoint, you can send identically formatted messages in the opposite direction on the serial device - from the host to the CAN translator. They’ll be processed in exactly the same way. These write messages are accepted via serial even if USB is connected.
On the chipKIT, UART1A is used for OpenXC output at the 460800 baud rate. Hardware flow control (RTS/CTS) is enabled, so CTS must be pulled low by the receiving device before data will be sent.
UART1A is also used by the USB-Serial connection, so in order to flash the PIC32, the Tx/Rx lines must be disconnected. Ideally we could leave that UART interface for debugging, but there are conflicts with all other exposed UART interfaces when using flow control.
On the NGX Blueboard LPC1768-H, UART1 is used for OpenXC output at the 921600 baud rate. Like on the chipKIT, hardware flow control (RTS/CTS) is enabled, so CTS must be pulled low by the receiving device before data will be sent.
Most users do not need to know the details of the device driver, but for reference it is documented here.
The CAN translator initializes its USB 2.0 controller as a USB device with three endpoints. The Android tablet or computer you connect to the translator acts as the USB host, and must initiate all transfers.
This is the standard USB control transfer endpoint. The CAN transalator has a few control commands:
Version control command: 0x80
The host can retrieve the version of the CAN translator using the 0x80 control request. The data returned is a string containing the software version of the firmware and the configured vehicle platform in the format:
Version: 1.0 (c346)
where 1.0 is the software version and c346 is the configured vehicle.
Reset control command: 0x81
The CAN transceivers can be re-initialized by sending the 0x81 control request. This command was introduced to work around a bug that caused the CAN translator to periodically stop responding. The bug still exists, but there are now workarounds in the code to automatically re-initialize the transceivers if they stop receiving messages.
Endpoint 1 is configured as a bulk transfer endpoint with the IN direction (device to host). OpenXC JSON messages read from the vehicle are sent to the host via IN transactions. When the host is ready to receive, it should issue a request to read data from this endpoint. A larger sized request will allow more messages to be batched together into one USB request and give high overall throughput (with the downside of introducing delay depending on the size of the request).
OpenXC JSON messages created by the host to send to the vehicle (i.e. to write to the CAN bus) are sent via OUT transactions. The CAN translator is prepared to accept writes from the host as soon as it initializes USB, so they can be sent at any time. There is no special demarcation on these messages to indicate they are writes - the fact that they are written in the OUT direction is sufficient. Write messages must be no more than 4 USB packets in size, i.e. 4 * 64 = 256 bytes.
In the same way the CAN translator is pre-configured with a list of CAN signals to read and parse from the CAN bus, it is configured with a whitelist of messages and signals for which to accept writes from the host. If a message is sent with an unlisted ID it is silently ignored.
Please see our Contributing Guide.
For discussions about the usage, development, and future of OpenXC, please join the OpenXC mailing list.
If you have any suggestions, bug reports or annoyances please report them to our issue tracker at http://github.com/openxc/cantranslator/issues/