Commit e3f72058 authored by Dimitris Lampridis's avatar Dimitris Lampridis

[doc] document fw devel

parent 62d3df83
......@@ -117,9 +117,9 @@ Other than that, the only requirement on the hardware is that it supports `White
If you are designing your own board and you would like to have something as a reference, here's a
few open-source boards that already support WR:
* `SPEC <https://www.ohwr.org/projects/spec>`_ (Xilinx Spartan6 FPGA)
* `FASEC <https://www.ohwr.org/projects/fasec>`_ (Xilinx Zynq SoC FPGA)
* `VFC-HD <https://www.ohwr.org/projects/vfc-hd>`_ (Intel Arria V)
* `SPEC <https://www.ohwr.org/projects/spec/wikis>`_ (Xilinx Spartan6 FPGA)
* `FASEC <https://www.ohwr.org/projects/fasec/wikis>`_ (Xilinx Zynq SoC FPGA)
* `VFC-HD <https://www.ohwr.org/projects/vfc-hd/wikis>`_ (Intel Arria V)
All of the above examples make use of the `WR PTP Core
<https://www.ohwr.org/project/wr-cores/wikis/wrpc-core>`_ inside their FPGA.
......@@ -129,7 +129,178 @@ All of the above examples make use of the `WR PTP Core
Gateware
========
There is no HDL template yet for WRTD gareware development. Users who need to develop WRTD gateware
for a new :ref:`node` are advised to use the top-level VHDL modules of the :ref:`ref_nodes` as a
starting point. Their source code is available on the WRTD Git repository:
https://www.ohwr.org/project/wrtd/tree/master/hdl/top
Every :ref:`node` should include at a minimum an instance of `MockTurtle
<https://www.ohwr.org/project/mock-turtle/wikis/home>`_ and the `WR PTP Core
<https://www.ohwr.org/project/wr-cores/wikis/wrpc-core>`_.
Furthermore, the MockTurtle configuration should define at least one *Host Message Queue* per CPU,
for communication between the WRTD library and the WRTD :ref:`application` running on the CPU, as
well as one *Remote Message Queue* per CPU for conencting the WRTD :ref:`application` to the WR
network.
Every :ref:`node` should also include a *MockTurtle Ethernet Endpoint*, to interface the *Remote
Message Queue* of the MockTurtle with the *Fabric Interface* of the WR PTP Core. If in doubt, have a
look at how these three modules are instantiated and connected to each other in the
:ref:`ref_nodes`.
.. _fw_dev:
Firmware
========
WRTD provides a common firmware development framework for :ref:`Applications <application>`. To use
it, users must also use a compatible :ref:`gw_dev`.
Similar to :ref:`gw_dev` development, users are advised to use the firmware of the :ref:`ref_nodes`
as a starting point:
https://www.ohwr.org/project/wrtd/tree/master/software/firmware
Setup
-----
To start developing firmware for WRTD, users must first include the relevant header file:
.. code-block:: c
#include "wrtd-rt-common.h"
Users must also describe the various features of their application, by means of C preprocessor
directives. The following needs to be copied to the application source code and adjusted as
necessary:
.. code-block:: c
/* Number of MockTurtle CPUs. */
#define NBR_CPUS xxx
/* Index of this CPU. */
#define CPU_IDX xxx
/* Maximum number of Rules allowed */
#define NBR_RULES xxx
/* Maximum number of Alarms allowed */
#define NBR_ALARMS xxx
/* Number of Devices. A "Device" is a unidirectional set
of Local Channels.
Most Applications will have one Device per direction (in/out).
Maximum allowed number of Devices = 4. */
#define NBR_DEVICES xxx
/* Number of Local Channels per Device. */
#define DEVICES_NBR_CHS { xxx, 0, 0, 0}
/* Direction of Local Channels per Device. Direction can be either
WRTD_CH_DIR_IN (from the environment to WRTD) or
WRTD_CH_DIR_OUT (from WRTD to the environment). */
#define DEVICES_CHS_DIR { WRTD_CH_DIR_IN, 0, 0, 0}
/* A unique number to identify this Application. */
#define APP_ID xxx
/* Application version (major, minor). */
#define APP_VER RT_VERSION(xxx, yyy)
/* A string name for this Application. */
#define APP_NAME xxx
/* 1 if the Application can receive Events over the network,
0 otherwise. */
#define WRTD_NET_RX x
/* 1 if the Application can send Events over the network,
0 otherwise. */
#define WRTD_NET_TX x
/* 1 if the Application can receive Events from Local Channels,
0 otherwise. */
#define WRTD_LOCAL_RX x
/* 1 if the Application can send Events to Local Channels,
0 otherwise. */
#define WRTD_LOCAL_TX x
Apart from the preprocessor definitions, users must also provide implementations for a set of
functions. These include:
* :ref:`fw_api_init`
+ :cpp:func:`wrtd_user_init`
+ :cpp:func:`wrtd_io`
* :ref:`fw_api_wr_link`
+ :cpp:func:`wr_link_up`
+ :cpp:func:`wr_time_ready`
+ :cpp:func:`wr_enable_lock`
+ :cpp:func:`wr_time_locked`
+ :cpp:func:`wr_sync_timeout`
* :ref:`fw_api_event_in`
+ :cpp:func:`wrtd_local_output`
.. _fw_api_init:
Initialisation and Main Loop
----------------------------
WRTD firmware runs in a continuous loop. All such code should be put in the :cpp:func:`wrtd_io`
function. Additionally, the :cpp:func:`wrtd_user_init` offers the possibility to execute code once,
after reset, before entering the main execution loop.
.. doxygenfunction:: wrtd_user_init
.. doxygenfunction:: wrtd_io
.. _fw_api_wr_link:
WR Link Control and Status
--------------------------
It is expected (but not required) that WRTD firmware has access to the WR link. In particular, most
applications should be able to detect whether the link is up, the timecode is valid, etc. The way
this is done is application-specific. The following functions allow users to describe how this is
done.
.. doxygenfunction:: wr_link_up
.. doxygenfunction:: wr_time_ready
.. doxygenfunction:: wr_enable_lock
.. doxygenfunction:: wr_time_locked
.. doxygenfunction:: wr_sync_timeout
Event I/O
---------
Ultimately, the purpose of a WRTD firmware is to relay :ref:`Events <event>` from/to the outside
world.
Internally, WRTD represents an Event using the :cpp:class:`wrtd_event` structure.
.. doxygenstruct:: wrtd_event
:members:
.. _fw_api_event_in:
Sending Events
++++++++++++++
When an incoming :ref:`Event <event>` has been matched to a :ref:`rule` with a :ref:`local_channel`
output, WRTD will call the user-provided :cpp:func:`wrtd_local_output` function. This function
should perform all the application-specific actions to program the relevant :ref:`local_channel` to
generate the actual output.
.. doxygenfunction:: wrtd_local_output
.. _fw_api_event_out:
Receiving Events
++++++++++++++++
Receiving an :ref:`event` is also application-specific. The monitoring of :ref:`local_channel`
inputs is typically done periodically in the main execution loop, using the :cpp:func:`wrtd_io`
function.
Once the firmware detects in incoming :ref:`event` and fills in a :cpp:class:`wrtd_event` structure,
it should simply pass this to WRTD using the :cpp:func:`wrtd_route_in` function. The rest (rule
matching, event forwarding, etc.) will be handled by WRTD.
.. doxygenfunction:: wrtd_route_in
.. hint:: Contrary to the rest of the functions presented in :numref:`fw_dev`,
:cpp:func:`wrtd_route_in` is not a user-defined function. It is provided by WRTD. Users
should simply call this function whenever an incoming :ref:`event` is detected.
......@@ -10,6 +10,9 @@ OPTIMIZE_OUTPUT_FOR_C = YES
EXTRACT_STATIC = YES
CASE_SENSE_NAMES = YES
ENABLE_PREPROCESSING = YES
PREDEFINED = WRTD_NET_RX
WARN_NO_PARAMDOC = YES
WARN_IF_UNDOCUMENTED = NO
......
......@@ -36,14 +36,78 @@
/* By default use lxi-evntsvc. */
#define WRTD_UDP_PORT 5044
/* Functions defined by the user. */
/* The following functions are application-specific and need to be defined by the user. */
/**
* Check whether the WR link is up or not.
*
* If the application does not need this, write a function that returns always ``1``.
*
* @return ``1`` if true, ``0`` otherwise.
*/
static int wr_link_up(void);
/**
* Check whether the application is locked to the WR clock or not.
*
* If the application does not need this, write a function that returns always ``1``.
*
* @return ``1`` if true, ``0`` otherwise.
*/
static int wr_time_locked(void);
/**
* Check whether the WR time is valid.
*
* If the application does not need this, write a function that returns always ``1``.
*
* @return ``1`` if true, ``0`` otherwise.
*/
static int wr_time_ready(void);
/**
* Enable/disable locking of the application to the WR clock.
*
* If the application does not need this, write a function that does nothing.
*
* @param[in] enable set to ``1`` to enable, set to ``0`` to disable.
*/
static void wr_enable_lock(int enable);
/**
* Generate an output Event on a Local Channel.
*
* If the application does not need this, write a function that returns always ``0``.
*
* @param[in] ev pointer to a struct wrtd_event, representing the Event to send.
* @param[in] ch Local Channel number to use.
* @return ``0`` on success, or error code otherwise.
*/
static int wrtd_local_output(struct wrtd_event *ev, unsigned ch);
/**
* Return the delay in seconds that the application should wait before
* considering the WR link synced.
*
* If the application does not need this, write a function that returns always ``0``.
*
* @return Integer number of seconds to wait.
*/
static int wr_sync_timeout(void);
/**
* Function to perform any apllication-specific initialisation (runs once after reset).
*
* If the application does not need this, write a function that returns always ``0``.
*
* @return ``0`` on success, or error code otherwise.
*/
static int wrtd_user_init(void);
/**
* Function to perform the main tasks of the application. This will run in a loop.
*
* Typically the application will check here for incoming Events and pass them to
* WRTD via the wrtd_route_in() function. It might also want to check if output
* Events previously scheduled via wrtd_local_output() have been executed or not.
*
* If the application does not need this, write a function that returns always ``0``.
*
* @return ``0`` on success, or error code otherwise.
*/
static void wrtd_io(void);
/* Forward function declarations. */
......@@ -504,8 +568,12 @@ static void wrtd_route(struct wrtd_rule *rule, const struct wrtd_event *ev)
while (0);
}
/**
* Route an event coming from a Local Input, Network, or Alarm.
*
* @param[in] ev pointer to a struct wrtd_event, representing the received Event.
*/
#if WRTD_LOCAL_RX > 0 || WRTD_NET_RX > 0 || NBR_ALARMS > 0
/* Route an event coming from a local input, network, or alarm. */
static void wrtd_route_in(struct wrtd_event *ev)
{
struct wrtd_rule *rule;
......
......@@ -34,6 +34,9 @@ typedef struct wrtd_tstamp {
uint32_t frac;
} wrtd_tstamp;
/**
* WRTD Event
*/
struct wrtd_event {
/** Time of the event. */
struct wrtd_tstamp ts;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment