Author: Exoligent’s Team
Description: The document's description

# UAFIP TSN Gateway : User’s Guide

Exoligent’s Team
info@exoligent.com
version v1.0.0, 2025-10-16

## 1. Disclaimer

Information contained in this publication regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. EXOLIGENT MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Exoligent disclaims all liability arising from this information and its use. Use of Exoligent devices in life support and/or safety applications is entirely at the buyer’s risk, and the buyer agrees to defend, indemnify and hold harmless Exoligent from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Exoligent intellectual property rights unless otherwise stated.

Exoligent SARL
390 rue d’Estienne d’Orves, 92700 Colombes - France
Tel: +33(0) 1 42 42 42 00
Web Site: https://www.exoligent.com/
Copyright © 2022 Exoligent SARL. All rights reserved.

## 2. Introduction

UAFIP is an open-source software gateway written in C for GNU/Linux operating system whose goal is to create a deterministic gateway between the WorldFIP fieldbus protocol (IEC 61158) and the OPC UA over TSN (IEC 62541) standard for data exchange. This user guide serves as starting point for a user to learn, install and configure this gateway for embedding into their products.

| This document is partly based on the very good guide from Kalycito: How to run OPC UA PubSub on real-time Linux and TSN

The structure of the UAFIP TSN gateway is divided into three entities:

- Configurator: json-c – an open-source C JSON parser licensed under MIT (github)

- OPC UA stack: open62541 – an open-source C (C99) implementation of OPC UA licensed under the Mozilla Public License v2.0 (github)

- WorldFIP stack: powerfip – a C communication stack to interface with the Exoligent’s FIP coprocessor (doc)

Figure 1. UAFIP software gateway (Principle Diagram)

## 3. Prerequisites

### 3.1. Hardware requirements

- x86-based system

  - 4-cores

  - Intel i210 Ethernet controller (as this controller supports features necessary for Time-Sensitive Networking)

  - 1 x PCIe slot or 1 x mPCIe slot

- FIP controller

  - PowerFIP Exoligent’s board (mPCIe and its derivatives)

We used Advantech’s UNO-1483G during our tests.

### 3.2. Software requirements

- Debian GNU/Linux 10 and more

  - Pre-compiled real-time kernel

  - A later version of iproute2 package (with support for newer real-time socket options and an IEEE 802.1 Qbv like scheduler)

  - A later version of LinuxPTP package (with support for IEEE 802.1 AS gPTP configuration)

- FIP library/kernel module + UAFIP TSN gateway sources (see last PowerFIP Package)

We used Debian GNU/Linux 11 (bullseye) with PREEMPT-RT 5.10.0-14-rt-amd64 kernel during our tests

| We selected Debian 11, as it is one of the more popular distributions. It also has a pre-compiled real-time kernel that can be installed using the Debian package manager. As it is not practically possible to provide a variant of the userguide for the many Linux distributions out there, we recommend that you use Debian for your initial tests and then switch to your chosen distribution.

## 4. Environment setup

In this section, we will set up the environment:

- Install real-time Linux kernel

- Install FIP controller

- Configure Ethernet network interface

- Configure TSN parameters

- Build UAFIP TSN gateway

### 4.1. Install real-time Linux Kernel

After installing the OS, update the node using the below command:

    $ sudo apt-get update && apt-get upgrade

It might take a while for the update and upgrade to complete. You can then download and install the real-time kernel that is distributed by Debian and reboot the node using the below commands:

    $ sudo apt-get install linux-image-rt-amd64 -y
    $ sudo reboot

After reboot, execute the below command and ensure that the newly installed real-time kernel is the one that is currently running.
The appearance of the “rt” keyword in the print message that appears as part of the command output shows that we have booted into the right kernel:

    $ uname -r

    5.10.0-14-rt-amd64

### 4.2. Install FIP controller

In this section, we will install FIP controller on your machine.

Once the real time Linux kernel is installed, shutdown your system and plug a PowerFIP PCIe card into a suitable slot

After reboot and log in user, download the archive of the latest version of the library from the Exoligent website (Download section) or get it from the following linux command (here the example is for the v1.4.0 package):

    $ cd ~/Documents
    $ wget https://www.exoligent.com/wiki/worldfip/pwrfip/download/1.4.0/powerfip-1.4.0-linux.tar.gz
    $ tar xzvf powerfip-1.4.0-linux.tar.gz
    $ cd powerfip-1.4.0-linux

Build and install the kernel module for FIP controller:

    $ cd ~/Documents/powerfip-1.4.0-linux/driver/linux
    $ make
    $ sudo ./install.sh

If you have a PowerFIP PCIe device connected to your machine, you should get the following console trace with the dmesg command:

    $ dmesg

    [78983.022874] powerfip: ==> Init
    [78983.022934] powerfip: ==> Device probing
    [78983.023186] powerfip: BAR 0 (0xf6000000 - 0xf6000fff), len = 4096, flags = 0x040200
    [78983.023205] powerfip: BAR 1 (0xf4000000 - 0xf5ffffff), len = 33554432, flags = 0x040200
    [78983.023883] powerfip: DMA Capability = YES
    [78983.023887] powerfip: MSI Capability = YES
    [78983.023888] powerfip: IRQ pin  = #1 (0=none, 1=INTA#...4=INTD#)
    [78983.023890] powerfip: IRQ line = #69
    [78983.023891] powerfip: IRQ vectors = 4

Now, install FIP firmware and library:

    $ cd ../../
    $ sudo ./install.sh

| Following files will be copied to your system `powerfip-firmware.bin` file to the path: /usr/local/lib/firmware `libpowerfip.a` and `libpowerfip.so` files to the path: /usr/local/lib `header (*.h)` files to the path: /usr/local/include/powerfip

The FIP controller is now ready for operation! If you want to test it, refer you to the turnkey examples in the `tools/` directory of the distribution.

### 4.3. Configure Ethernet network interface

In this section, we will set up static IP address and VLAN configuration to the i210 interface. Open the interfaces file using the below commands:

    $ sudo nano /etc/network/interfaces

Copy and paste the following lines at the end of the interfaces file in both the nodes and replace “X” as shown in the screenshot below and save the file. E.g., In node 1 (ex: ua_pong node example), set the IP address as 192.168.100.1, and in node 2 (ex: uafip tsn gateway node), set the IP address as 192.168.100.2. The PubSub TSN applications are configured to run with VLAN Id 8. For this purpose, VLAN configuration is done in the i210 interface as below:

    auto enp7s0
    iface enp7s0 inet static
        address 192.168.100.X
        netmask 255.255.255.0
        broadcast 192.168.100.255
    auto enp7s0.8
    iface enp7s0.8 inet static
        address 192.168.8.X
        netmask 255.255.255.0

Throughout this QSG we will be using enp7s0 for the interface name, replace it with your nodes’ i210 interface name.

Below is the screenshot of the interfaces files of the two nodes:

Save the interfaces file and restart the networking service:

    $ sudo /etc/init.d/networking restart

Now verify the static IP address and the connection between two nodes (from node 1 ping node 2 and vice versa) using the below commands:

    $ ip a

    [...]

    3: enp7s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdpgeneric/id:34 qdisc mqprio state UP group default qlen 1000
        link/ether 74:fe:48:30:39:eb brd ff:ff:ff:ff:ff:ff
        inet 192.168.100.2/24 brd 192.168.100.255 scope global enp7s0
           valid_lft forever preferred_lft forever
        inet6 fe80::76fe:48ff:fe30:39eb/64 scope link
           valid_lft forever preferred_lft forever

    [...]

    $ ping 192.168.100.X

### 4.4. Configure TSN parameters

In this section, we will run some scripts from the Kalycito company (setup.sh, application_dependencies.sh) to configure the TSN parameters.
The setup.sh available in the package does the following,

- Updates the installed packages in the node

- Installs iproute2 package for kernel version 5.10

- Installs Linux PTP version 2.0

- Checks if 8021q module is loaded; if not, adds the same

The application_dependencies.sh available in the package does the following,

- Configures traffic control parameters to transmit and receive

- Sets Egress and Ingress policies

- Tunes real-time behaviors

- Runs Linux PTP and PHC2SYS

- Kernel mechanism to allocate CPU to the processes

The above scripts are included in the powerfip package. To access them, go to the kalycito directory, and run the setup.sh script using the below command:

    $ cd ~/Documents/powerfip-1.4.0-linux/tools/uafip_tsn_gateway/scripts/kalycito
    $ sudo ./setup.sh

| We have modified the grub settings, so reboot is required.

Reboot the nodes after completing the initial setup

    $ sudo reboot

Run PTP and PHC2SYS

  After the reboot, run the application_dependencies.sh. As shown in the architecture diagram, configure one of the nodes as PTP master and the other node as PTP slave.

To configure the node as PTP master use the below command:

    $ cd ~/Documents/powerfip-1.4.0-linux/tools/uafip_tsn_gateway/scripts/kalycito
    $ sudo ./application_dependencies.sh -i enp2s0 -m

To configure the node as PTP slave use the below command:

    $ sudo ./application_dependencies.sh -i enp2s0 -s

After configuring the node as PTP master or slave, the output log can be verified using the below command:

    $ tail -f /var/log/ptp4l.log

If you have configured your node as a PTP master, your output log should be similar to the below image. The text “assuming the grand master role” ensures that you have configured the node as PTP master. Once you have seen the output, press Ctrl + C to return to the console.

    $ tail -f /var/log/ptp4l.log

      ptp4l[3194.498]: port 1: link up
      ptp4l[3194.558]: port 1: FAULTY to LISTENING on INIT_COMPLETE
      ptp4l[3205.493]: port 1: LISTENING to MASTER on ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES
      ptp4l[3205.493]: selected local clock 74fe48.fffe.42c2e4 as best master
      ptp4l[3205.493]: port 1: assuming the grand master role

If you have configured your node as a PTP slave, your output log should be similar to the below image.

| The master offset values are represented in nanosecond (ns). This value should be within the range of -1000 ns to +1000 ns

    $ tail -f /var/log/ptp4l.log

      ptp4l[4527.664]: master offset          4 s2 freq  +39804 path delay       -17
      ptp4l[4527.789]: master offset          5 s2 freq  +39806 path delay       -17
      ptp4l[4527.914]: master offset          0 s2 freq  +39799 path delay       -17
      ptp4l[4528.039]: master offset          0 s2 freq  +39799 path delay       -17
      ptp4l[4528.165]: master offset         -6 s2 freq  +39791 path delay       -17
      ptp4l[4528.290]: master offset         -4 s2 freq  +39793 path delay       -17

The application_dependencies.sh would have run PHC2SYS utility to synchronize user clock and hardware clock. You can verify the output log of PHC2SYS in both the nodes using the below command:

    $ tail -f /var/log/phc2sys.log

Your PHC2SYS log should be similar to the below image.

| The sys offset values are represented in nanosecond (ns). This value should be within the range of -1000 ns to +1000 ns

Once you have seen the output, press Ctrl + C to return to the console.

### 4.5. Build UAFIP TSN gateway

#### 4.5.1. XDP Pre-requisties

XDP (Express Data Path) is used by the gateway subscriber for faster processing the data.

| For our test with the Debian 11 OS (5.10.0-14-rt-amd64) we use the bpf library v0.3.

To build and install libbpf library, use the following commands:

    $ sudo apt install llvm
    $ sudo apt install clang

    $ cd ~/Documents
    $ git clone https://github.com/libbpf/libbpf.git
    $ cd libbpf/
    $ git checkout 051a4009f94d5633a8f734ca4235f0a78ee90469
    $ cd src/
    $ sudo OBJDIR=/usr/lib make install

#### 4.5.2. Build open62541

    $ sudo apt install build-essential gcc pkg-config cmake python

    $ cd ~/Documents
    $ wget https://github.com/open62541/open62541/archive/refs/tags/v1.3.tar.gz -O open62541-1.3.0.tar.gz
    $ tar xzvf open62541-1.3.0.tar.gz
    $ cd open62541-1.3.0
    $ mkdir build
    $ cd build
    $ cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DOPEN62541_VERSION=v1.3.0 -DUA_ENABLE_PUBSUB=ON -DUA_ENABLE_PUBSUB_ETH_UADP=ON -DUA_ENABLE_MALLOC_SINGLETON=ON -DUA_ENABLE_IMMUTABLE_NODES=ON -DUA_ENABLE_PUBSUB_INFORMATIONMODEL=ON -DUA_MULTITHREADING=150
    $ make
    $ sudo make install

#### 4.5.3. Build the gateway

    $ sudo apt install libjson-c-dev

    $ cd ~/Documents/powerfip-1.4.0-linux/tools/uafip_tsn_gateway
    $ make

#### 4.5.4. Start the gateway

    $ cd ~/Documents/powerfip-1.4.0-linux/tools/uafip_tsn_gateway
    $ sudo setcap cap_sys_nice+ep uafipd
    $ ./uafipd -f ./config/2sta/sta1.json

#### 4.5.5. Install the gateway as a daemon

Install UAFIP gateway as a daemon:

    $ cd ~/Documents/powerfip-1.4.0-linux/tools/uafip_tsn_gateway/svc/
    $ sudo ./install_svc.sh

    Created symlink /etc/systemd/system/multi-user.target.wants/uafipd.service → /etc/systemd/system/uafipd.service.

Once installed, you can manipulate the daemon with the classic commands of systemd:

Daemon status:

    $ sudo systemctl status uafipd

    ● uafipd.service - OPC UA Pub/Sub TSN <-> FIP/WorldFIP gateway
         Loaded: loaded (/etc/systemd/system/uafipd.service; enabled; vendor preset: enabled)
         Active: active (running) since Fri 2022-06-10 15:01:52 CEST; 59s ago
       Main PID: 5910 (uafipd)
          Tasks: 5 (limit: 9383)
         Memory: 3.6M
            CPU: 1.241s
         CGroup: /system.slice/uafipd.service
                 └─5910 /usr/bin/uafipd -f /etc/exoligent/uafip/config/performance/sta1.json -L /var/log/uafipd.log

Stop the daemon:

    $ sudo systemctl stop uafipd

Start the daemon:

    $ sudo systemctl start uafipd

Enable the daemon at system startup:

    $ sudo systemctl enable uafipd

    Created symlink /etc/systemd/system/multi-user.target.wants/uafipd.service → /etc/systemd/system/uafipd.service.

Disable the daemon at system startup:

    $ sudo systemctl disable uafipd

    Removed /etc/systemd/system/multi-user.target.wants/uafipd.service.

## 5. Gateway configuration

The UAFIP TSN gateway can be configured using a JSON file. The OPC PUB/SUB parameters are defined there as well as the parameters of the embedded FIP node.

Example of UAFIP gateway configuration file (config/ping/uno/sta1.json)

    {
      "opc": {
        "publisher" : {
          "network_interface":"enp7s0",
          "url":"opc.eth://74-fe-48-42-c2-e4:8.3",
          "publisher_id":"5671",
          "dataset_writer_id":"62541",
          "writer_group_id":"101",
          "publish_period_us":"250"
        },
        "subscriber" : {
          "network_interface":"enp7s0",
          "url":"opc.eth://74-fe-48-30-39-eb:8.3",
          "publisher_id":"5670",
          "dataset_writer_id":"62541",
          "writer_group_id":"100"
        }
      },
      "fip": {
        "name":"FIP node 1",
        "address":"1",
        "segment":"0",
        "frame_type":"worldfip",
        "bitrate":"1mbps",
        "turn_around_us":"30",
        "silence_us":"150",
        "vars": [
          {
            "name":"[0x3800]",
            "type":"cons",
            "id":"0x3800",
            "payload_bsz":"8",
            "refreshment":"yes",
            "promptness":"yes",
            "prompt_us":"7500",
            "event":"none"
          },
          {
            "name":"[0x3801]",
            "type":"prod",
            "id":"0x3801",
            "payload_bsz":"8",
            "refreshment":"yes",
            "refresh_us":"7500",
            "event":"none"
          },
          {
            "name":"[0xFF00]",
            "type":"sync",
            "id":"0xFF00",
            "event":"w_op"
          },
          {
            "name":"[0xFF01]",
            "type":"sync",
            "id":"0xFF01",
            "event":"r_op"
          }
        ]
      }
    }

| See appendix `sta0.json` to get a gateway configuration example with a master FIP node (Bus Arbiter enabled).

The JSON file is a data tree structure composed of nodes (containers) and leaves (data).
Below is a description of the layout of the containers and [arrays]:

- opc

  - publisher

    - network_interface, (…​)

  - subcriber

    - network_interface, (…​)

- fip

  - name, (…​), [vars]

    - name, (…​)

  - bus_arbiter

    - enable, (…​), [cycles]

      - [windows]

        - type, (…​)

        - [requests] (only inside periodic window)

          - type, (…​)

Name | Status | Type | Description
--- | --- | --- | ---
opc | required | object | OPC-UA configuration container
publisher | required | object | OPC-UA PUB container
network_interface | required | string | Publisher network interface
url | required | string | Publisher MAC address ex: opc.eth://74-fe-48-30-39-eb:8.3 (where 8 is the VLAN ID and 3 is the PCP) ex: opc.udp://224.0.0.32:4840/ (multicast address)
publisher_id | required | u16 | Unique ID for a publisher with the message-oriented middleware
dataset_writer_id | required | u16 | The dataset writer Id identifies the dataset writer in the writer group. It is unique across all dataset writers for a publisher ID
writer_group_id | required | u16 | Writer Group Identifier. It is unique across writer groups for a publisher ID
publish_period_us | required | u32 | Publisher cycle time in microseconds
subscriber | required | object | OPC-UA SUB container
network_interface | required | string | Subscriber network interface
url | required | string | Subscriber MAC address ex: opc.eth://74-fe-48-42-c2-e4:8.3 (where 8 is the VLAN ID and 3 is the PCP) ex: opc.udp://224.0.0.22:4840/ (multicast address)
publisher_id | required | u16 | Unique ID of the publisher to subscribe to
dataset_writer_id | required | u16 | Dataset Writer ID to subscribe to
writer_group_id | required | u16 | Writer Group ID to subscribe to
fip | required | object | FIP configuration container
name | optional | string | FIP node identification label
address | required | u8 | FIP node physical address
segment | required | u8 | FIP node segment number
frame_type | required | enum | Values: worldfip WorldFIP frame encoding type (IEC [International Electrotechnical Commission]) fip FIP frame encoding type (UTE [Union Technique de l'Electricité])
bitrate | required | enum | Values: 31.25kbps FIP/WorldFIP bitrate at 31.25Kbps 1mbps FIP/WorldFIP bitrate at 1Mbps 2.5mbps FIP/WorldFIP bitrate at 2.5Mbps 5mbps FIP/WorldFIP bitrate at 5Mbps 12.5mbps FIP/WorldFIP bitrate at 12.5Mbps [experimental] 25mbps FIP/WorldFIP bitrate at 25Mbps [experimental]
turn_around_us | required | u32 | Turn-Around time in microseconds
silence_us | required | u32 | Silence time in microseconds
vars | optional | array | Array of FIP variables configuration
name | optional | string | FIP variable identification label
type | required | enum | Values: cons Input FIP variable (consumed) prod Output FIP variable (produced)
id | required | u16 | Unique identifier of a FIP variable
payload_bsz | required | u16 | FIP variable payload size in bytes
| Only significant for FIP prod and cons variable type.
refreshment | optional | boolean | Enable/Disable the production status byte (refreshement) for the FIP variable
refresh_us | optional | u32 | Refreshment period in microseconds
| Only significant for FIP prod variable type.
promptness | optional | boolean | Enable/Disable the promptness status for a FIP consumed variable
| Only significant for FIP cons variable type.
prompt_us | optional | u32 | Promptness period in microseconds
| Only significant for FIP cons variable type.
event | optional | enum | Values: none No FIP event attached to the variable r_op Read operation of the FIP variables by the gateway w_op Write operation of the FIP variables by the gateway rw_op Read and write operation of the FIP variables by the gateway
bus_arbiter | optional | object | FIP master configuration container
enable | required | boolean | Enable/Disable bus arbiter (master) capability
priority | required | u8 | Should be in [0..15] range (0: highest priority)
cycles | required | array | Array of Fip master macrocycles
windows | required | array | Array of BA windows inside a macrocycle
type | required | enum | Values: periodic Periodic BA window aperiodic_var Aperiodic Variable BA window aperiodic_msg Aperiodic Message BA window wait Internal Resync waiting BA window
end_ustime | optional | u32 | End time of the aperiodic BA window in microseconds
| Only significant for aperiodic_var, aperiodic_msg and wait BA window types
| The end time is relative to the first macrocycle operation
requests | optional | array |
| Only significant for periodic BA window type
type | required | enum | Values: id_dat FIP variable BA request id_msg FIP message BA request
id | required | u16 | FIP identifier to request during a periodic BA window

## 6. Ping-Pong example

Figure 2. Ping/Pong Test (Principle Diagram)

The "ping-pong" example is a test between a FIP master node (BA) and an OPC-UA node (client) where an UAFIP TSN gateway acts as an intermediary between the two heterogeneous nodes.

1. The FIP node increments a PING counter (64-bit value) at each macrocycle and produces a RP_DAT[0x3800] FIP frame with the updated counter to the FIP network.

2. This FIP data is consumed by the UAFIP gateway and is transfered via an OPC-UA publisher to the Ethernet network.

3. A remote OPC-UA node (client) subscribes to the gateway’s publisher and returns this value by republishing it (PONG counter).

4. The gateway in turn consumes this OPC value via a subscriber and produces a RP_DAT[0x3801] FIP frame with the updated PONG counter (64-bit value).

5. At each new macrocycle, the FIP node consumes the RP_DAT[0x3801] data [PONG] and compares it to the new value of the RP_DAT[0x3800] variable to be produced [PING].
   If the real time capacity of the whole system is maintained, the difference between the consumed and produced counters should never exceed 1 unit for the FIP node.

| In order to avoid cycle losses due to initial conditions, the starting order of the different nodes is important! You should start by launching UAFIP_GATEWAY, then UA_PONG and finally FIP_PING.

UAFIP_GATEWAY

    uno1483g@uno1483g:~/Documents/powerfip/tools/uafip_tsn_gateway$ sudo ./start_rt_gateway.sh "./uafipd -f ./config/ping/uno/sta1.json"

| Here we use the start_rt_gateway.sh script to start the gateway, locks the process to a specific CPU, and sets the scheduling policy. We configure the gateway using the config/ping/uno/sta1.json file (see its description `here`)

Console trace of the UAFIP TSN gateway started

UA_PONG

  Then, launch the OPC node which will play the PONG role with the command below:

    uno2372g@uno2372g:~/Documents/powerfip/tools/uafip_tsn_gateway/tools/ua_pong$ sudo ./ua_pong

| Make sure that the settings defined in the powerfip/tools/uafip_tsn_gateway/tools/ua_pong/test.h header file match those of the UAFIP gateway.

Console trace of the UA_PONG example started

FIP_PING

  Finally, launch the FIP node which will play the PING role with the command below:

    pctest@pctest:~/Documents/powerfip/tools/pwrfip_ping$ sudo ./pwrfip_ping -i 1 -n 0 -c 10000

| Here we use the parameters: -i 1: FIP device index number 1 -n 0: FIP node address 0 (.i.e: PING station) -c 10000: FIP macrocycle period of 10ms

Console trace of the FIP_PING example started

If all goes well, the bus arbiter should start and the ping/pong `ok` counter start to increment. No loss of FIP macrocycle occurs while the `nok` counter remains at 0.

## Appendix A: JSON files examples

### A.1. Ping (FIP Node 0)

config/ping/uno/sta0.json

    {
      "opc": {
        "publisher" : {
          "network_interface":"enp2s0",
          "url":"opc.eth://74-fe-48-30-39-eb:8.3",
          "publisher_id":"5670",
          "dataset_writer_id":"62541",
          "writer_group_id":"100",
          "publish_period_us":"250"
        },
        "subscriber" : {
          "network_interface":"enp2s0",
          "url":"opc.eth://74-fe-48-42-c2-e4:8.3",
          "publisher_id":"5671",
          "dataset_writer_id":"62541",
          "writer_group_id":"101"
        }
      },
      "fip": {
        "name":"FIP node 0",
        "address":"0",
        "segment":"0",
        "frame_type":"worldfip",
        "bitrate":"1mbps",
        "turn_around_us":"30",
        "silence_us":"150",
        "vars": [
          {
            "name":"[0x3800]",
            "type":"prod",
            "id":"0x3800",
            "payload_bsz":"8",
            "refreshment":"yes",
            "refresh_us":"7500",
            "event":"none"
          },
          {
            "name":"[0x3801]",
            "type":"cons",
            "id":"0x3801",
            "payload_bsz":"8",
            "refreshment":"yes",
            "promptness":"yes",
            "prompt_us":"7500",
            "event":"none"
          },
          {
            "name":"[0xFF00]",
            "type":"sync",
            "id":"0xFF00",
            "event":"r_op"
          },
          {
            "name":"[0xFF01]",
            "type":"sync",
            "id":"0xFF01",
            "event":"w_op"
          }
        ],
        "bus_arbiter": {
          "enable":"yes",
          "priority":"1",
          "cycles": [
            {
              "windows": [
                {
                  "type":"periodic",
                  "requests": [
                    {
                      "type":"id_dat",
                      "id":"0x3800"
                    },
                    {
                      "type":"id_dat",
                      "id":"0xFF00"
                    }
                  ]
                },
                {
                  "type":"wait",
                  "end_ustime":"2500"
                },
                {
                  "type":"periodic",
                  "requests": [
                    {
                      "type":"id_dat",
                      "id":"0x3801"
                    },
                    {
                      "type":"id_dat",
                      "id":"0xFF01"
                    }
                  ]
                },
                {
                  "type":"wait",
                  "end_ustime":"5000"
                }
              ]
            }
          ]
        }
      }
    }

### A.2. Pong (FIP Node 1)

config/ping/uno/sta1.json

    {
      "opc": {
        "publisher" : {
          "network_interface":"enp7s0",
          "url":"opc.eth://74-fe-48-42-c2-e4:8.3",
          "publisher_id":"5671",
          "dataset_writer_id":"62541",
          "writer_group_id":"101",
          "publish_period_us":"250"
        },
        "subscriber" : {
          "network_interface":"enp7s0",
          "url":"opc.eth://74-fe-48-30-39-eb:8.3",
          "publisher_id":"5670",
          "dataset_writer_id":"62541",
          "writer_group_id":"100"
        }
      },
      "fip": {
        "name":"FIP node 1",
        "address":"1",
        "segment":"0",
        "frame_type":"worldfip",
        "bitrate":"1mbps",
        "turn_around_us":"30",
        "silence_us":"150",
        "vars": [
          {
            "name":"[0x3800]",
            "type":"cons",
            "id":"0x3800",
            "payload_bsz":"8",
            "refreshment":"yes",
            "promptness":"yes",
            "prompt_us":"7500",
            "event":"none"
          },
          {
            "name":"[0x3801]",
            "type":"prod",
            "id":"0x3801",
            "payload_bsz":"8",
            "refreshment":"yes",
            "refresh_us":"7500",
            "event":"none"
          },
          {
            "name":"[0xFF00]",
            "type":"sync",
            "id":"0xFF00",
            "event":"w_op"
          },
          {
            "name":"[0xFF01]",
            "type":"sync",
            "id":"0xFF01",
            "event":"r_op"
          }
        ]
      }
    }

## Appendix B: Glossary of acronyms

BA | Bus Arbiter
FIP | Factory Instrumentation Protocol
OPC-UA | Open Platform Communications Unified Architecture
TSN | Time-Sensitive Networking

## Appendix C: Revision History

Revision | Changes | Authors | Date
--- | --- | --- | ---
1.0.0 | First version | MC | 2025-10-16