4.1.1. CAN-Ethernet Gateway demo

4.1.1.1. Overview

Gateway is one of the major use cases in modern cars. Performance requirements for gateway applications are ever increasing due to the advanced connected car architecture having multiple domain controllers.

The CAN-Ethernet gateway demo showcases P2P (Protocol to Protocol) translation i.e. translating data and control information between incompatible networks like Ethernet and CAN for communication on the J721E device through the IEEE-1722 protocol.

The demo application enables full duplex routing between: CAN-to-Ethernet, Ethernet-to-CAN, CAN-to-CAN, and Ethernet-to-Ethernet. The demo uses MCAL drivers running on one Main R5F core, along with a Ethernet remote switch server running on the other Main R5F.

4.1.1.2. Changes over previous release

  • CPSW 2G usage has been replaced with CPSW 9G.
  • MCU domain usage is deprecated and has been replaced with Main domain.
  • Support for Ethernet-to-Ethernet routing has been added since the demo now uses two Ethernet ports on CPSW 9G.
  • The demo uses MCAN4 and MCAN9 ports in the Main domain, instead of previously utilizing the MCAN0 and MCAN1 in MCU Domain.
  • Automation support via Python scripts has been added for testing the demo application. It uses the Linux driver for PCAN-USB from PEAK-System Technik GmbH.
  • GUI has been provided for improved look and feel.
  • An add-on card called GESI is required in addition to the J721E EVM Board.
  • The gateway demo requires an additional component called the Ethernet Remote Switch server to enable the CPSW 9G switch.
  • PCAN GUI based Windows tool is no longer used.
  • SD Card boot mode support has been removed, and OSPI boot support has been added.

4.1.1.3. Assumptions and Prerequisities

Before getting into more details, readers should familiarize themselves with the assumptions made in this document and general demo requirements.

4.1.1.3.1. Assumptions

  • Basic familiarity with operating any CAN device capable of sending and receiving CAN-FD messages. This includes knowledge of wiring and signals. In this demo, the PCAN tool is used to show the same.
  • Basic familiarity with Python3, as it is used for implementing test automation.
  • Basic familiarity with Ethernet interface and IEEE 1722 protocol
  • Knowledge of raw sockets is helpful, but not essential
  • Operation of a PC/System running Linux. Since raw sockets are used, Windows is not supported.
  • Basic familiarity with Jacinto 7 Architecture
  • For details on individual parts of the Jacinto 7, such as MCAN, Main domain, and other parts, readers are asked to read SoC documentation first (if they haven’t done so already).

4.1.1.3.2. Hardware

  • J721E EVM Board (SOM Board and Common Board) and a GESI add-on card (for CAN and Ethernet ports)
  • CAN Receiver/Transmitter with minimum of 2x ports. This demo shows CAN functionality with 2x PCAN-USB tools, but it’s not limited to PCAN tools. Refer to PCAN tool setup section for further details.
  • 2x LAN Cables (preferably CAT6)
  • 2x Micro USB cable (for UART and JTAG)
  • Linux PC (recommended: Ubuntu 18.04) with minimum of 2x Gigabit ports and root access. If ports are not available natively, then USB-Ethernet adapters can be used.

Important

Root access is required because the demo uses raw sockets, and raw sockets are only accessible with root privileges.

4.1.1.3.3. Software

  • Ubuntu 18.04 is required if user intends to run the GUI which is provided as a precompiled binary.

  • Code Composer Studio (CCS) version 9.3.0

  • PC Ethernet tools - Required for receiving and transmitting data over Ethernet

    • Use/run recv_1722.out and send_1722.out utilities on host PC. These utilities are available at:

      <SDK_INSTALL_PATH>/gateway-demos/pctools
      
  • Test Automation Framework - Can only be used with PCAN-USB tool and Ethernet adapters attached to Linux PC

    • Use/run run_demo.py to run automation tools. There is a separate section on using the Test automation framework here Automated Test Framework.
    • Python3 base installation on Ubuntu PC
    • libpopt-dev installation for compiling Peak CAN linux driver
  • CAN tool software (PCAN drivers and PCAN View if using PCAN-USB tool)

  • PCAN Driver 8.9.3 for Linux (if using the test automation framework) from PEAK-System Technik GmbH. See Download Link

4.1.1.4. Architecture Overview

The following block diagram shows the various functional blocks and the data flow used in the gateway demo application. As shown in the diagram, PC Ethernet applications are used for transmitting and receiving Ethernet frames between PC and the J721E EVM. Similarly, any compatible CAN tool can be used for CAN message reception and transmission.

J721E Demo setup graphic

The routing is done based on a queue-based architecture, where the gateway task periodically polls the CAN and Ethernet queues, which are, in turn, populated by the respective drivers in the interrupt context. This architecture allows full packet inspection of packet and allows matching two asynchronous interfaces like Ethernet and CAN.

The CAN/Ethernet demo application is supported only on the Main_Cortex_R5_0_1 core of the J721E device along with the accompanying remote switch driver, which runs on the Main_Cortex_R5_0_0 core.

4.1.1.5. Software Features

  • Routing at L2 within application, through IEEE 1722 protocol for CAN-to-CAN, CAN-to-Eth, Eth-to-CAN and Eth-to-Eth
  • PC-based raw socket applications for sending/receiving 1722 frames
  • Weighted average bridge delay computation for all routed packets
  • Test Automation Framework to automatically run the demo and report throughput and latency numbers without user intervention
  • A GUI binary to provide improved look and feel

4.1.1.6. Directory Structure

The CAN_ETH Gateway demo is located in the Processor SDK RTOS release under the following directory path:

<SDK_INSTALL_PATH>/gateway-demos/can_eth_gateway

User must issue make command from <SDK_INSTALL_PATH>/gateway-demos location. Detailed description of the directory structure is given below:

  • binary - directory where gateway app and other compiled binaries are generated
  • pctools - directory containing Ethernet PC tools sources and python scripts for Test Automation
  • src - Source files for gateway application and utils
  • docs - Contains User Guide PDF
  • mcuss_demos - Contains MCUSW components which are specific to gateway app
  • build - Contains the makefile infrastructure

4.1.1.7. Components

RTOS components:

  • SYSBIOS
  • XDC

Processor SDK RTOS drivers:

  • MCUSW components like CAN, Eth
  • Eth Firmware
  • UART
  • Board
  • OSAL
  • CSL
  • udma
  • sciclient
  • CPSW LLD
  • IPC

4.1.1.8. Building the Demo

The demo application is built using makefile.

Note

Refer to PDK rules.mk for setting tools paths. Run following commands after this has been done.

Type the following in <SDK_INSTALL_PATH>/gateway-demos to see makefile options:

make help

The following are steps to clean the demo:

cd <SDK_INSTALL_PATH>/gateway-demos
make allclean

The following are steps to compile the demo with all dependencies:

cd <SDK_INSTALL_PATH>/gateway-demos
make all -s -j

4.1.1.9. Host Applications

The PC tools for Ethernet reception, transmission and Test Automation are located under pctools directory. These tools can be built for Linux only through:

cd <SDK_INSTALL_PATH>/gateway-demos/pctools
make all

The python scripts can be used without any changes. Usage is described below under “Test Automation Framework”

4.1.1.10. Running the Demo

The demo can be run either using the Automated Test Framework or manually. The Automated Test Framework has the limitation that it can only be used with the PCAN-USB tool from PEAK-System Technik GmbH.

If using a CAN tool from another manufacturer, please refer to the section which describes how to manually run the demo. The setup for both the systems looks the same, so it is described below before we discuss the Automated Test Framework.

4.1.1.10.1. J721E Board Setup

This demo uses MCAN4, MCAN9, and CPSW 9G’s two ports (Port 2 and Port 3) on the GESI card, which is attached to the bottom of the J721E board. Conceptually, the wiring should be done as shown below:

Graphical representation of J721E demo setup showing all connections

When actual connections are made it looks like below:

Picture of J721E Demo setup on ESD mat with all wires connected

4.1.1.10.1.1. Ethernet Setup

As shown in the figure above, connect the two CPSW 9G Ethernet ports to PC’s Ethernet ports and assign a fixed local IP to the interfaces to avoid unnecessary ARP traffic. If built-in NIC’s are not available, then USB Ethernet NIC’s can be used.

4.1.1.10.1.2. MCAN Setup

As shown in the picture below, connect the two USB-CAN analyzers to MCAN0 and MCAN1 instances, which are labeled as J30 and J32 respectively on the J721E base EVM board. The MCAN pin connection is as follows:

  • Pin 1 (CAN_H)
  • Pin 2 (GRD)
  • Pin 3 (CAN_L)

The following diagram shows the MCAN4 and MCAN9 connections on GESI card. MCAN9 has the same pin orientation (CAN_H, CAN_L and GND) as MCAN4.

CAN connections on base board

If using the PCAN tool, the DB-9 connection is as follows:

PCAN tool pinout

4.1.1.10.2. Automated Test Framework

The framework has two parts:

  • Raw socket based Ethernet tools (provided by TI)
  • Linux Peak CAN driver (Open source driver from PEAK-System Technik GmbH)

In addition to these two, there is a GUI based on open frameworks, which allows the user to visualize the CPU Load, latency, and throughput.

There are two raw socket based Ethernet tools, send_1722.out and recv_1722.out which are used for sending and receiving IEEE 1722 frames, respectively. Their usage is described below.

4.1.1.10.2.1. Ethernet Tool usage

The tools can be built by the user by executing the make all command in the <SDK_INSTALL_PATH>/gateway-demos/can_eth_gateway/pctools directory. The tools provide multiple options to the user, and they can be accessed by running them with the –help option. So, for example, to understand the options provided with send_1722.out run the command:

sudo send_1722.out --help

Example usage:

sudo ./send_1722.out --eth_interface eth0 --gateway_mac 70:ff:76:1d:88:32 --dst_mac f8:b1:56:a6:86:e6 --ipg 1000 --route ETH --timeout 12
sudo ./recv_1722.out --eth_interface eth1 --timeout 12

sudo option is required since raw sockets in Linux require super user permission. As a result, even the python scripts that execute the automated tests require super user permission.

The analogous tool for CAN is called pcanfdtst, which supports both Tx and Rx modes. Its installation and usage is described below.

4.1.1.10.2.2. PCAN Linux driver installation and usage

To install the PCAN Linux driver, follow these steps on your Linux PC. Ubuntu 18.04 is recommended.

  • Download the Peak CAN Linux driver ver. 8.9.3 from https://www.peak-system.com/fileadmin/media/linux/files/peak-linux-driver-8.9.3.tar.gz

  • Extract the package into your home directory or any other location.

  • Install the dependency of libpopt-dev package:

    sudo apt-get install -y libpopt-dev
    
  • Run the following commands to build and install the driver:

    cd peak-linux-driver-8.9.3
    make all
    sudo make install
    
  • Finally, run the following command to enable the driver:

    sudo modprobe pcan
    
  • If the command is successful and the PCAN-USB tool is plugged into PC, then the green light on the device will come up now.

  • The default pcanfdtst tool provided in the Linux driver doesn’t have the necessary extensions required for the automation. To do that, user needs to apply the patch specified here PCAN tool patch to the file pcanfdtst.c in the folder peak-linux-driver-8.9.3/test/src.

  • To patch and build the tool, copy the contents from the section PCAN tool patch to a file, let’s call it pcanfdtst.patch and then execute the following commands in the directory peak-linux-driver-8.9.3/test/src:

    patch pcanfdtst.c pcanfdtst.patch
    cd ..
    make all
    
  • This will build pcanfdtst tool in the peak-linux-driver-8.9.3/test directory.

The pcanfdtst tool has many options, to see all of them run the command:

./pcanfdtst --help

Example usage to receive packets at 1 Mbps bitrate and 5 Mbps data rate:

./pcanfdtst rx --bitrate 1000000 --dbitrate 5000000 --clock 80000000 --brs --fd -q -M 12 /dev/pcan32

4.1.1.10.2.3. Running the Automated Tests

There are four routes to test in the demo:

  • CAN-to-CAN
  • CAN-to-Eth
  • Eth-to-CAN
  • Eth-to-Eth

Each route requires running sender(s) and listener(s) tasks simultaneously. This is automatically done by the Python script called run_demo.py. Besides these four routes, the script supports running System tests which enables all four routes simultaneously. The system tests can only be run with the GUI, which is described in the :ref:Running the GUI section <running_gui>.

Since the python script uses pcanfdtst utility from PCAN Linux Driver, the user first needs to copy the pctools folder to the folder peak-linux-driver-8.9.3/test:

cp -Rf <SDK_INSTALL_PATH>/gateway-demos/can_eth_gateway/pctools peak-linux-driver-8.9.3/test

User can now run the script from the peak-linux-driver-8.9.3/test folder. To find out what all option the script supports, run the command:

python3 pctools/run_demo.py --help

Note

Due to hardcoded dependencies in the path of executables, the script must be run from the test folder as described above.

To run the demo, the Python script needs the following information:

  1. CAN devices attached to the PC. The script needs to know which device is connected to MCAN4, and which one is connected to MCAN9. Users can see this by running the command:

    lspcan
    
  2. Ethernet devices attached to the PC (two are required). Users can see this by running the command:

    ifconfig
    
  3. MAC address of the Gateway application running on the Jacinto 7 EVM. This is either determined automatically or updated manually.

Providing so much information to the script is not easy, so the script provides a way to read this from a file. The file is called app_config.txt and should be kept in the same folder as the script. A sample app_config.txt file is provided in <SDK_INSTALL_PATH>/gateway-demos/can_eth_gateway/pctools folder. If the Python script cannot find the file, then the script tries to generate it automatically with the help from the user. The interaction is self-explanatory, but an example is provided below with comments.

Example usage:

python3 pctools/run_demo.py --iterations 1 --run_time 5 --system_test 0 --gui_enabled 0

Here --iterations 1 tells the script to run the unit tests only once, --run_time 5 tells the script to run each iteration for 5 seconds and --gui_enabled 0 tells the script not to invoke the GUI.

If the script cannot find app_config.txt, it will prompt the user with the following prompts:

Please remove any PCAN devices connected to the PC....hit Enter when ready
Now connect the first PCAN device to MCAN4 interface (J14) on the GESI card...refer to the setup diagram

At this point, if the user connects a PCAN-USB device to PC, then user will get the prompt:

Found one interface

Continuing with the prompts, the user gets:

Now connect the second PCAN device to MCAN9 interface (J6) on the GESI card...refer to the setup diagram
Please select the primary interface. Its usually the built in Ethernet card on a laptop or PC

Now, the user will be prompted with different ethernet interfaces on the PC and must select the appropriate interfaces connected to the Jacinto 7 EVM by entering Y or N. (See setup diagram) For example, if eth0 and eth1 are connected to the Jacinto 7 EVM, then those must be selected:

Please select the secondary interface. Its usually a USB dongle on a laptop or a secondary NIC on a PC

At this prompt, user must select the second ethernet interface. Once that’s done, the script will display something like:

--------Two CAN and two Ethernet Interfaces were added as shown below--------
CAN Interface for MCAN4     : /dev/pcanusbfd32
CAN Interface for MCAN9     : /dev/pcanusbfd33
Primary Eth Interface               : enp1s2
Secondary Eth Interface             : enxd037455f8444
If this is ok, then hit Y else hit N (to exit)

If the user proceeds and everything (Ethernet connection, CAN adapter, drivers, setup, cables) is OK, then user will get the prompt:

Found Gateway MAC. Good!

and the script will create the file app_config.txt file in the folder where the Python script is being run from. Else, the user will get the prompt:

Didn't get any packet from gateway, are you sure you are running it ? Maybe run wireshark and check ?

If this happens, then the user must debug the issue by checking each route manually and trying to figure out where the problem lies. One can also attempt to create app_config.txt manually, if one is confident about the connections. Please see Manually Checking the routes to debug the issue.

4.1.1.10.2.4. Verifying the results

Below, one can see the sample output from a successful unit test run for all four routes:

Iteration # 0 : Script will now run individual tests

Script will now run CAN 2 CAN tests
-------------------CAN 2 CAN Test Results----------------------

Number of CAN frames sent   :  7633
Number of CAN frames received       :  7633
CAN interface received frames for   :  5372364.000000 us

Average CAN 2 CAN delay     :  10 us
Max CAN 2 CAN delay                 :  198 us

Average CPU Load            :  1.000000 %
Script will now run CAN 2 Eth tests
-------------------CAN 2 ETH Test Results----------------------

Number of CAN frames sent   :  7626
Number of Eth frames received       :  15252

Eth interface received frames for   :  6218675.000000 us

Average CAN 2 Eth delay     :  28 us
Max CAN 2 Eth delay                 :  46 us

Average CPU Load            :  3.000073 %
Script will now run Eth 2 Eth tests
-------------------ETH 2 ETH Test Results----------------------

Number of Eth frames sent   :  5391
Number of Eth frames received       :  4941

Eth interface received frames for   :  6432795.000000 us

Average ETH 2 ETH delay     :  28 us
Max ETH 2 ETH delay                 :  48 us

Average CPU Load            :  2.000000 %
Script will now run Eth 2 CAN tests
-------------------ETH 2 CAN Test Results----------------------

Number of Eth frames sent   :  16959
Number of CAN frames received on 1st interface      :  12444

1st interface of CAN received packets for   :  5022384.000000 us

Average ETH 2 CAN delay for 1st interface   :  15 us
Max ETH 2 CAN delay for 1st interface               :  21651188 us

Average CPU Load            :  4.000037 %
Iteration # 0 completed

The command used to execute this test is:

python3 pctools/run_demo.py --iterations 1 --run_time 5 --system_test 0 --gui_enabled 0

There is a known issue of high maximum latency for Eth 2 CAN routes, and this is documented in Known issues & limitations.

4.1.1.10.2.5. Running the GUI and Unit tests

As explained before, to run the unit tests, execute the command:

python3 pctools/run_demo.py --iterations 1 --run_time 5 --system_test 0 --gui_enabled 0

This will cycle through all the 4 routes, CAN-to-CAN, CAN-to-Eth, Eth-to-Eth and Eth-to-CAN cyclically once, while also displaying the statistics.

To run system tests, first run the GUI.

4.1.1.10.2.6. Running the GUI

The GUI is packaged as a downloadable tarball in the Processor SDK Linux Automotive download page. The link is titled can-eth-gateway-demo-gui.tar.gz.

Note

The GUI binaries have been compiled on an x86 machine running Ubuntu 18.04. If another Operating System or Ubuntu version is being used, then this will not work. At the moment, there is no plan to provide sources for compiling the GUI on a different Operating System.

To run the GUI, extract the tarball in your machine at the location <GUI_INSTALL_DIR> and run the following commands to run the data aggregator:

cd <GUI_INSTALL_DIR>/aggregator/bin
./makefifo.sh
./ces-gui-data-aggregator

This will create the pipes and launch the aggregator, which serves as an Inter Process Communication system between the GUI and the PC tools. Now, to run the actual GUI, run the following command in another terminal:

cd <GUI_INSTALL_DIR>/gui/bin
./ces2020-gui-template

This will launch a GUI which looks like this:

CAN-Eth gateway GUI

Now to see the GUI in action, run the following command in peak-linux-driver-8.9.3/test folder:

python3 pctools/run_demo.py --iterations 1 --run_time 20 --system_test 1 --gui_enabled 1

This will run the system tests for 20 seconds. If you see the GUI while the test is running, you will see the bars and dials moving.

4.1.1.10.3. Manually Checking the routes

This section describes how to manually check all four routes using the PCAN-USB FD tool or, for that matter, any other tool. Information provided here can also be used to debug the setup. We now describe how to test each route separately.

4.1.1.10.3.1. CAN to CAN

There are two CAN-to-CAN routes, MCAN4 to MCAN9 and vice versa. The routing is decided based on the value of some bytes in the CAN-FD message. These byte offsets have been chosen keeping future requirements in mind. If the user is using the customised tools provided with the demo, then this is handled automatically based on command line arguments. But if user has their own tools, then they need to re-create the message and use the particular Message ID.

The CAN ports on the Gateway (Jacinto 7 EVM) can only accept a particular extended message ID. This is documented below:

CAN Port Message ID
MCAN4 0xD0
MCAN9 0xE0

If you see the sample app_config.txt file, then you will find the same information.

To send an extended CAN FD message from MCAN4 to MCAN9, run the following command in peak-linux-driver-8.9.3/test directory:

./pcanfdtst tx CAN_ONLY  --bitrate 1000000 --dbitrate 5000000 --clock 80000000 -n 1 -ie 0xD0 --fd -l 64 --tx-pause-us 1000 /dev/pcanusbfd32

Note

Here, we assume that /dev/pcanusbfd32 is connected to MCAN4.

This will send 1 CAN message with the ID 0xD0 with correct formatting to the gateway, which will route it to MCAN9.

To listen and display the CAN message being received on MCAN9, run the following command in another terminal:

./pcanfdtst rx --bitrate 1000000 --dbitrate 5000000 --clock 80000000 --fd -M 10 /dev/pcanusbfd33

Here, we tell the utility to listen on MCAN9 for 10 seconds.

If using a different PCAN tool, use the following 64B message format (hex):

aa ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff

The 0xff values are don’t care, and the user can use anything instead. Only the 0xaa is important. If 0xaa is not used, then routing won’t happen correctly.

If routing from MCAN9 to MCAN4, use the same message but change the message ID and CAN port. So the command will change to:

./pcanfdtst tx CAN_ONLY  --bitrate 1000000 --dbitrate 5000000 --clock 80000000 -n 1 -ie 0xE0 --fd -l 64 --tx-pause-us 1000 /dev/pcanusbfd33

On the listener side, we will change the command to listen on a different port:

./pcanfdtst rx --bitrate 1000000 --dbitrate 5000000 --clock 80000000 --fd -M 10 /dev/pcanusbfd32

4.1.1.10.3.2. CAN to ETH

To do CAN-to-ETH routing, we only need to change the first byte of message ID which tells the gateway how to route the packet. Other aspects of the message like message ID and CAN device remain the same.

To send packet from MCAN4 to both ETH ports, run this command:

./pcanfdtst tx ETH_ONLY  --bitrate 1000000 --dbitrate 5000000 --clock 80000000 -n 1 -ie 0xD0 --fd -l 64 --tx-pause-us 1000 /dev/pcanusbfd32

On the listener side, we need to run this command in pctools directory to check for Ethernet frames:

sudo ./recv_1722.out --eth_interface eth0 --timeout 12 --pipes 0

If using a different PCAN tool, then use the following 64B message format (hex):

bb ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff

Only 0xbb is important, rest of the bytes can be anything.

Note

Here, we assume that eth0 interface is connected to one of the GESI ethernet ports as shown in J721E Board Setup.

4.1.1.10.3.3. ETH to ETH

Refer to the figure below to understand how ETH-to-ETH routing works on gateway:

Eth 2 Eth routing

The PC tools take care of embedding the MAC ID of destination as well as formatting a message.

To send packets, run the following command in the pctools directory:

sudo ./send_1722.out --eth_interface eth0 --gateway_mac 70:ff:76:1d:88:32 --dst_mac 00:ad:24:8f:f6:4e --ipg 1000 --route ETH --num_packets 10

This will send 10 packets on the interface eth0 to gateway device with a MAC ID of 70:ff:76:1d:88:32, where the MAC ID of other ethernet interface is 00:ad:24:8f:f6:4e. Here, --ipg 1000 will add an approximate delay of 1000 us between two ethernet frames.

To receive packets, run the following command in the pctools directory:

sudo ./recv_1722.out --eth_interface eth1 --timeout 12 --pipes 0

To change routing from eth1 to eth0, swap the interface names and MAC ID in the sender and listener commands.

Note

Here, we assume that eth0 and eth1 are ethernet interfaces connected to the GESI card.

4.1.1.10.3.4. ETH to CAN

To do Ethernet to CAN routing, we need to run Ethernet sender and CAN receiver tasks.

Send 10 packets from eth0 to MCAN4 at an IPG of 1ms:

sudo ./send_1722.out --eth_interface eth0 --gateway_mac 70:ff:76:1d:88:32 --ipg 1000 --route MCAN4 --num_packets 10

Listen on MCAN4 for CAN messages for 10 seconds:

./pcanfdtst rx --bitrate 1000000 --dbitrate 5000000 --clock 80000000 --fd -M 10 /dev/pcanusbfd32

Note

Here, we assume that /dev/pcanusbfd32 is connected to MCAN4.

The tool also supports sending output to both CAN ports. To do that, change the --route option to BOTH:

sudo ./send_1722.out --eth_interface eth0 --gateway_mac 70:ff:76:1d:88:32 --ipg 1000 --route BOTH --num_packets 10

4.1.1.10.4. Load and Run the Demo

4.1.1.10.4.1. CCS Boot

For more details about installation of CCS and J721E target creation, refer to the Processor SDK RTOS
Automotive User’s Guide inside “psdk_rtos_auto/docs/user_guide” folder, which can be found in SDK installation.
  1. Connect a micro USB cable to JTAG port of J721E_EVM. The XDS110 JTAG connector is labeled XDS110 (J3).

  2. Connect a micro USB cable to Main Domain UART port on J721E_EVM. Its labeled Main UART (J44). This will create 4 UART ports from /dev/ttyUSB0 to /dev/ttyUSB3

  3. Set EVM’s DIP switches SW8 and SW9 for no-boot mode:

    • SW8 = 10001000
    • SW9 = 01110000
  4. Power on the J721E EVM board. Ensure that SD card is not present or QSPI flashed.

  5. Open up a serial terminal to ttyUSB2 (third instance) for UART communication. This will show logs from MAIN_Cortex_R5F_0_1 core where the Ethernet remote switch runs.

    • Set serial parameters to: 115200 8N1.
    • Set hardware and software flow control to “No”.
    • Below figure shows serial parameters set in Minicom.
    Serial Port Settings in Minicom
  6. Open CCS and launch target config file for J721E_EVM.

  7. Initialize the SoC and load system firmware using the launch.js script at <SDK_INSTALL_PATH>/pdk/packages/ti/drv/sciclient/tools/ccsLoadDmsc/j721e.

  8. Wait for initialization and then connect to MAIN_Cortex_R5F_0_0.

  9. Load the demo executable:

    <SDK_INSTALL_PATH>/ethfw/out/J721E/R5F/SYSBIOS/release/app_remoteswitchcfg_server.xer5f
    
  10. Now connect to MAIN_Cortex_R5F_0_0.

  11. Load the demo executable:

    <SDK_INSTALL_PATH>/gateway-demos/binary/can_eth_gateway_app/bin/j721e_evm/can_eth_gateway_app_mcu2_1_release.xer5f
    
  12. Now first run the application on MAIN_Cortex_R5F_0_0 core, and then immediately run the gateway binary on the other core MAIN_Cortex_R5F_0_1.

  13. The application should boot up with the CCS log shown below. Note that the Ethernet interface takes a few seconds to come up:

    Gateway App:Variant - Pre Compile being used !!!
    CAN_APP: Successfully Enabled CAN Transceiver Main Domain Inst 4,9,11!!!
    Gateway App: Starting CAN Rx
    Gateway App: Starting CAN Rx Interface
    Gateway App:MAC Port 2 Address: 70:ff:76:1d:88:32
    Gateway App: Starting Eth Rx Interface
    Gateway App: Starting Gateway Router
    
  14. The 70:ff:76:1d:88:32 value shown above refers to the MAC address of the Gateway and is the same one that is used in ETH to ETH routing. It will change from device to device.

  15. If UART is connected, then the user will see the following log from remote switch driver indicating a successful boot:

    GESI board detected
    Enabling clocks for CPSW_9G!
    =======================================================
            CPSW Ethernet Firmware Demo
    =======================================================
    ETHFW Version: 0. 1. 1
    ETHFW Build Date (YYYY/MMM/DD):2020/Jan/23
    ETHFW Commit SHA:1aac7995
    ETHFW PermissionFlag:0x1ffffff, UART Connected:true,UART Id:2IPC_echo_test (core : mcu2_0) .....
    CPSW_9G Test on MAIN NAVSS
    Remote demo device (core : mcu2_0) .....
    CpswPhy_bindDriver: PHY 0: OUI:080028 Model:23 Ver:01 <-> 'dp83867' : OK
    Function:CpswProxyServer_attachHandlerCb,HostId:4,CpswType:1
    CpswPhy_bindDriver: PHY 3: OUI:080028 Model:23 Ver:01 <-> 'dp83867' : OK
    PHY 0 is alive
    PHY 3 is alive
    PHY 12 is alive
    PHY 23 is alive
    Host MAC address: Function:CpswProxyServer_allocTxHandlerCb,HostId:4,Handle:a2e1e770,CoreKey:38acb976
    70:ff:76:1d:88:31
    Function:CpswProxyServer_allocRxHandlerCb,HostId:4,Handle:a2e1e770,CoreKey:38acb976
    [NIMU_NDK] CPSW has been started successfully
    Function:CpswProxyServer_ioctlHandlerCb,HostId:4,Handle:a2e1e770,CoreKey:38acb976, Cmd:5000d,InArgsLen:0, OutArgsL
    Function:CpswProxyServer_allocMacHandlerCb,HostId:4,Handle:a2e1e770,CoreKey:38acb976
    Function:CpswProxyServer_ioctlHandlerCb,HostId:4,Handle:a2e1e770,CoreKey:38acb976, Cmd:20000,InArgsLen:24, OutArgs
    Function:CpswProxyServer_registerMacHandlerCb,HostId:4,Handle:a2e1e770,CoreKey:38acb976, MacAddress:70:ff:76:1d:886
    Cpsw_ioctlInternal: CPSW: Registered MAC address.ALE entry:10, Policer Entry:0Function:CpswProxyServer_registerEth6
    Cpsw_handleLinkUp: port 3: Link up: 1-Gpbs Full-Duplex
    Cpsw_handleLinkUp: port 2: Link up: 1-Gpbs Full-Duplex
    

4.1.1.10.4.2. OSPI Boot

  1. OSPI boot mode is the fastest boot mode and the recommended option when it comes to early CAN response.

  2. Download TI’s uniflash tool from https://www.ti.com/tool/UNIFLASH (Ver. 5.2.0) and install in your Linux machine.

  3. Connect a micro USB cable to MCU Domain UART port on J721E_EVM. Its labeled MCU UART (J43).

  4. Open up a serial terminal to port ttyUSB1 for UART1 communication. This will be used to verify boot mode and flash OSPI binaries.

    • Set serial parameters to: 115200 8N1.
  5. Set EVM’s DIP switches SW8 and SW9 for UART boot mode:

    • SW8 = 00000000
    • SW9 = 01110000
  6. Power cycle the EVM. You should see continuous CCCC prints on the console. This means that the EVM is now in UART boot mode and ready to flash OSPI binaries.

Important

Close the serial terminal or you won’t be able to flash the binaries.

  1. Build the binaries required for a successful OSPI boot.

    • Execute the following command in <SDK_INSTALL_PATH>/mcusw/build directory to build the CAN boot app:

      make -sj can_boot_app_mcu_rtos BUILD_OS_TYPE=tirtos HLOSBOOT=none BOOTMODE=ospi CANFUNC=can_fast_response BOARD=j721e_evm SOC=j721e BUILD_PROFILE=release
      
    • Execute the following command in <SDK_INSTALL_PATH>/pdk/packages/ti/build:

      make -sj sbl_cust_img
      
  2. Now copy the following binaries and keep them in one folder, let’s call it <OSPI_BINARIES>.

    • Copy CAN boot application from <SDK_INSTALL_PATH>/mcusw/binary/can_boot_app_mcu_rtos/bin/j721e_evm/can_boot_app_mcu_rtos_mcu1_0_release.appimage to <OSPI_BINARIES> and rename it to app.
    • Copy the bootloader <SDK_INSTALL_PATH>/pdk/packages/ti/boot/sbl/binary/j721e_evm/cust/bin/sbl_cust_img_mcu1_0_release.tiimage to <OSPI_BINARIES> and rename it to tiboot3.bin.
    • Copy System firmware <SDK_INSTALL_PATH>/pdk/packages/ti/drv/sciclient/soc/V1/sysfw.bin to <OSPI_BINARIES>.
    • Run the script gen_combined_image.sh in <SDK_INSTALL_PATH>/gateway-demos/pctools to generate the image app_switch2.appimage and copy it to <OSPI_BINARIES>.
  3. Navigate to the folder where Uniflash tool was installed and run the following command:

    sudo ./dslite.sh --mode processors -c /dev/ttyUSB1 -f /<PATH_TO_UNIFLASH_TOOL>/uniflash_5.2.0/processors/FlashWriter/j721e_evm/uart_j721e_evm_flash_programmer_release.tiimage -i 0
    
  4. If successful, then flash the following images, else power cycle the board and restart. Check for any open connections to the UART if trouble persists.

  5. Run the following commands in succession:

    sudo ./dslite.sh --mode processors -c /dev/ttyUSB1 -f <OSPI_BINARIES>/tiboot3.bin -d 3 -o 0
    sudo ./dslite.sh --mode processors -c /dev/ttyUSB1 -f <OSPI_BINARIES>/sysfw.bin -d 3 -o 40000
    sudo ./dslite.sh --mode processors -c /dev/ttyUSB1 -f <OSPI_BINARIES>/app -d 3 -o A0000
    sudo ./dslite.sh --mode processors -c /dev/ttyUSB1 -f <OSPI_BINARIES>/app_switch2.appimage -d 3 -o 1700000
    
  6. Set EVM’s DIP switches SW8 and SW9 for OSPI boot mode.

    • SW8 = 00000000
    • SW9 = 01000000
  7. Connect a micro USB cable to Main Domain UART port on J721E_EVM. Its labeled Main UART (J44).

  8. Open up a serial terminal to port ttyUSB4 for UART2 communication. This will be used to verify whether gateway application has booted correctly.

    • Set serial parameters to: 115200 8N1.
  9. Power cycle the EVM. Gateway application should boot up, and you will see the log from Ethernet Firmware (see above CCS Boot).

4.1.1.10.5. Statistics

Three types of statistics are of concern to use when running gateway application.

  • Bridge Delay or Latency : The time taken by Gateway to route a packet. This is measured internally by the gateway through timestamps, which is then inserted into the outgoing packet by the Gateway so it can be parsed by external tools. See figure below to understand more on how this is done.
  • Throughput : The number of packets sent/received in a given amount of time. This is calculated by external tools.
  • CPU Load : Gateway application measures it periodically in percentage terms and communicates this to recv_1722.out application. The tool, in turn, calculates an average and displays it along with other test results.
Latency calculation

When a unit test is run, the test automation script automatically displays all the statistics from the test run. See a sample output for a CAN-to-CAN test:

-------------------CAN 2 CAN Test Results----------------------

Number of CAN frames sent           :  4614
Number of CAN frames received       :  4614
CAN interface received frames for   :  5378319.000000 us

Average CAN 2 CAN delay     :  10 us
Max CAN 2 CAN delay                 :  37 us

Average CPU Load            :  4.000037 %

4.1.1.10.6. Known issues & limitations

  1. The Average CPU load value is the last known averaged CPU load.
  2. For ETH-to-CAN tests the Max latency is sometimes high (in the order of milliseconds).
  3. CAN-to-CAN latency is high when running the automated test script because CAN driver is configured in interrupt mode, and high traffic results in a lot of context switches. To see actual latency values, try to set --tx-pause-us to ~1000 or run the test in manual mode.

4.1.1.10.7. PCAN tool patch

The patch required for PCAN-USB tool is provided below. Use it without any modifications:

/* Copyright (C) {YEAR} Texas Instruments Incorporated - https://www.ti.com/
*  This program has been modified by Texas Instruments and those modifications are licensed as follows.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*/

--- pcanfdtst_orig.c        2019-10-29 16:12:45.000000000 +0530
+++ pcanfdtst.c     2020-01-22 18:06:37.318143383 +0530
@@ -126,6 +126,10 @@
/* number max of /dev/pcan interfaces tested at the same time */
#define TST_DEV_PCAN_MAX    8

+/*Scaling factors for GUI*/
+#define LATENCY_SCALING_FACTOR      500
+#define BW_SCALING_FACTOR   5000
+
enum tst_status { NOK, OK, END };
enum tst_seq_mode { FIXD, RAND, INCR };

@@ -231,6 +235,41 @@

static int exit_status = 0;

+#define CAN_ONLY        0xAA
+#define ETH_ONLY        0xBB
+#define ETH_AND_CAN     0xCC
+
+static int route = 0;
+/*Decides the route that CAN frames will take in gateway*/
+static int pipes_enabled = 1;
+/*Enable pipes in application. Enabled by default*/
+
+/*Variables to track CAN 2 CAN bridge delay*/
+static int min_can_2_can_bridge_delay = 0xffffffff;
+static int max_can_2_can_bridge_delay = 0;
+static int avg_can_2_can_bridge_delay = 0;
+
+/*Variables to track Eth 2 CAN bridge delay*/
+static int min_eth_2_can_bridge_delay = 0xffffffff;
+static int max_eth_2_can_bridge_delay = 0;
+static int avg_eth_2_can_bridge_delay = 0;
+
+/*Counters to calculate throughput*/
+static int can_2_can_counter = 0;
+struct timeval start_of_can_2_can;
+struct timeval end_of_can_2_can;
+
+static int eth_2_can_counter = 0;
+struct timeval start_of_eth_2_can;
+struct timeval end_of_eth_2_can;
+
+/*Named FIFO descriptors*/
+int fd_can_2_can_latency = 0;  //For CAN 2 CAN latency values
+int fd_can_2_can_bw = 0;       //For CAN 2 CAN Bandwidth
+
+int fd_eth_2_can_latency = 0;  //For Eth 2 CAN latency values
+int fd_eth_2_can_bw = 0;       //For Eth 2 CAN Bandwidth
+
#ifdef ONE_TASK_PER_DEVICE

/* if defined sem_wait() is used instead of sem_trywait() */
@@ -803,6 +842,7 @@
static int exit_application(int err)
{
    close_application();
+    double time_diff_usec = 0;

    if (pcan_device_opened > 0) {

@@ -816,6 +856,21 @@
            break;
        case TST_MODE_RX:
            lprintf(ALWAYS, "received frames: %u\n", tst_rx_count);
+            printf("Average CAN 2 CAN Delay : %d us\n", avg_can_2_can_bridge_delay);
+            printf("Max CAN 2 CAN Delay : %d us\n", max_can_2_can_bridge_delay);
+
+            printf("Average Eth 2 CAN Delay : %d us\n", avg_eth_2_can_bridge_delay);
+            printf("Max Eth 2 CAN Delay : %d us\n", max_eth_2_can_bridge_delay);
+
+            time_diff_usec = ((double)end_of_can_2_can.tv_sec * 1000000 + (double)end_of_can_2_can.tv_usec);
+            time_diff_usec -= ((double)start_of_can_2_can.tv_sec * 1000000 + (double)start_of_can_2_can.tv_usec);
+
+            printf("CAN 2 CAN test ran for : %f us \n", time_diff_usec);
+
+            time_diff_usec = ((double)end_of_eth_2_can.tv_sec * 1000000 + (double)end_of_eth_2_can.tv_usec);
+            time_diff_usec -= ((double)start_of_eth_2_can.tv_sec * 1000000 + (double)start_of_eth_2_can.tv_usec);
+
+            printf("ETH 2 CAN test ran for : %f us \n", time_diff_usec);
            break;
        default:
            break;
@@ -1720,6 +1775,13 @@
            lprintf(DEBUG,
                "CAN_Write(%p) returns %d\n", dev->handle, err);
#else
+            usleep(tst_tx_pause_us); //add delay as specified
+
+            //automation changes
+            if(route != 0)
+            {
+                pcan_msg->data[0] = route;
+            }
            err = pcanfd_send_msg(dev->fd, pcan_msg);
            lprintf(DEBUG, "pcanfd_send_msg(%d, "
                "msg id=%xh flags=%08xh len=%u) returns %d\n",
@@ -1931,7 +1993,19 @@
{
    struct pcanfd_msg *pcan_msg = dev->can_rx_msgs->list;
    enum tst_status tst_status = OK;
-   int m, err;
+   int m, err, bridge_delay;
+
+    double current_time_in_sec = 0;
+    int    num_packets_sent_in_window = 0;
+
+    static int    last_num_packets_count_can = 0;
+    static double last_updated_time_in_sec_can = 0;
+
+    static int    last_num_packets_count_eth = 0;
+    static double last_updated_time_in_sec_eth = 0;
+
+    //For writing to named pipe
+    char string_buf[20];

    /* be sure to multi read *ONLY* when in RX mode (in TX mode, a single
    * read MUST be used because this function is called when at least ONE
@@ -1941,14 +2015,12 @@
        dev->can_rx_msgs->count = dev->msgs_count;

        err = pcanfd_recv_msgs(dev->fd, dev->can_rx_msgs);
-
        lprintf(DEBUG, "pcanfd_recv_msgs(%d, %u) returns %d "
            "(msgs count=%u)\n",
            dev->fd, dev->msgs_count, err,
            dev->can_rx_msgs->count);
#else
        dev->can_rx_msgs->count = 0;
-
        err = pcanfd_recv_msgs_list(dev->fd,
                    dev->msgs_count,
                    dev->can_rx_msgs->list);
@@ -1971,8 +2043,110 @@
                dev->handle, err);
        pcanmsg_to_fd(pcan_msg, &msgv1);
#else
+        //Test automation changes
        err = pcanfd_recv_msg(dev->fd, pcan_msg);
-
+        if(pcan_msg->data_len != 0)
+        {
+            //Get the min, max and average bridge delay from payload
+            memcpy(&bridge_delay, &(pcan_msg->data[7]), 4);
+
+            /*Calculate for CAN 2 CAN*/
+            if(pcan_msg->data[6] == 0)
+            {
+                if(bridge_delay < min_can_2_can_bridge_delay) {
+                    min_can_2_can_bridge_delay = bridge_delay;
+                }
+
+                if(bridge_delay > max_can_2_can_bridge_delay) {
+                    max_can_2_can_bridge_delay = bridge_delay;
+                }
+
+                avg_can_2_can_bridge_delay = (8 * avg_can_2_can_bridge_delay + 2 * bridge_delay) / 10;
+
+                if(can_2_can_counter++ == 0)
+                {
+                    /*Get the start time*/
+                    gettimeofday (&start_of_can_2_can, NULL);
+                }
+
+                /*Get the end time*/
+                gettimeofday (&end_of_can_2_can, NULL);
+
+                current_time_in_sec = (double)end_of_can_2_can.tv_sec;
+                if((current_time_in_sec - last_updated_time_in_sec_can) >= 1)
+                {
+                    last_updated_time_in_sec_can = current_time_in_sec;
+                    /*1 second has elapsed. Get number of packets sent in this window*/
+                    num_packets_sent_in_window = can_2_can_counter - last_num_packets_count_can;
+                    last_num_packets_count_can = can_2_can_counter;
+
+                    /*Write CAN 2 CAN BW to pipe*/
+                    if(fd_can_2_can_bw)
+                    {
+                        float value = (float)num_packets_sent_in_window/(float)BW_SCALING_FACTOR;
+                        sprintf(string_buf, "%0.3f\n", value);
+                        write(fd_can_2_can_bw, string_buf, strlen(string_buf) + 1);
+                    }
+
+                }
+                //write latency to PIPE
+                if(fd_can_2_can_latency && ((can_2_can_counter % 200) == 0))
+                {
+                    float value = (float)avg_can_2_can_bridge_delay/(float)LATENCY_SCALING_FACTOR;
+                    sprintf(string_buf, "%0.3f\n", value);
+                    write(fd_can_2_can_latency, string_buf, strlen(string_buf) + 1);
+                }
+
+            }
+
+            /*Calculate for ETH 2 CAN*/
+            if(pcan_msg->data[6] == 1)
+            {
+                if(bridge_delay < min_eth_2_can_bridge_delay) {
+                    min_eth_2_can_bridge_delay = bridge_delay;
+                }
+
+                if(bridge_delay > max_eth_2_can_bridge_delay) {
+                    max_eth_2_can_bridge_delay = bridge_delay;
+                }
+
+                avg_eth_2_can_bridge_delay = (8 * avg_eth_2_can_bridge_delay + 2 * bridge_delay) / 10;
+
+                if(eth_2_can_counter++ == 0)
+                {
+                    /*Get the start time*/
+                    gettimeofday (&start_of_eth_2_can, NULL);
+                }
+
+                /*Get the end time*/
+                gettimeofday (&end_of_eth_2_can, NULL);
+                current_time_in_sec = (double)end_of_eth_2_can.tv_sec;
+                if((current_time_in_sec - last_updated_time_in_sec_eth) >= 1)
+                {
+                    last_updated_time_in_sec_eth = current_time_in_sec;
+                    /*1 second has elapsed. Get number of packets sent in this window*/
+                    num_packets_sent_in_window = eth_2_can_counter - last_num_packets_count_eth;
+                    last_num_packets_count_eth = eth_2_can_counter;
+
+                    /*Write ETH 2 CAN BW to pipe*/
+                    if(fd_eth_2_can_bw)
+                    {
+                        float value = (float)num_packets_sent_in_window/(float)BW_SCALING_FACTOR;
+                        sprintf(string_buf, "%0.3f\n", value);
+                        write(fd_eth_2_can_bw, string_buf, strlen(string_buf) + 1);
+                    }
+                }
+
+                //write latency to PIPE
+                if(fd_eth_2_can_latency && ((eth_2_can_counter % 200) == 0))
+                {
+                    float value = (float)avg_eth_2_can_bridge_delay/(float)LATENCY_SCALING_FACTOR;
+                    sprintf(string_buf, "%0.3f\n", value);
+                    write(fd_eth_2_can_latency, string_buf, strlen(string_buf) + 1);
+                }
+            }
+
+        }
        lprintf(DEBUG, "pcanfd_recv_msg(%d) returns %d\n",
                dev->fd, err);
#endif
@@ -2189,9 +2363,9 @@
    if (tst_mode == TST_MODE_TX)
        tst = handle_tx_tst(pdev);

-   if (pdev->pause_us)
-           if (usleep(pdev->pause_us))
-                   tst = handle_errno(errno, pdev);
+   //if (pdev->pause_us)
+   //      if (usleep(pdev->pause_us))
+   //              tst = handle_errno(errno, pdev);

    return tst;
}
@@ -2997,7 +3171,15 @@
            tst_mode = TST_MODE_REC;
        } else if (!strncmp(argv[i], "none", 4)) {
            tst_mode = TST_MODE_NONE;
-           } else if (pcan_device_count < TST_DEV_PCAN_MAX) {
+        } else if (!strcmp(argv[i], "CAN_ONLY")) {
+            route = CAN_ONLY;
+        } else if (!strcmp(argv[i], "ETH_ONLY")) {
+            route = ETH_ONLY;
+           } else if (!strcmp(argv[i], "ETH_AND_CAN")) {
+            route = ETH_AND_CAN;
+        } else if (!strcmp(argv[i], "NO_GUI")) {
+            pipes_enabled = 0;  /*Disable pipes if no GUI*/
+        } else if (pcan_device_count < TST_DEV_PCAN_MAX) {
            memset(pdev, '\0', sizeof(*pdev));

            pdev->name = argv[i];
@@ -3070,7 +3252,55 @@
#endif
#endif /* RT */

-   run_application();
+    //GUI automation code
+    //Open pipes to send data
+
+    if(tst_mode == TST_MODE_RX && pipes_enabled)
+    {
+        if((fd_can_2_can_latency = open("/tmp/can-latency-pipe", O_WRONLY)) < 0)
+        {
+            printf("Could not open can 2 can latency FIFO \n");
+        }
+
+        if((fd_can_2_can_bw = open("/tmp/can-bw-pipe", O_WRONLY)) < 0)
+        {
+            printf("Could not open can 2 can BW FIFO \n");
+        }
+
+        if((fd_eth_2_can_latency = open("/tmp/e2c-latency-pipe", O_WRONLY)) < 0)
+        {
+            printf("Could not open eth 2 can latency FIFO \n");
+        }
+
+        if((fd_eth_2_can_bw = open("/tmp/e2c-bw-pipe", O_WRONLY)) < 0)
+        {
+            printf("Could not open eth 2 can BW FIFO \n");
+        }
+    }
+
+    run_application();
+
+    //Close the named pipes
+
+    if(fd_can_2_can_latency)
+    {
+        close(fd_can_2_can_latency);
+    }
+
+    if(fd_can_2_can_bw)
+    {
+        close(fd_can_2_can_bw);
+    }
+
+    if(fd_eth_2_can_latency)
+    {
+        close(fd_eth_2_can_latency);
+    }
+
+    if(fd_eth_2_can_bw)
+    {
+        close(fd_eth_2_can_bw);
+    }

    return exit_application(exit_status);
}