CAN-Ethernet Gateway demo

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.

Changes over previous release

Note : The document still refers to j721e/J721E in many places where folder paths are mentioned, please replace with j7200/J7200 as needed for DRA821.

Assumptions and Prerequisities

Assumptions

Hardware

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

Software

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/J7200 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 Jacinto device along with the accompanying remote switch driver, which runs on the Main_Cortex_R5_0_0 core.

Software Features

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

This contains two folders :

Users must run either the can_traffic_generator app or the default sciclient test application for regular demo. For Out of Box configuration, users must run the can_traffic_generator application.

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

Components

RTOS components:

Processor SDK RTOS drivers:

Building the Demos

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

Issue in Building

If you are building the applications for the first time or after a clean build then all PDK dependencies are built first. For can_eth_gateway_app MCU2_1 dependencies get built and for can_traffic_generator_app MCU1_0 dependencies.

Host Applications

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

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"

Running the regular demo

The regular 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.

J721E Board Setup

This demo uses MCAN4, MCAN9, and CPSW 9G's two ports (Port 2 and Port 3) on the GESI card. 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

J7200 Board Setup

The connections for J7200 are identical except the CPSW 9G ports which use the SGMII ports on the add on QSGMII add-on card. Shown below:

Picture of SGMII Eth connections on J7200 EVM

On J7200, the MCAN9 port is referred to as the MCAN8 port, but pins and wiring remains the same. The change is in the software.

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.

MCAN Setup

As shown in the picture below, connect the two USB-CAN analyzers to MCAN4 and MCAN8/9 instances, which are labeled as J30 and J32 respectively on the GESI card. The MCAN pin connection is as follows:

The following diagram shows the MCAN4 and MCAN9 connections on GESI card. MCAN8/9 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

Routing Table Architecture

Routing inside the gateway demo is now configurable, users can configure it as per their requirements.

This is achieved through the use of a simple lookup table inside the gateway application with 256 entries. Each entry has two masks, one for Ethernet and one for CAN.

The masks tell which ports are open for Transmit. So if Eth mask is set to 0 then no packets are sent out of any Ethernet port, same for CAN.

See figure below on how this is done.

J721E Demo setup graphic

Using the CAN ID as an index allows for O(1) lookup time.

Automated Test Framework

The framework has two parts

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.

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.

PCAN Linux driver installation and usage

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

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

Running the Automated Tests

There are four routes to test in the demo:

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 Running GUI section.

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

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 section to debug the issue.

Configuring the Routing Table

The routing table configuration is done automatically by the automation script. If you open run_demo.py file then you will see the following line.

sudo ./pctools/send_1722.out --eth_interface gateway_interfaces[3] --can_id gateway_interface_lut[gateway_interfaces[1]] --update_hash_table 1 --can_mask 0x1 --eth_mask 0x0

This line is used to configure the gateway for CAN 2 CAN routing such that CAN frames can only go out of the first port. No transmit from Ethernet ports is permitted.

The --can_id option is used to provide the CAN ID and --can_mask and --eth_mask are used to configure the Eth and CAN entries.

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 

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

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

Eth interface received frames for 	:  6218675.000000 us 

Script will now run Eth 2 Eth tests
-------------------ETH 2 ETH Test Results----------------------

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

Eth interface received frames for 	:  6432795.000000 us 

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 	:  16959 

1st interface of CAN received packets for 	:  5022384.000000 us 

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

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.

Running the GUI

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

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.

The GUI has run-time dependencies on the Open Framework module, to install them follow the steps below.

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.

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.

Do not use 0xAA as the first byte of any CAN message sent to CAN Eth Gateway as it's reserved for test automation

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

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

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

CAN to ETH

To do CAN-to-ETH routing, we need to configure the routing table appropriately as described in this section

To send on second Eth port, set the eth_mask field to 0x2. If sending on both Ethernet ports then eth_mask field should be 0x3. While doing CAN to Eth routing, can_mask should be 0 or else there will be CAN 2 CAN routing.

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

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

ETH to ETH

To do Eth to Eth routing there are two requirements.

Both these requirements are taken care of by the send_1722.c tool, which reads the app_config.txt configuration file to know the PC and gateway device MAC addresses. The second requirement to tell the device about the MAC ID of the PC is also taken care of by the send_1722.c tool.

To configure the MAC address on the device, use the following command (also present in run_demo.py)

sudo ./pctools/send_1722.out --eth_interface ``70:ff:76:1d:88:32`` --send_mac_address 1

Additionally user must configure the routing table by setting the can_mask to 0 and eth_mask to appropriate value based on routing requirement.

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.

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

ETH to CAN

To do Ethernet to CAN routing, we need to configure eth_mask and can_mask appropriately (see CAN to CAN section above) and 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

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

Load and Run the Demo

CCS Boot

For more details about installation of CCS and J721E/J7200 target creation, refer to the Processor SDK RTOS User's Guide inside "psdk_rtos/docs/user_guide" folder, which can be found in SDK installation.

OSPI Boot

OSPI boot is currently not functional for J721E, the alternative is to use CCS Boot. See (here)

Please edit the script gen_combined_image.sh as per your requirement as the paths may not match sometimes

Running the Out of Box Demo

The Out of Box demo is identical to the regular demo with the exception that no PCAN-USB devices are used. Hence it's much easier to setup.

To run the demo, the following connections need to be made

See the picture below on how connections are made with the help of two color coded jumper cable strips.

Out of Box Gateawy connections for CAN

Out of Box demo does not support GUI or Manual checking of the routes

Running the Low Latency Demo

See picture below regarding connections. The MCU MCAN0 and MCU MCAN1 ports are the same ones which are used for OOB demo, except that they are connected to PCAN devices now.

Out of Box Gateawy connections for CAN

Statistics

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

When a unit test is run, the test automation script automatically displays all the statistics from the test run.

Known issues & limitations

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);
}