Commit a9d7899e authored by Dimitris Lampridis's avatar Dimitris Lampridis

sw: remove deprecated lib-old

parent 407f25d7
# If it exists includes Makefile.specific. In this Makefile, you should put
# specific Makefile code that you want to run before this. For example,
# build a particular environment.
-include Makefile.specific
# include parent_common.mk for buildsystem's defines
# It allows you to inherit an environment configuration from larger project
REPO_PARENT ?= ..
-include $(REPO_PARENT)/parent_common.mk
TRTL ?= ../../dependencies/mock-turtle/software
LIBTDC ?= ../../fmc-tdc-sw/lib
LIBFD ?= ../../fine-delay-sw/lib
LIBS = libwrtd.so
LIB = libwrtd.a
LOBJ := libwrtd-internal.o
LOBJ += libwrtd-common.o
LOBJ += libwrtd-logging.o
LOBJ += libwrtd-input.o
LOBJ += libwrtd-output.o
CFLAGS += -Wall -ggdb -O2 -fPIC -I. -I../include -I$(TRTL)/include -I$(TRTL)/lib -I$(LIBFD) -I$(LIBTDC) -I$(LIBFD)/../kernel
CFLAGS += -Werror
CFLAGS += $(EXTRACFLAGS)
LDLIBS += -L. -lwrtd
ARFLAGS = rc
modules all: $(LIB) $(LIBS)
%: %.c $(LIB)
$(CC) $(CFLAGS) $(LDFLAGS) $*.c $(LDLIBS) -o $@
$(LIB): $(LOBJ)
$(AR) $(ARFLAGS) $@ $^
$(LIBS): $(LIB)
$(CC) -shared -o $@ -Wl,--whole-archive,-soname,$@ $^ -Wl,--no-whole-archive
clean:
rm -f $(LIB) .depend *.o *~
.depend: Makefile $(wildcard *.c *.h)
$(CC) $(CFLAGS) -M $(LOBJ:.o=.c) -o $@
install modules_install:
-include .depend
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* inspired by a draft of Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdint.h>
#include <libmockturtle.h>
#include <libwrtd-internal.h>
static const char * const wrtd_errors[] = {
"Received an invalid answer from white-rabbit-node-code CPU",
"Cannot read channel/trigger state",
"You are using an invalid binary",
"Invalid dead time value",
"Invalid delay value",
"Invalid trigger identifier",
"Invalid channel number",
"Function not yet implemented",
"Received an invalid trigger entry",
"Received an invalid hash entry",
"Received an invalid hash chain",
"Received an invalid trigger handle",
"Trigger not found",
"No trigger condition",
"Invalid pulse width",
"Invalid input real-time application version",
"Invalid output real-time application version"
};
/**
* It returns a string messages corresponding to a given error code. If
* it is not a libwrtd error code, it will run trtl_strerror()
* @param[in] err error code
* @return a message error
*/
const char *wrtd_strerror(int err)
{
if (err < EWRTD_INVALID_ANSWER_ACK || err >= __EWRTD_MAX_ERROR_NUMBER)
return trtl_strerror(err);
return wrtd_errors[err - EWRTD_INVALID_ANSWER_ACK];
}
/**
* It initializes the WRTD library. It must be called before doing
* anything else. If you are going to load/unload WRTD devices, then
* you have to un-load (wrtd_exit()) e reload (wrtd_init()) the library.
*
* This library is based on the libmockturtle, so internally, this function also
* run trtl_init() in order to initialize the WRNC library.
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
int wrtd_init(void)
{
int err;
err = trtl_init();
if (err)
return err;
return 0;
}
/**
* It releases the resources allocated by wrtd_init(). It must be called when
* you stop to use this library. Then, you cannot use functions from this
* library.
*/
void wrtd_exit(void)
{
trtl_exit();
}
static int __wrtd_load(struct wrtd_desc *wrtd, char *fw,
unsigned int cpu, uint16_t id)
{
struct trtl_fw_version version;
int err;
err = trtl_cpu_load_application_file(wrtd->trtl, cpu, fw);
if (err)
return err;
err = trtl_cpu_enable(wrtd->trtl, cpu);
if (err)
return err;
/* Do a ping, but wait for 5sec for the FW to be ready. */
err = trtl_fw_ping_timeout(wrtd->trtl, cpu, 0, 5000);
if (err)
return err;
err = trtl_fw_version(wrtd->trtl, cpu, 0, &version);
if (err)
return err;
if (version.rt_id != id) {
errno = EWRTD_INVALID_IN_APP;
return -1;
}
return 0;
}
/**
* It loads the input firmare (TDC)
* @param[in] dev device token
* @param[in] fw path to firmware
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
int wrtd_in_load(struct wrtd_node *dev, char *fw)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
return __wrtd_load(wrtd, fw, WRTD_CPU_TDC, WRTD_IN_RT_ID);
}
/**
* It loads the output firmare (FD)
* @param[in] dev device token
* @param[in] fw path to firmware
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
int wrtd_out_load(struct wrtd_node *dev, char *fw)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
return __wrtd_load(wrtd, fw, WRTD_CPU_FD, WRTD_OUT_RT_ID);
}
/**
* It opens and initialize the configuration for the given device
* @param[in] device_id device identifier
* @return It returns an anonymous wrtd_node structure on success.
* On error, NULL is returned, and errno is set appropriately.
*/
struct wrtd_node *wrtd_open(uint32_t device_id)
{
struct wrtd_desc *wrtd;
wrtd = malloc(sizeof(struct wrtd_desc));
if (!wrtd)
return NULL;
wrtd->trtl = trtl_open_by_id(device_id);
if (!wrtd->trtl)
goto out;
wrtd->dev_id = device_id;
return (struct wrtd_node *)wrtd;
out:
free(wrtd);
return NULL;
}
/**
* It closes a WRTD device opened with one of the following function:
* wrtd_open_by_lun(), wrtd_open_by_fmc()
* @param[in] dev device token
*/
void wrtd_close(struct wrtd_node *dev)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
trtl_close(wrtd->trtl);
free(wrtd);
dev = NULL;
}
/**
* It returns the WRNC token in order to allows users to run
* functions from the WRNC library
* @param[in] dev device token
* @return the WRNC token
*/
struct trtl_dev *wrtd_get_trtl_dev(struct wrtd_node *dev)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
return (struct trtl_dev *)wrtd->trtl;
}
/**
* It converts the white rabbit time stamp to a pico seconds
* @param[in] ts time-stamp
* @param[out] pico pico-seconds
*/
void wrtd_ts_to_pico(struct wr_timestamp *ts, uint64_t *pico)
{
uint64_t p;
p = ts->frac * 8000 / 4096;
p += (uint64_t) ts->ticks * 8000LL;
p += ts->seconds * (1000ULL * 1000ULL * 1000ULL * 1000ULL);
*pico = p;
}
/**
* It converts a pico seconds integer into a white rabbit time stamp
* @param[in] pico pico-seconds
* @param[out] ts time-stamp
*/
void wrtd_pico_to_ts(uint64_t *pico, struct wr_timestamp *ts)
{
uint64_t p = *pico;
ts->seconds = p / (1000ULL * 1000ULL * 1000ULL * 1000ULL);
p %= (1000ULL * 1000ULL * 1000ULL * 1000ULL);
ts->ticks = p / 8000;
p %= 8000;
ts->frac = p * 4096 / 8000;
}
/**
* It converts a white rabbit time stamp to seconds and pico-seconds
* @param[in] ts time-stamp
* @param[out] sec seconds
* @param[out] pico pico-seconds
*/
void wrtd_ts_to_sec_pico(struct wr_timestamp *ts, uint64_t *sec, uint64_t *pico)
{
*sec = ts->seconds;
*pico = ts->frac * 8000 / 4096;
*pico += (uint64_t) ts->ticks * 8000LL;
}
/**
* It converts a white rabbit time stamp to seconds and pico-seconds
* @param[in] sec seconds
* @param[in] pico pico-seconds
* @param[out] ts time-stamp
*/
void wrtd_sec_pico_to_ts(uint64_t sec, uint64_t pico, struct wr_timestamp *ts)
{
ts->seconds = sec;
ts->ticks = pico / 8000;
ts->frac = (pico % 8000) * 4096 / 8000;
}
/**
* Substract two timestamp. Returns -1 if the result would be negative.
* @param[in] l left operand
* @param[in] r right operand
* @param[out] res result
*/
int wrtd_ts_sub(struct wr_timestamp *res,
struct wr_timestamp *l, struct wr_timestamp *r)
{
int carry;
uint32_t rticks;
uint64_t rsecs;
carry = (l->frac < r->frac);
res->frac = (carry ? 4096 : 0) + l->frac - r->frac;
rticks = r->ticks + (carry ? 1 : 0);
carry = l->ticks < rticks;
res->ticks = (carry ? 125000000 : 0) + l->ticks - rticks;
rsecs = r->seconds + (carry ? 1 : 0);
if (l->seconds < rsecs)
return - 1;
res->seconds = l->seconds - rsecs;
return 0;
}
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* inspired by a draft of Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <errno.h>
#include <libmockturtle.h>
#include "libwrtd-internal.h"
/**
* Internal helper to send and recevie synchronous messages to/from the TDC
*/
static inline int wrtd_in_send_and_receive_sync(struct wrtd_desc *wrtd,
struct trtl_msg *msg)
{
int err;
/* Send the message and get answer */
err = trtl_msg_sync(wrtd->trtl, WRTD_CPU_TDC, 0, msg, msg,
WRTD_DEFAULT_TIMEOUT);
return err < 0 ? err : 0; /* Ignore timeout */
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * PROTOTYPEs IMPLEMENTATION * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* FIXME
* Most of the function's code below can be optimized by using memcpy()
* or similar operations. For the time being, I'm leaving it like this
* because data structures are shared with the real-time applications
*/
/**
* It retreives the current status of a given input channel
* @param[in] dev device token
* @param[in] input index (0-based) of the input channel
* @param[out] state the current status of a channel
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_state_get(struct wrtd_node *dev, unsigned int input,
struct wrtd_input_state *state)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
int err;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
uint32_t variables[] = {IN_VAR_DEVICE_SENT_PACK, 0,
IN_VAR_DEVICE_DEAD_TIME, 0};
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
if (state == NULL) {
errno = ENOMEM;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
err = trtl_fw_variable_get(wrtd->trtl, WRTD_CPU_TDC, 0, variables, 2);
if (err)
return err;
/* Convert to state structure */
state->input = chan.n;
state->assigned_id = chan.config.id;
state->delay = chan.config.delay;
state->tdc_timebase_offset = chan.config.timebase_offset;
state->last_pulse = chan.stats.last_pulse;
state->flags = chan.config.flags;
state->log_level = chan.config.log_level;
state->mode = chan.config.mode;
state->total_pulses = chan.stats.total_pulses;
state->sent_triggers = chan.stats.sent_pulses;
state->last_sent = chan.stats.last_sent;
state->miss_no_timing = chan.stats.miss_no_timing;
state->dead_time.seconds = 0;
state->dead_time.frac = 0;
state->dead_time.ticks = variables[3] * 2;
state->sent_packets = variables[1];
return 0;
}
/**
* Hardware enable/disable a WRTD input channel.
* @param[in] dev pointer to open node device.
* @param[in] input index (0-based) of the input channel
* @param[in] enable 1 to enable the input, 0 disables it.
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_enable(struct wrtd_node *dev, unsigned int input, int enable)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
uint32_t variables[] = {IN_VAR_DEVICE_CHAN_ENABLE, 0};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
err = trtl_fw_variable_get(wrtd->trtl, WRTD_CPU_TDC, 0, variables, 1);
if (err)
return err;
if (enable) {
variables[1] |= (1 << input);
chan.config.flags |= WRTD_ENABLED;
} else {
variables[1] &= ~(1 << input);
chan.config.flags &= ~WRTD_ENABLED;
}
err = trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
return trtl_fw_variable_set(wrtd->trtl, WRTD_CPU_TDC, 0, variables, 1);
}
/**
* Assign (unassign) a trigger ID to a given WRTD input. Passing a NULL trig_id
* un-assigns the current trigger (the input will be tagging pulses and
* logging them, but they will not be sent as triggers to the WR network).
* @param[in] dev device token
* @param[in] input index (0-based) of the input channel
* @param[in] trig_id the trigger to be sent upon reception of a pulse on the
* given input.
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_trigger_assign(struct wrtd_node *dev, unsigned int input,
struct wrtd_trig_id *trig_id)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
if (trig_id) {
chan.config.id = *trig_id;
chan.config.flags |= WRTD_TRIGGER_ASSIGNED;
chan.config.flags &= ~WRTD_LAST_VALID;
} else {
memset(&chan.config.id, 0, sizeof(struct wrtd_trig_id));
chan.config.flags &= ~WRTD_TRIGGER_ASSIGNED;
}
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
}
/**
* It un-assign the trigger on an input channel. It is just an helper that
* internally use wrtd_in_trigger_unassign()
* @param[in] dev device token
* @param[in] input index (0-based) of the input channel
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_trigger_unassign(struct wrtd_node *dev,
unsigned int input)
{
return wrtd_in_trigger_assign(dev, input, NULL);
}
/**
* Set trigger mode for a given WRTD input. Note that the input must be armed
* by calling wrtd_in_arm() at least once before it can send triggers.
*
* The mode can be single shot or continuous. Single shot means the input will
* trigger on the first incoming pulse and will ignore the subsequent pulses
* until re-armed.
*
* @param[in] dev device token
* @param[in] input (0-based) of the input channel
* @param[in] mode triggering mode.
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_trigger_mode_set(struct wrtd_node *dev, unsigned int input,
enum wrtd_trigger_mode mode)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
chan.config.mode = mode;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
}
/**
* It generates a software trigger at a given TAI value. The TAI value that
* you provide to this function (trigger->ts) is considered as a delay
* from the current time. The current time means the time when the real-time
* application receive the software trigger command
* @param[in] dev device token
* @param[in] trigger trigger to enumlate
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_trigger_software(struct wrtd_node *dev,
struct wrtd_trigger_entry *trigger)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct trtl_msg msg;
if (trigger == NULL) {
errno = EWRTD_INVALID_TRIG_ID;
return -1;
}
memset(&msg, 0, sizeof(struct trtl_msg));
msg.hdr.msg_id = WRTD_IN_ACTION_SW_TRIG;
msg.hdr.flags = TRTL_HMQ_HEADER_FLAG_RPC;
msg.hdr.len = sizeof(struct wrtd_trigger_entry) / 4;
memcpy(msg.data, trigger, sizeof(struct wrtd_trigger_entry));
/* Send the message and get answer */
return wrtd_in_send_and_receive_sync(wrtd, &msg);
}
/**
* Arm (disarm) a WRTD input for triggering. By arming the input, you are making
* it ready to accept/send triggers
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[in] armed 1 arms the input, 0 disarms the input.
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_arm(struct wrtd_node *dev, unsigned int input, int armed)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
if (armed)
chan.config.flags |= WRTD_ARMED;
else
chan.config.flags &= ~WRTD_ARMED;
chan.config.flags &= ~WRTD_TRIGGERED;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
}
/**
* Set the dead time (the minimum gap between input pulses, below which
* the TDC ignores the subsequent pulses; limits maximum input pulse rate,
* 16 ns granularity)
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[in] dead_time_ps dead time in pico-seconds [80000000, 160000000000]
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_dead_time_set(struct wrtd_node *dev, unsigned int input,
uint64_t dead_time_ps)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
uint32_t variables[] = {IN_VAR_DEVICE_DEAD_TIME, 0};
uint32_t dead_time_cycles;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
/* Convert dead-times in cycles/ticks */
dead_time_cycles = dead_time_ps / 16000;
if(dead_time_cycles < 5000 || dead_time_cycles > 10000000 ) {
errno = EWRTD_INVALID_DEAD_TIME;
return -1;
}
variables[1] = dead_time_cycles; // FIXME wrong API
return trtl_fw_variable_set(wrtd->trtl, WRTD_CPU_TDC, 0, variables, 1);
}
/**
* Set the offset (for compensating cable delays), in 10 ps steps.
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[in] delay_ps delay in pico-seconds
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_delay_set(struct wrtd_node *dev, unsigned int input,
uint64_t delay_ps)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
struct wr_timestamp t;
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
wrtd_pico_to_ts(&delay_ps, &t);
memcpy(&chan.config.delay, &t, sizeof(struct wr_timestamp));
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
}
/**
* Set the time offset on a given input channel. The time offset is between
* the White-Rabbit timescale and the ACAM TDC timescale. This information
* is only known by the TDC driver which has access the calibration data
* on the TDC eeprom. So, it is necessary to inform the RealTime application
* about this offset as soon as the RealTime application start to run.
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[in] offset time offset in pico seconds
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_timebase_offset_set(struct wrtd_node *dev, unsigned int input,
uint64_t offset)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
struct wr_timestamp t;
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
wrtd_pico_to_ts(&offset, &t);
memcpy(&chan.config.timebase_offset, &t, sizeof(struct wr_timestamp));
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
}
/**
* Reset all counters on a given input channel
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_counters_reset(struct wrtd_node *dev, unsigned int input)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
chan.stats.total_pulses = 0;
chan.stats.sent_pulses = 0;
chan.stats.miss_no_timing = 0;
chan.config.flags &= ~WRTD_LAST_VALID;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
}
/**
* Reset global counters
* @param[in] dev device token
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_global_counters_reset(struct wrtd_node *dev)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
uint32_t variables[] = {IN_VAR_DEVICE_SENT_PACK, 0};
return trtl_fw_variable_set(wrtd->trtl, WRTD_CPU_TDC, 0, variables, 1);
}
/**
* Check the enable status on a trigger input.
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[out] enable 1 if it is enabled, 0 otherwise
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_is_enabled(struct wrtd_node *dev, unsigned int input,
unsigned int *enable)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
*enable = !!(chan.config.flags & WRTD_ENABLED);
return 0;
}
/**
* Check the armed status on a trigger input.
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[out] armed 1 if it is enabled, 0 otherwise
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_is_armed(struct wrtd_node *dev, unsigned int input,
unsigned int *armed)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
*armed = !!(chan.config.flags & WRTD_ARMED);
return 0;
}
/**
* Check the trigger assigned status on a trigger input.
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[out] armed 1 if it is enabled, 0 otherwise
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_has_trigger(struct wrtd_node *dev, unsigned int input,
unsigned int *assigned)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
*assigned = !!(chan.config.flags & WRTD_TRIGGER_ASSIGNED);
return 0;
}
/**
* Get the dead time (the minimum gap between input pulses, below which
* the TDC ignores the subsequent pulses; limits maximum input pulse rate,
* 16 ns granularity)
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[out] dead_time_ps dead time in pico-seconds
* @return 0 on success, -1 on error and errno is set appropriately
*
* @todo to be implemented
*/
int wrtd_in_dead_time_get(struct wrtd_node *dev, unsigned int input,
uint64_t *dead_time_ps)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
uint32_t variables[] = {IN_VAR_DEVICE_DEAD_TIME, 0};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_variable_get(wrtd->trtl, WRTD_CPU_TDC, 0, variables, 1);
if (err)
return err;
*dead_time_ps = variables[1] * 16000;
return 0;
}
/**
* Get the offset (for compensating cable delays), in 10 ps steps.
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[out] delay_ps delay in pico-seconds
* @return 0 on success, -1 on error and errno is set appropriately
*
* @todo to be implemented
*/
int wrtd_in_delay_get(struct wrtd_node *dev, unsigned int input,
uint64_t *delay_ps)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
wrtd_ts_to_pico(&chan.config.delay, delay_ps);
return 0;
}
/**
* Get/set the Sequence ID counter (counting up at every pulse)
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_seq_counter_set(struct wrtd_node *dev, unsigned int input,
unsigned int value)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct trtl_tlv tlv = {
.type = IN_STRUCT_CHAN_0 + input,
.size = sizeof(struct wrtd_in_channel),
.buf = &chan,
};
int err;
if (input >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
if (err)
return err;
chan.stats.seq = value;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_TDC, 0, &tlv, 1);
}
/**
* It check if the input real-time application is alive
* @param[in] dev device token
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_ping(struct wrtd_node *dev)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
return trtl_fw_ping(wrtd->trtl, WRTD_CPU_TDC, 0);
}
/**
* It gets the input base time
* @param[in] dev device token
* @param[out] ts input device base time
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_base_time(struct wrtd_node *dev, struct wr_timestamp *ts)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
uint32_t variables[] = {IN_VAR_DEVICE_TIME_S, 0,
IN_VAR_DEVICE_TIME_T, 0};
int err;
err = trtl_fw_variable_get(wrtd->trtl, WRTD_CPU_TDC, 0, variables, 2);
if (err)
return err;
ts->seconds = variables[1];
ts->ticks = variables[3];
return 0;
}
/**
* It gets the output version
* @param[in] dev device token
* @param[out] version the RT application version
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_version(struct wrtd_node *dev, struct trtl_fw_version *version)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
return trtl_fw_version(wrtd->trtl, WRTD_CPU_TDC, 0, version);
}
/**
* It tells if the input firmware is valid
* @param[in] dev device token
* @param[out] version the RT application version
* @return 1 when valid, 0 if invalid or error (and errno is set appropriately)
*/
int wrtd_in_is_valid(struct wrtd_node *dev)
{
struct trtl_fw_version version;
int err;
err = wrtd_in_version(dev, &version);
if (err)
return 0;
if (version.rt_id != WRTD_IN_RT_ID) {
errno = EWRTD_INVALID_IN_APP;
return 0;
}
return 1;
}
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* inspired by a draft of Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <libmockturtle.h>
#include "libwrtd-internal.h"
/**
* It validates the answer of a synchronous message
* @param[in] msg message to validate
* @return 0 if it is valid, -1 otherwise and errno is appropriately set
*/
int wrtd_validate_acknowledge(struct trtl_msg *msg)
{
if (msg->hdr.len != 2 || msg->data[0] != WRTD_REP_ACK_ID) {
errno = EWRTD_INVALID_ANSWER_ACK;
return -1;
}
return 0;
}
/**
* It extracts a wr_timestamp from a given buffer (arriving from a real-time
* application)
* @param[in] buf answer of the real time application
* @param[in] offset offset of the timestamp inside the answer buffer
* @param[out] ts where write the wr_timestamp
*/
void unbag_ts(uint32_t *buf, int offset, struct wr_timestamp *ts)
{
ts->seconds = buf[offset];
ts->ticks = buf[offset + 1];
ts->frac = buf[offset + 2];
}
/**
* It compares two triggers id. The output is the same of memcmp(2)
* @param[in] id1 first id to compare
* @param[in] id2 second id to compare
* @return like memcmp(2)
*/
int wrtd_trig_id_cmp(struct wrtd_trig_id *id1, struct wrtd_trig_id *id2)
{
return memcmp(id1, id2, sizeof(struct wrtd_trig_id));
}
/*
* Internal helper to send and receive synchronous messages to/from the WRNC
*/
int wrtd_send_and_receive_sync(struct wrtd_desc *wrtd,
struct trtl_msg *msg,
int cpu)
{
int err;
err = trtl_msg_sync(wrtd->trtl, cpu, 0,
msg, msg, WRTD_DEFAULT_TIMEOUT);
return err < 0 ? err : 0; /* ignore timeout */
}
/**
* It performs a simple request to a given core which will only answer
* with an ACK
*/
int wrtd_trivial_request(struct wrtd_node *dev,
struct trtl_msg *request_msg,
int cpu)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
int err;
err = wrtd_send_and_receive_sync(wrtd, request_msg, cpu);
if (err)
return err;
return wrtd_validate_acknowledge(request_msg);
}
/*
* Copyright (C) 2014 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* License: GPL v3
*/
#ifndef __LIBWRTD_INTERNAL__H__
#define __LIBWRTD_INTERNAL__H__
#include <stdlib.h>
#include <errno.h>
#include <libwrtd.h>
/* FIXME
* Statically defined but we must find a dynamic way to determinate
* these offsets
*/
#define WRTD_TDC_DEV_ID_OFFSET 0
#define WRTD_FD_DEV_ID_OFFSET 1
/**
* Description of a White-Rabbit Trigger-Distribution device
*/
struct wrtd_desc {
struct trtl_dev *trtl; /**< WRNC device associated */
uint32_t dev_id; /**< fmc device id */
uint32_t app_id; /**< Application id */
uint32_t n_cpu; /**< Number of CPUs */
};
#define WRTD_OUT_CHANNEL_PUBLIC_SIZE (sizeof(struct wrtd_out_channel) \
- sizeof(struct wrtd_out_channel_private))
/**
* @file libwrtd-interal.c
*/
void unbag_ts(uint32_t *buf, int offset, struct wr_timestamp *ts);
int wrtd_validate_acknowledge(struct trtl_msg *msg);
int wrtd_trig_id_cmp(struct wrtd_trig_id *id1, struct wrtd_trig_id *id2);
extern int wrtd_trivial_request(struct wrtd_node *dev,
struct trtl_msg *request_msg,
int cpu);
extern int wrtd_send_and_receive_sync(struct wrtd_desc *wrtd,
struct trtl_msg *msg,
int cpu);
#endif
/*
* Copyright (C) 2015-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* 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, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
#include <libmockturtle.h>
#include <libwrtd-internal.h>
/**
* It returns a human readable string that describe a given log level
* @param[in] lvl log level
* @return a string if the log level is mapped, otherwise an empty string
*/
const char *wrtd_strlogging(enum wrtd_log_level lvl)
{
switch (lvl & WRTD_LOG_LEVEL_MASK) {
case WRTD_LOG_NOTHING:
return "off";
case WRTD_LOG_RAW:
return "raw";
case WRTD_LOG_SENT:
return "sent";
case WRTD_LOG_PROMISC:
return "promiscuous";
case WRTD_LOG_FILTERED:
return "filtered";
case WRTD_LOG_EXECUTED:
return "executed";
case WRTD_LOG_MISSED:
return "missed";
case WRTD_LOG_ALL:
return "all";
}
return "n/a";
}
/**
* It returns the full string describing the log_level in use
* @param[out] buf where write the string
* @param[in] log_level the log level to describe
*/
void wrtd_strlogging_full(char *buf, uint32_t log_level)
{
enum wrtd_log_level lvl;
if (!log_level) { /* No log level */
strcpy(buf, wrtd_strlogging(log_level));
return;
}
strcpy(buf,"");
for (lvl = 0x1; lvl <= WRTD_LOG_MISSED; lvl <<= 1) {
if (lvl & log_level) {
strcat(buf, wrtd_strlogging(lvl));
strcat(buf, " ");
}
}
}
/**
* It converts a given logging string into a log_level
* @param[in] log string log level
* @return the correspondent log level enum
*/
enum wrtd_log_level wrtd_strlogging_to_level(char *log)
{
if(!strcmp(log, "all"))
return WRTD_LOG_ALL;
if(!strcmp(log, "promiscuous"))
return WRTD_LOG_PROMISC;
if(!strcmp(log, "raw"))
return WRTD_LOG_RAW;
if(!strcmp(log, "executed"))
return WRTD_LOG_EXECUTED;
if(!strcmp(log, "missed"))
return WRTD_LOG_MISSED;
if(!strcmp(log, "sent"))
return WRTD_LOG_SENT;
if(!strcmp(log, "filtered"))
return WRTD_LOG_FILTERED;
return WRTD_LOG_NOTHING;
}
/**
* It reads one or more log entry from a given hmq_log. The user of this
* function must check that the hmq_log used correspond to a logging interface
* @param[in] hmq_log logging HMQ.
* @param[out] log log message
* @param[in] count number of messages to read
* @param[in] poll_timeout poll(2) timeout argument. Negative means infinite.
* @return number of read messages on success (check errno if it returns less
* messages than expected), -1 on error and errno is set appropriately
*/
int wrtd_log_read(struct wrtd_node *dev,
struct wrtd_log_entry *log,
int count, int poll_timeout)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_log_entry *cur = log;
struct trtl_msg msg;
#define __WRTD_POLL_N 2
struct polltrtl p[__WRTD_POLL_N];
int remaining = count;
int n_read = 0, ret, i;
for (i = 0; i < __WRTD_POLL_N; ++i) {
p[i].trtl = wrtd->trtl;
p[i].idx_hmq = 0;
p[i].events = POLLIN;
}
p[0].idx_cpu = WRTD_CPU_TDC;
p[1].idx_cpu = WRTD_CPU_FD;
/* Clean up errno to be able to distinguish between error cases and
normal behaviour when the function return less messages
than expected */
errno = 0;
while (remaining > 0) {
ret = trtl_msg_poll(p, 2, poll_timeout);
if (ret <= 0)
break;
for (i = 0; i < __WRTD_POLL_N; ++i) {
if (!(p[i].revents & POLLIN))
continue;
ret = trtl_msg_async_recv(p[i].trtl,
p[i].idx_cpu,
p[i].idx_hmq,
&msg, 1);
if (ret <= 0)
break;
memcpy(cur, msg.data, sizeof(struct wrtd_log_entry));
cur->type |= (p[i].idx_cpu << WRTD_LOG_CPU_SHIFT);
remaining--;
n_read++;
cur++;
}
}
#undef __WRTD_POLL_N
return (n_read > 0 || errno == 0 ? n_read : -1);
}
/**
* @param[in] dev device token
* @param[in] channel 0-based channel index
* @param[in] log_level log level to apply to the logging messages
* @return 0 on success, -1 on error and errno is set appropriately
*/
static int wrtd_log_level_set(struct wrtd_node *dev, unsigned int channel,
uint32_t log_level, int core)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct trtl_tlv tlv;
struct wrtd_out_channel ochan;
struct wrtd_in_channel ichan;
int err;
switch (core) {
case WRTD_CPU_FD:
if (channel >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
tlv.type = OUT_STRUCT_CHAN_0 + channel;
tlv.size = WRTD_OUT_CHANNEL_PUBLIC_SIZE;
tlv.buf = &ochan;
break;
case WRTD_CPU_TDC:
if (channel >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
tlv.type = IN_STRUCT_CHAN_0 + channel;
tlv.size = sizeof(struct wrtd_in_channel);
tlv.buf = &ichan;
break;
default:
abort();
}
err = trtl_fw_buffer_get(wrtd->trtl, core, 0, &tlv, 1);
if (err)
return err;
switch(core) {
case WRTD_CPU_FD:
ochan.config.log_level = log_level;
break;
case WRTD_CPU_TDC:
ichan.config.log_level = log_level;
break;
default:
abort();
}
return trtl_fw_buffer_set(wrtd->trtl, core, 0, &tlv, 1);
}
/**
* It sets the logging level for an output channel
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[in] log_level log level to apply to the logging messages
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_log_level_set(struct wrtd_node *dev, unsigned int output,
uint32_t log_level)
{
return wrtd_log_level_set(dev, output, log_level, WRTD_CPU_FD);
}
/**
* It gets the logging level for an output channel
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[out] log_level current log level used by the Real-Time application
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_log_level_get(struct wrtd_node *dev, unsigned int input,
uint32_t *log_level)
{
struct wrtd_output_state state;
int err;
err = wrtd_out_state_get(dev, input, &state);
if (err)
return err;
*log_level = state.log_level;
return 0;
}
/**
* It sets the logging level for an input channel
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[in] log_level log level to apply to the logging messages
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_log_level_set(struct wrtd_node *dev, unsigned int input,
uint32_t log_level)
{
return wrtd_log_level_set(dev, input, log_level, WRTD_CPU_TDC);
}
/**
* It gets the logging level for an input channel
* @param[in] dev device token
* @param[in] input index (0-based) of input channel
* @param[out] log_level current log level used by the Real-Time application
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_in_log_level_get(struct wrtd_node *dev, unsigned int input,
uint32_t *log_level)
{
struct wrtd_input_state state;
int err;
err = wrtd_in_state_get(dev, input, &state);
if (err)
return err;
*log_level = state.log_level;
return 0;
}
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* inspired by a draft of Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libmockturtle.h>
#include <libwrtd-internal.h>
/*
* Internal helper to send and receive synchronous messages to/from the WRNC
*/
static inline int wrtd_out_send_and_receive_sync(struct wrtd_desc *wrtd,
struct trtl_msg *msg)
{
int err;
/* Send the message and get answer */
err = trtl_msg_sync(wrtd->trtl, WRTD_CPU_FD, 0, msg, msg,
WRTD_DEFAULT_TIMEOUT);
return err < 0 ? err : 0; /* Ignore timeout */
}
/**
* It retrieves the trigger index where you can write.
* If the trigger with ID 'tid' already exists it returns its index,
* otherwise it return the first free index.
*/
static int wrtd_out_trigger_index_get(struct wrtd_desc *wrtd,
struct wrtd_trig_id *tid)
{
struct trtl_msg msg;
int err;
memset(&msg.hdr, 0, sizeof(struct trtl_hmq_header));
msg.hdr.flags = TRTL_HMQ_HEADER_FLAG_RPC;
msg.hdr.msg_id = WRTD_OUT_ACTION_TRIG_IDX;
msg.hdr.len = sizeof(struct wrtd_trig_id) / 4;
memcpy(msg.data, tid, sizeof(struct wrtd_trig_id));
err = wrtd_out_send_and_receive_sync(wrtd, &msg);
if (err)
return -1;
if (msg.hdr.msg_id != WRTD_OUT_ACTION_TRIG_IDX &&
msg.hdr.msg_id != WRTD_OUT_ACTION_TRIG_FRE) {
errno = ETRTL_INVALID_MESSAGE;
return -1;
}
/* return the trigger index */
return msg.data[0];
}
int wrtd_out_trigger_sw_now(struct wrtd_node *dev, unsigned int output)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct trtl_msg msg;
struct wrtd_out_trigger_sw d;
int err;
memset(&msg.hdr, 0, sizeof(struct trtl_hmq_header));
msg.hdr.flags = TRTL_HMQ_HEADER_FLAG_RPC;
msg.hdr.msg_id = WRTD_OUT_ACTION_SW_TRIG;
msg.hdr.len = sizeof(struct wrtd_out_trigger_sw) / 4;
d.chan = output;
d.now = 1;
memset(&d.tstamp, 0, sizeof(d.tstamp));
memcpy(msg.data, &d, sizeof(d));
err = wrtd_out_send_and_receive_sync(wrtd, &msg);
if (err)
return -1;
if (msg.hdr.msg_id != WRTD_OUT_ACTION_SW_TRIG) {
errno = ETRTL_INVALID_MESSAGE;
return -1;
}
return 0;
}
static int wrtd_out_action_one_word(struct wrtd_desc *wrtd,
uint8_t msgid, uint32_t word)
{
struct trtl_msg msg;
memset(&msg.hdr, 0, sizeof(struct trtl_hmq_header));
msg.hdr.flags = TRTL_HMQ_HEADER_FLAG_RPC;
msg.hdr.msg_id = msgid;
msg.hdr.len = 1;
msg.data[0] = word;
return wrtd_out_send_and_receive_sync(wrtd, &msg);
}
static inline int wrtd_out_trigger_insert(struct wrtd_desc *wrtd, uint32_t tid)
{
return wrtd_out_action_one_word(wrtd, WRTD_OUT_ACTION_TRIG_ADD, tid);
}
static inline int wrtd_out_trigger_remove(struct wrtd_desc *wrtd, uint32_t tid)
{
return wrtd_out_action_one_word(wrtd, WRTD_OUT_ACTION_TRIG_DEL, tid);
}
static inline int wrtd_out_rt_disable(struct wrtd_desc *wrtd,
unsigned int output)
{
return wrtd_out_action_one_word(wrtd, WRTD_OUT_ACTION_DISABLE, output);
}
static struct trtl_tlv wrtd_trigger_tlv(uint32_t index,
struct wrtd_out_trigger *trig)
{
struct trtl_tlv tlv = {
.type = __WRTD_OUT_STRUCT_MAX + index,
.size = sizeof(struct wrtd_out_trigger),
.buf = trig,
};
return tlv;
}
static struct trtl_tlv wrtd_channel_tlv(uint32_t index,
struct wrtd_out_channel *chan)
{
struct trtl_tlv tlv = {
.type = OUT_STRUCT_CHAN_0 + index,
.size = WRTD_OUT_CHANNEL_PUBLIC_SIZE,
.buf = chan,
};
return tlv;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * PROTOTYPEs IMPLEMENTATION * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* It retreives the current output status of a given channel
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[out] state channel status
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_state_get(struct wrtd_node *dev, unsigned int output,
struct wrtd_output_state *state)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out out;
struct wrtd_out_channel chan;
struct trtl_tlv tlv = wrtd_channel_tlv(output, &chan);
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
if (state == NULL) {
errno = ENOMEM;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
/* Copy to state structure */
state->output = chan.n;
state->executed_pulses = chan.stats.hits;
state->missed_pulses_late = chan.stats.miss_timeout;
state->missed_pulses_deadtime = chan.stats.miss_deadtime;
state->missed_pulses_overflow = chan.stats.miss_overflow;
state->missed_pulses_no_timing = chan.stats.miss_no_timing;
state->last_executed = chan.stats.last_executed;
state->last_enqueued = chan.stats.last_enqueued;
state->last_lost = chan.stats.last_lost;
state->mode = chan.config.mode;
state->flags = chan.config.flags;
state->log_level = chan.config.log_level;
state->pulse_width.seconds = 0;
state->pulse_width.frac = 0;
state->pulse_width.ticks = chan.config.width_cycles;
state->dead_time.seconds = 0;
state->dead_time.frac = 0;
state->dead_time.ticks = chan.config.dead_time;
tlv.type = OUT_STRUCT_DEVICE;
tlv.size = sizeof(struct wrtd_out);
tlv.buf = &out;
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
state->received_messages = out.counter_etherbone;
state->received_loopback = out.counter_loopback;
state->last_received = out.last_received;
return 0;
}
/**
* It enables/disables a trigger output line
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[in] enable 1 to enable the output, 0 disables it.
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_enable(struct wrtd_node *dev, unsigned int output,
int enable)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct trtl_tlv tlv = wrtd_channel_tlv(output, &chan);
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
if (enable) {
chan.config.flags |= WRTD_ENABLED;
} else {
chan.config.flags &= ~(WRTD_ENABLED | WRTD_ARMED |
WRTD_TRIGGERED | WRTD_LAST_VALID);
chan.config.state = OUT_ST_IDLE;
err = wrtd_out_rt_disable(wrtd, output);
if (err)
return -1;
}
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
static int wrtd_out_trig_assign_condition_by_index(struct wrtd_node *dev,
unsigned int output,
uint32_t trig_idx,
uint32_t cond_idx)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_trigger trig;
struct trtl_tlv tlv;
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
tlv = wrtd_trigger_tlv(trig_idx, &trig);
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
if (!(trig.flags & ENTRY_FLAG_VALID)) {
/* If the given trigger is not valid, then skip */
errno = EINVAL;
return -1;
}
trig.ocfg[output].state &= ~HASH_ENT_DIRECT;
trig.ocfg[output].state |= HASH_ENT_CONDITIONAL;
trig.ocfg[output].cond_ptr = cond_idx;
err = trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
tlv = wrtd_trigger_tlv(cond_idx, &trig);
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
if (!(trig.flags & ENTRY_FLAG_VALID)) {
/* If the given trigger is not valid, then skip */
errno = EINVAL;
return -1;
}
trig.ocfg[output].state &= ~HASH_ENT_DIRECT;
trig.ocfg[output].state |= HASH_ENT_CONDITION;
trig.ocfg[output].cond_ptr = -1;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* It sets the given bitmaks (it means that it does OR with the current value)
*/
static int wrtd_out_flag_set(struct wrtd_node *dev, unsigned int output,
uint32_t flags)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct trtl_tlv tlv = wrtd_channel_tlv(output, &chan);
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
chan.config.flags |= flags;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* It sets the given bitmaks (it means that it does AND NOT with the current
* value)
*/
static int wrtd_out_flag_clr(struct wrtd_node *dev, unsigned int output,
uint32_t flags)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct trtl_tlv tlv = wrtd_channel_tlv(output, &chan);
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
chan.config.flags &= ~flags;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
static int wrtd_out_trig_assign_one(struct wrtd_node *dev, unsigned int output,
struct wrtd_trigger_handle *handle,
struct wrtd_trig_id *tid)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_trigger trig;
struct trtl_tlv tlv;
int err, ret;
handle->channel = output;
if (handle->channel >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
ret = wrtd_out_trigger_index_get(wrtd, tid);
if (ret < 0)
return ret;
handle->ptr_trig = ret;
tlv = wrtd_trigger_tlv(handle->ptr_trig, &trig);
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
trig.flags |= ENTRY_FLAG_VALID;
trig.id = *tid;
memset(&trig.ocfg[handle->channel], 0, sizeof(struct lrt_output_rule));
trig.ocfg[handle->channel].delay_cycles = 100000000 / 8000;
trig.ocfg[handle->channel].state = HASH_ENT_DISABLED;
trig.ocfg[handle->channel].state |= HASH_ENT_DIRECT;
trig.ocfg[handle->channel].cond_ptr = -1;
err = trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
err = wrtd_out_trigger_insert(wrtd, handle->ptr_trig);
if (err)
return err;
return wrtd_out_flag_set(dev, handle->channel, WRTD_TRIGGER_ASSIGNED);
}
/**
* It assign a trigger to an output channel
* @param[in] dev pointer to open node device.
* @param[in] output index (0-based) of output channel
* @param[out] handle
* @param[in] trig trigger id to assign
* @param[in] condition trigger id to assign to the condition
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_trig_assign(struct wrtd_node *dev, unsigned int output,
struct wrtd_trigger_handle *handle,
struct wrtd_trig_id *tid,
struct wrtd_trig_id *condition)
{
struct wrtd_trigger_handle tmp_handle;
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = wrtd_out_trig_assign_one(dev, output, handle, tid);
if (err)
return err;
/* Return now for direct triggers. */
if (!condition)
return 0;
/* Setup the condition trigger. */
err = wrtd_out_trig_assign_one(dev, output, &tmp_handle, condition);
if (err)
return err;
handle->ptr_cond = tmp_handle.ptr_trig;
return wrtd_out_trig_assign_condition_by_index(dev, output,
handle->ptr_trig,
handle->ptr_cond);
}
/**
* Un-assign a give trigger
* @param[in] dev pointer to open node device.
* @param[in] handle
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_trig_unassign(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_output_trigger_state triggers[256];
struct wrtd_out_trigger trig;
struct trtl_tlv tlv = wrtd_trigger_tlv(handle->ptr_trig,
&trig);
struct wrtd_output_trigger_state state;
int err, cnt = 0, i;
volatile int cond;
if (handle->channel >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
cond = trig.ocfg[handle->channel].cond_ptr;
memset(&trig.ocfg[handle->channel], 0, sizeof(struct lrt_output_rule));
for (i = 0; i < FD_NUM_CHANNELS; i++)
if (trig.ocfg[i].state == HASH_ENT_EMPTY)
cnt++;
if (cnt == FD_NUM_CHANNELS)
trig.flags &= ~ENTRY_FLAG_VALID;
err = trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
err = wrtd_out_trigger_remove(wrtd, handle->ptr_trig);
if (err)
return err;
err = wrtd_out_trig_get_all(dev, handle->channel, triggers, 256);
if (err < 0)
return -1;
if (err == 0){
err = wrtd_out_flag_clr(dev, handle->channel,
WRTD_TRIGGER_ASSIGNED);
} else {
err = 0;
}
if (cond < 0 || cond > FD_HASH_ENTRIES)
return err;
/* Remove also its condition */
err = wrtd_out_trig_state_get_by_index(dev, cond,
handle->channel, &state);
if (err)
return err;
return wrtd_out_trig_unassign(dev, &state.handle);
}
/**
* It retreive a given number of triggers from output device
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[out] triggers list of assigned trigger
* @param[in] max_count maximum triggers to retreive
* @return number of triggers on success, -1 on error and
* errno is set appropriately
*/
int wrtd_out_trig_get_all(struct wrtd_node *dev, unsigned int output,
struct wrtd_output_trigger_state *triggers,
int max_count)
{
struct wrtd_output_trigger_state tmp;
int err = 0, i, count = 0;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
for (i = 0; count < max_count && i < FD_HASH_ENTRIES; i++) {
err = wrtd_out_trig_state_get_by_index(dev, i, output, &tmp);
if (err) {
if (errno == EWRTD_NOFOUND_TRIGGER) {
err = 0;
continue;
} else {
break;
}
} else {
memcpy(&triggers[count], &tmp,
sizeof(struct wrtd_output_trigger_state));
count++;
}
}
/* Do not count trigger with error */
if (err)
count--;
return count > 0 ? count : err;
}
/**
* It returns a trigger state from a given handle.
* @param[in] dev pointer to open node device.
* @param[in] handle trigger where act on
* @param[out] trigger trigger status
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_trig_state_get_by_handle(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle,
struct wrtd_output_trigger_state *trigger)
{
return wrtd_out_trig_state_get_by_index(dev, handle->ptr_trig,
handle->channel, trigger);
}
/**
* It returns a trigget from a given identifier.
* Whenever is possible you should prefer wrtd_out_trig_state_get_by_handle()
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[in] id identifier of the trigger to retrieve
* @param[out] trigger trigger status
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_trig_state_get_by_id(struct wrtd_node *dev,
unsigned int output,
struct wrtd_trig_id *tid,
struct wrtd_output_trigger_state *trigger)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
int index;
index = wrtd_out_trigger_index_get(wrtd, tid);
if (index < 0) {
errno = EWRTD_NOFOUND_TRIGGER;
return -1;
}
return wrtd_out_trig_state_get_by_index(dev, index, output, trigger);
}
/**
* It returns a trigget from a given index. The index may change due to trigger
* assing and un-assing. So, before use this function you have to check the
* current trigger's indexes. Note that this is not thread safe.
* Whenever is possible you should prefer wrtd_out_trig_state_get_by_handle()
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[out] trigger trigger status
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_trig_state_get_by_index(struct wrtd_node *dev, unsigned int index,
unsigned int output,
struct wrtd_output_trigger_state *trigger)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_trigger trig;
struct trtl_tlv tlv = wrtd_trigger_tlv(index, &trig);
struct wrtd_output_trigger_state cond;
int err;
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
if (!(trig.flags & ENTRY_FLAG_VALID) ||
(trig.ocfg[output].state == HASH_ENT_EMPTY)) {
errno = EWRTD_NOFOUND_TRIGGER;
return -1;
}
memset(trigger, 0, sizeof(struct wrtd_output_trigger_state));
trigger->handle.channel = output;
trigger->handle.ptr_trig = index;
trigger->handle.ptr_cond = (uint32_t)trig.ocfg[output].cond_ptr;
trigger->is_conditional = (0 <= trigger->handle.ptr_cond && trigger->handle.ptr_cond <= FD_HASH_ENTRIES);
trigger->enabled = !(trig.ocfg[output].state & HASH_ENT_DISABLED);
trigger->trigger = trig.id;
trigger->delay_trig.ticks = trig.ocfg[output].delay_cycles;
trigger->delay_trig.frac = trig.ocfg[output].delay_frac;
if (trig.ocfg[output].latency_avg_nsamples) {
trigger->latency_average_us = (trig.ocfg[output].latency_avg_sum /
trig.ocfg[output].latency_avg_nsamples + 124) / 125;
} else {
trigger->latency_average_us = 0;
}
trigger->latency_worst_us = (trig.ocfg[output].latency_worst + 124)
/ 125;
trigger->executed_pulses = trig.ocfg[output].hits;
trigger->missed_pulses = trig.ocfg[output].misses;
if (!trigger->is_conditional)
return 0;
/* Get conditional trigger */
err =wrtd_out_trig_state_get_by_index(dev, trigger->handle.ptr_cond,
output, &cond);
if (err)
return err;
memcpy(&trigger->condition, &cond.trigger, sizeof(struct wrtd_trig_id));
memcpy(&trigger->delay_cond, &cond.delay_trig,
sizeof(struct wr_timestamp));
return 0;
}
static int wrtd_out_rule_delay_set(struct wrtd_node *dev,
int output,
uint32_t trig_idx,
uint64_t delay_ps)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_trigger trig;
struct trtl_tlv tlv = wrtd_trigger_tlv(trig_idx, &trig);
struct wr_timestamp t;
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
if (delay_ps > (1000 * 1000 * 1000 * 1000ULL - 1000ULL)) {
errno = EWRTD_INVALID_DELAY;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
if (!(trig.flags & ENTRY_FLAG_VALID)) {
errno = EWRTD_NOFOUND_TRIGGER;
return -1;
}
wrtd_pico_to_ts(&delay_ps, &t);
trig.ocfg[output].delay_cycles = t.ticks;
trig.ocfg[output].delay_frac = t.frac;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* It sets the delay to apply for a given trigger
* @param[in] dev pointer to open node device.
* @param[in] handle trigger where act on
* @param[in] delay_ps delay in pico-seconds in range [0, 999999999000]
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_trig_delay_set(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle,
uint64_t delay_ps)
{
return wrtd_out_rule_delay_set (dev, handle->channel, handle->ptr_trig, delay_ps);
}
/**
* Sets the pulse width for a given output channel.
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[in] width_ps pulse width in pico-seconds (from 250ns to 1s)
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_pulse_width_set(struct wrtd_node *dev, unsigned int output,
uint64_t width_ps)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct trtl_tlv tlv = wrtd_channel_tlv(output, &chan);
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
if (width_ps < 1000ULL * 250 ||
width_ps >= 1000ULL * 1000 * 1000 * 1000) {
errno = EWRTD_INVALID_PULSE_WIDTH;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
chan.config.width_cycles = width_ps / 8000ULL;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* It set the dead time for a given output channel. so, it applies on all
* triggers assigned to the given output channel.
*
* The function will round the value, so it may happen that you read back a
* different value. The reason is that the RT application measure the dead
* time in ticks, which are 8ns steps. So this function will internally
* convert the dead time in ticks. The function accept pico-seconds only to
* be consistent with the API.
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[in] dead_time_ps dead time in pico-seconds
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_dead_time_set(struct wrtd_node *dev, unsigned int output,
uint64_t dead_time_ps)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct trtl_tlv tlv = wrtd_channel_tlv(output, &chan);
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
chan.config.dead_time = dead_time_ps / 8000;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* @param[in] dev pointer to open node device.
* @param[in] handle trigger where act on
* @param[in] delay_ps delay in pico-seconds in range [0, 999999999000]
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_trig_condition_delay_set(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle,
uint64_t delay_ps)
{
if (handle->ptr_cond == 0)
{
errno = EWRTD_NO_TRIGGER_CONDITION;
return -1;
}
return wrtd_out_rule_delay_set (dev, handle->channel, handle->ptr_cond, delay_ps);
}
/**
* @param[in] dev pointer to open node device.
* @param[in] handle trigger where act on
* @param[in] enable 1 to enable, 0 to disable
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_trig_enable(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle, int enable)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_trigger trig;
struct trtl_tlv tlv = wrtd_trigger_tlv(handle->ptr_trig,
&trig);
int err;
if (handle->channel >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
if (!(trig.flags & ENTRY_FLAG_VALID)) {
errno = EWRTD_NOFOUND_TRIGGER;
return -1;
}
if (enable)
trig.ocfg[handle->channel].state &= ~HASH_ENT_DISABLED;
else
trig.ocfg[handle->channel].state |= HASH_ENT_DISABLED;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* It sets the trigger mode of a given output channel
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[in] mode output mode
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_trigger_mode_set(struct wrtd_node *dev,
unsigned int output,
enum wrtd_trigger_mode mode)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct trtl_tlv tlv = wrtd_channel_tlv(output, &chan);
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
chan.config.mode = mode;
chan.config.flags &= ~(WRTD_TRIGGERED | WRTD_LAST_VALID);
if (chan.config.mode == WRTD_TRIGGER_MODE_SINGLE) {
chan.config.flags &= ~WRTD_ARMED;
chan.config.state = OUT_ST_IDLE;
}
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* It arms (un-arms) a given output channel
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[in] armed 1 to arm, 0 to un-arm
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_arm(struct wrtd_node *dev, unsigned int output, int armed)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct trtl_tlv tlv = wrtd_channel_tlv(output, &chan);
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
chan.config.flags &= ~WRTD_TRIGGERED;
if (armed) {
chan.config.flags |= WRTD_ARMED;
chan.config.state = OUT_ST_ARMED;
} else {
chan.config.flags &= ~WRTD_ARMED;
chan.config.state = OUT_ST_IDLE;
}
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_counters_reset(struct wrtd_node *dev, unsigned int output)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct trtl_tlv tlv = wrtd_channel_tlv(output, &chan);
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
chan.stats.hits = 0;
chan.stats.miss_timeout = 0;
chan.stats.miss_deadtime = 0;
chan.stats.miss_no_timing = 0;
chan.stats.miss_overflow = 0;
chan.config.flags &= ~WRTD_LAST_VALID;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* Reset global counters
* @param[in] dev device token
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_global_counters_reset(struct wrtd_node *dev)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out out;
struct trtl_tlv tlv;
int err;
tlv.type = OUT_STRUCT_DEVICE;
tlv.size = sizeof(struct wrtd_out);
tlv.buf = &out;
err = trtl_fw_buffer_get(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
if (err)
return err;
out.counter_etherbone = 0;
out.counter_loopback = 0;
return trtl_fw_buffer_set(wrtd->trtl, WRTD_CPU_FD, 0, &tlv, 1);
}
/**
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_check_triggered(struct wrtd_node *dev, unsigned int output)
{
struct wrtd_output_state st;
int err;
err = wrtd_out_state_get(dev, output, &st);
if(err)
return err;
return st.flags & WRTD_TRIGGERED ? 1 : 0;
}
/**
* Check the enable status on a trigger output.
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[out] enable 1 if it is enabled, 0 otherwise
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_is_enabled(struct wrtd_node *dev, unsigned int output,
unsigned int *enable)
{
struct wrtd_output_state state;
int err;
err = wrtd_out_state_get(dev, output, &state);
if (err)
return -1;
*enable = !!(state.flags & WRTD_ENABLED);
return 0;
}
/**
* Check the armed status on a trigger output.
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[out] armed 1 if it is enabled, 0 otherwise
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_is_armed(struct wrtd_node *dev, unsigned int output,
unsigned int *armed)
{
struct wrtd_output_state state;
int err;
err = wrtd_out_state_get(dev, output, &state);
if (err)
return -1;
*armed = !!(state.flags & WRTD_ARMED);
return 0;
}
/**
* Check the trigger assigned status on a trigger output. If you provide
* a trigger identifier then the function checks that the given trigger
* is assigned to the given channel. Otherwise it will tell you if there
* is any trigger assigned to the channel.
* @param[in] dev device token
* @param[in] output index (0-based) of output channel
* @param[in] id trigger identifier (optional)
* @param[out] armed 1 if it is enabled, 0 otherwise
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_has_trigger(struct wrtd_node *dev, unsigned int output,
struct wrtd_trig_id *id, unsigned int *assigned)
{
struct wrtd_output_trigger_state triggers[256];
struct wrtd_output_state state;
int ret, i;
/* Set default output */
*assigned = 0;
ret = wrtd_out_state_get(dev, output, &state);
if (ret)
return -1;
if (!id) {
/* Check only if there is at least one trigger */
*assigned = !!(state.flags & WRTD_TRIGGER_ASSIGNED);
return 0;
}
/* Look for the id among all assigned trigger */
ret = wrtd_out_trig_get_all(dev, output, triggers, 256);
if (ret < 0)
return -1;
for (i = 0; i < ret; i++) {
if (wrtd_trig_id_cmp(id, &triggers[i].trigger) == 0) {
*assigned = 1;
return 0;
}
}
return 0;
}
/**
* It check if the output real-time application is alive
* @param[in] dev device token
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_ping(struct wrtd_node *dev)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
return trtl_fw_ping(wrtd->trtl, WRTD_CPU_FD, 0);
}
/**
* It gets the output base time
* @param[in] dev device token
* @param[out] ts output device base time
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_base_time(struct wrtd_node *dev, struct wr_timestamp *ts)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
uint32_t variables[] = {OUT_VAR_DEVICE_TIME_S, 0,
OUT_VAR_DEVICE_TIME_T, 0};
int err;
err = trtl_fw_variable_get(wrtd->trtl, WRTD_CPU_FD, 0, variables, 2);
if (err)
return err;
ts->seconds = variables[1];
ts->ticks = variables[3];
return 0;
}
/**
* It gets the output version
* @param[in] dev device token
* @param[out] version the RT application version
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_out_version(struct wrtd_node *dev, struct trtl_fw_version *version)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
return trtl_fw_version(wrtd->trtl, WRTD_CPU_FD, 0, version);
}
/**
* It tells if the ouput firmware is valid
* @param[in] dev device token
* @param[out] version the RT application version
* @return 1 when valid, 0 if invalid or error (and errno is set appropriately)
*/
int wrtd_out_is_valid(struct wrtd_node *dev)
{
struct trtl_fw_version version;
int err;
err = wrtd_out_version(dev, &version);
if (err)
return 0;
if (version.rt_id != WRTD_OUT_RT_ID) {
errno = EWRTD_INVALID_IN_APP;
return 0;
}
return 1;
}
/*
* Copyright (C) 2014 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* inspired by a draft of Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* License: GPL v3
*/
#ifndef __WRTD_LIB_H__
#define __WRTD_LIB_H__
/** @file libwrtd.h */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdio.h>
#include "libmockturtle.h"
/**
* @file wrtd-common.h
*/
#include "wrtd-common.h"
struct wrtd_node;
#define WRTD_DEFAULT_TIMEOUT 1000
/**
* @enum wrtd_error_list
* White Rabbit Trigger Distribution errors
*/
enum wrtd_error_list {
EWRTD_INVALID_ANSWER_ACK = 3276,
EWRTD_INVALID_ANSWER_STATE,
EWRTD_INVALID_BINARY,
EWRTD_INVALID_DEAD_TIME,
EWRTD_INVALID_DELAY,
EWRTD_INVALID_TRIG_ID,
EWRTD_INVALID_CHANNEL,
EWRTD_NO_IMPLEMENTATION,
EWRTD_INVALID_ANSWER_TRIG,
EWRTD_INVALID_ANSWER_HASH,
EWRTD_INVALID_ANSWER_HASH_CONT,
EWRTD_INVALID_ANSWER_HANDLE,
EWRTD_NOFOUND_TRIGGER,
EWRTD_NO_TRIGGER_CONDITION,
EWRTD_INVALID_PULSE_WIDTH,
EWRTD_INVALID_IN_APP,
EWRTD_INVALID_OUT_APP,
__EWRTD_MAX_ERROR_NUMBER,
};
/**
* Trigger token
*/
struct wrtd_trigger_handle {
uint32_t ptr_cond; /**< trigger condition pointer */
uint32_t ptr_trig; /**< trigger pointer */
int channel; /**< channel assigned to the trigger */
};
/**
* Status description for an input channel
*/
struct wrtd_input_state {
int input; /**< Input channel index */
uint32_t flags; /**< enum list_io_flags */
uint32_t log_level; /**< enum list_log_level */
enum wrtd_trigger_mode mode; /**< Trigger mode in use */
uint32_t total_pulses; /**< Number of incoming pulses detected */
uint32_t sent_triggers; /**< Number of triggers sent over the
white-rabbit network */
uint32_t sent_packets; /**< Number of packets sent over the
white-rabbit network */
uint32_t miss_no_timing; /**< Number of pulse missing due to no WR
timing */
struct wrtd_trigger_entry last_sent; /**< Description of the last
trigger sent */
struct wrtd_trig_id assigned_id; /**< trigger assigned to this channel */
struct wr_timestamp dead_time; /**< Configured dead time */
struct wr_timestamp delay; /**< Time delay assined */
struct wr_timestamp last_pulse; /** Time stamp of the last
detected pulse*/
struct wr_timestamp tdc_timebase_offset; /**< TDC time base offset */
};
/**
* Status description for a trigger on output
*/
struct wrtd_output_trigger_state {
int is_conditional; /**< tell if the trigger is under condition or not */
int enabled; /**< tell if the trigger is enable, so it may be
generater as output */
struct wrtd_trig_id trigger; /**< Trigger identifier */
struct wrtd_trig_id condition; /**< Trigger identifier for the trigger
condition */
struct wr_timestamp delay_trig; /**< Configured trigger delay */
struct wr_timestamp delay_cond; /**< Configured trigger condition delay */
struct wrtd_trigger_handle handle;
int latency_worst_us; /**< Worst latency in micro-seconds */
int latency_average_us; /**< Average latency in micro-seconds */
uint32_t executed_pulses; /**< Number of executed pulses */
uint32_t missed_pulses; /**< Number of missed pulses */
void *private_data; /**< private pointer used by the library */
};
/**
* Status description for an output channel
*/
struct wrtd_output_state {
int output; /**< Output channel index */
uint32_t executed_pulses; /**< Number of generated pulses */
uint32_t missed_pulses_late; /**< Number of missed pulses due to: */
uint32_t missed_pulses_deadtime; /**< Number of missed pulses due to: */
uint32_t missed_pulses_overflow; /**< Number of missed pulses due to: */
uint32_t missed_pulses_no_timing; /**< Number of missed pulses due to: */
struct wrtd_trigger_entry last_executed; /**< Trigger description of the
last generated trigger */
struct wrtd_trigger_entry last_received; /**< Trigger description of the
last received trigger from
the white-rabbit network */
struct wrtd_trigger_entry last_enqueued; /**< Trigger description of
the last enqueued trigger
in the execution queue */
struct wrtd_trigger_entry last_lost; /**< Trigger description of the
last lost trigger */
uint32_t flags; /**< enum list_io_flags */
uint32_t log_level; /**< enum list_log_level */
enum wrtd_trigger_mode mode; /**< Trigger mode in use */
struct wr_timestamp dead_time; /**< Configured dead time */
struct wr_timestamp pulse_width; /**< Pulse width */
uint32_t received_messages; /**< Number of received packets from
the network */
uint32_t received_loopback;
};
/**
* @file libwrtd-common.c
*/
/**
* @defgroup dev
* Set of functions to manage the basic device and library configuration.
* @{
*/
extern int wrtd_init();
extern void wrtd_exit();
extern struct wrtd_node *wrtd_open(uint32_t device_id);
extern void wrtd_close(struct wrtd_node *dev);
extern struct trtl_dev *wrtd_get_trtl_dev(struct wrtd_node *dev);
extern int wrtd_in_load(struct wrtd_node *dev, char *fw);
extern int wrtd_out_load(struct wrtd_node *dev, char *fw);
extern int wrtd_out_is_valid(struct wrtd_node *dev);
extern int wrtd_in_is_valid(struct wrtd_node *dev);
extern int wrtd_white_rabbit_sync(struct wrtd_node *dev,
unsigned long timeout_s);
extern int wrtd_time_get(struct wrtd_node *dev, unsigned int input,
struct wr_timestamp *current_time);
/**@}*/
/**
* @defgroup util Utilities
* Set of utilities
* @{
*/
extern const char *wrtd_strerror(int err);
extern void wrtd_ts_to_pico(struct wr_timestamp *ts, uint64_t *pico);
extern void wrtd_pico_to_ts(uint64_t *pico, struct wr_timestamp *ts);
extern void wrtd_ts_to_sec_pico(struct wr_timestamp *ts,
uint64_t *sec, uint64_t *pico);
extern void wrtd_sec_pico_to_ts(uint64_t sec, uint64_t pico,
struct wr_timestamp *ts);
extern int wrtd_ts_sub(struct wr_timestamp *res,
struct wr_timestamp *l, struct wr_timestamp *r);
/**@}*/
/**
* @defgroup log Logging
* Set of logging functions for input and output channels
* @{
*/
extern const char *wrtd_strlogging(enum wrtd_log_level lvl);
enum wrtd_log_level wrtd_strlogging_to_level(char *log);
extern void wrtd_strlogging_full(char *buf, uint32_t log_level);
extern int wrtd_log_read(struct wrtd_node *dev,
struct wrtd_log_entry *log,
int count, int poll_timeout);
extern int wrtd_in_log_level_set(struct wrtd_node *dev, unsigned int input,
uint32_t log_level);
extern int wrtd_in_log_level_get(struct wrtd_node *dev, unsigned int input,
uint32_t *log_level);
extern int wrtd_out_log_level_set(struct wrtd_node *dev, unsigned int output,
uint32_t log_level);
extern int wrtd_out_log_level_get(struct wrtd_node *dev, unsigned int input,
uint32_t *log_level);
/**@}*/
/**
* @file libwrtd-input.c
*/
/**
* @defgroup input Input Management
* Set of functions to handle input channels
* @{
*/
extern int wrtd_in_state_get(struct wrtd_node *dev, unsigned int input,
struct wrtd_input_state *state);
extern int wrtd_in_enable(struct wrtd_node *dev, unsigned int input, int enable);
extern int wrtd_in_trigger_assign(struct wrtd_node *dev, unsigned int input,
struct wrtd_trig_id *trig_id);
extern int wrtd_in_trigger_unassign(struct wrtd_node *dev, unsigned int input);
extern int wrtd_in_trigger_mode_set(struct wrtd_node *dev, unsigned int input,
enum wrtd_trigger_mode mode);
extern int wrtd_in_trigger_software(struct wrtd_node *dev,
struct wrtd_trigger_entry *trigger);
extern int wrtd_in_arm(struct wrtd_node *dev, unsigned int input, int armed);
extern int wrtd_in_dead_time_set(struct wrtd_node *dev, unsigned int input,
uint64_t dead_time_ps);
extern int wrtd_in_delay_set(struct wrtd_node *dev, unsigned int input,
uint64_t delay_ps);
extern int wrtd_in_timebase_offset_set(struct wrtd_node *dev,
unsigned int input, uint64_t offset);
extern int wrtd_in_counters_reset(struct wrtd_node *dev, unsigned int input);
extern int wrtd_in_global_counters_reset(struct wrtd_node *dev);
extern int wrtd_in_seq_counter_set (struct wrtd_node *dev, unsigned int input,
unsigned int value);
extern int wrtd_in_is_enabled(struct wrtd_node *dev, unsigned int input,
unsigned int *enable);
extern int wrtd_in_is_armed(struct wrtd_node *dev, unsigned int input,
unsigned int *armed);
extern int wrtd_in_has_trigger(struct wrtd_node *dev, unsigned int input,
unsigned int *assigned);
extern int wrtd_in_ping(struct wrtd_node *dev);
extern int wrtd_in_base_time(struct wrtd_node *dev, struct wr_timestamp *ts);
extern int wrtd_in_version(struct wrtd_node *dev,
struct trtl_fw_version *version);
extern int wrtd_in_dead_time_get(struct wrtd_node *dev, unsigned int input,
uint64_t *dead_time_ps);
extern int wrtd_in_delay_get(struct wrtd_node *dev, unsigned int input,
uint64_t *delay_ps);
/**@}*/
/**
* @file libwrtd-output.c
*/
/**
* @defgroup output Output Management
* Set of functions to handle output channels
* @{
*/
extern int wrtd_out_state_get(struct wrtd_node *dev, unsigned int output,
struct wrtd_output_state *state);
extern int wrtd_out_enable(struct wrtd_node *dev, unsigned int output,
int enable);
extern int wrtd_out_trig_assign(struct wrtd_node *dev, unsigned int output,
struct wrtd_trigger_handle *handle,
struct wrtd_trig_id *trig,
struct wrtd_trig_id *condition);
extern int wrtd_out_trig_unassign(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle);
extern int wrtd_out_trig_get_all (struct wrtd_node *dev, unsigned int output,
struct wrtd_output_trigger_state *triggers,
int max_count);
extern int wrtd_out_trig_state_get_by_index(struct wrtd_node *dev,
unsigned int index,
unsigned int output,
struct wrtd_output_trigger_state *trigger);
extern int wrtd_out_trig_state_get_by_id(struct wrtd_node *dev,
unsigned int output,
struct wrtd_trig_id *id,
struct wrtd_output_trigger_state *trigger);
extern int wrtd_out_trig_state_get_by_handle(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle,
struct wrtd_output_trigger_state *state);
extern int wrtd_out_trig_delay_set(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle,
uint64_t delay_ps);
extern int wrtd_out_dead_time_set(struct wrtd_node *dev, unsigned int output,
uint64_t dead_time_ps);
extern int wrtd_out_pulse_width_set(struct wrtd_node *dev, unsigned int output,
uint64_t pulse_width_ps);
extern int wrtd_out_trig_enable(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle, int enable);
extern int wrtd_out_ping(struct wrtd_node *dev);
extern int wrtd_out_base_time(struct wrtd_node *dev, struct wr_timestamp *ts);
extern int wrtd_out_version(struct wrtd_node *dev,
struct trtl_fw_version *version);
extern int wrtd_out_trigger_mode_set(struct wrtd_node *dev,
unsigned int output,
enum wrtd_trigger_mode mode);
extern int wrtd_out_trig_condition_delay_set(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle,
uint64_t delay_ps);
extern int wrtd_out_arm(struct wrtd_node *dev, unsigned int input, int armed);
extern int wrtd_out_counters_reset(struct wrtd_node *dev, unsigned int output);
extern int wrtd_out_global_counters_reset(struct wrtd_node *dev);
extern int wrtd_out_check_triggered(struct wrtd_node *dev, unsigned int output);
extern int wrtd_out_is_enabled(struct wrtd_node *dev, unsigned int output,
unsigned int *enable);
extern int wrtd_out_is_armed(struct wrtd_node *dev, unsigned int output,
unsigned int *armed);
extern int wrtd_out_has_trigger(struct wrtd_node *dev, unsigned int output,
struct wrtd_trig_id *id, unsigned int *assigned);
extern int wrtd_out_trigger_sw_now(struct wrtd_node *dev, unsigned int output);
extern int wrtd_out_trigger_sw(struct wrtd_node *dev, unsigned int output,
struct wr_timestamp *ts);
/**@}*/
#ifdef __cplusplus
};
#endif
#endif
Library Overview {#mainpage}
================
This is the **WRTD** library documentation. Here you can find all
the information about the *White-Rabbit Trigger-Distribution* API and the main
library behavior that you need to be aware of.
If you are reading this from the doxygen documentation, then you can find
the API documentation in the usual Doxygen places. Otherwise, you can get
the API documentation directly from the source code that you can find in
the *lib* directory.
In this document we are going to provides you some clues to understand how
to use the library API.
This library is completely base on the *White-Rabbit Node-Core* library.
It uses all its features to establish the communication between the
Trigger Distribution Real Time applications. This library hides the knowledge
about the conventions (protocol) used between the Host and the Real Time
applications and it exposes a simple API for the interaction.
While reading any documentation we suggest you to read the dictionary to avoid
misinterpretation.
Overview
========
The White-Rabbit Trigger-Distribution is a system that allow its users to detect
a trigger (pulse), propagate it over the White-Rabbit network and reproduce it
on a remote machine. This library is in charge to ease the configuration of this
system. The system is based on the White-Rabbit Node-Core. There are two cores
running separately two Real Time applications: one to manage the input,
one to manage the output.
+--------------Trigger-Distribution-System-------------+
| RealTime App - - - - - - - - - RealTime App |
-\ | +-------+ ( ) +--------+ | /-
|--------|->| INPUT |--->( WhiteRabbit Network )--->| OUTPUT |--|------->|
-/ PULSE | +-------+ ( ) +--------+ | PULSE \-
| - - - - - - - - - |
+------------------------------------------------------+
Initialization
==============
To be able to use this library the first thing to do is to initialize a library
instance using wrtd_init(); form this point on you are able to use the
library API. Of course, when you finished to use the library you have to
remove this instance using wrtd_exit().
At the beginning, all communication channels are close, so before start to
communicate with the Real Time application you have to open your communication
channel. Then, close it when you have done.
Logging
=======
The WRTD Real Time applications are able to provide some logging information
about the things happening on the FPGA. This interface is read only, so
you can only read logging messages. There are only two configuration parameters:
one for the *logging level*; the other one to set the exclusivity access to the
logging interface. When the logging interface is shared, then also other users
are allowed to get the same messages.
Input
=====
The *input* Real Time application and the associated part of library manages
the detection of the incoming pulse and their correct propagation over the
white-rabbit network as trigger event.
The library allows the user to fully configure the input parameter and to get
the current status of Real Time application but also to get information about
the triggers associated to the input channels. Go directly to the API for the
list of parameters that you can set.
Output
======
The *input* Real Time application and the associated part of library manages
the pluse generation and their correct reception from the white-rabbit
network as trigger event.
The library allows the user to fully configure the output parameter and to get
the current status of Real Time application but also to get information about
the trigger associated to the output channesl. Go directly to the API for the
list of parameters that you can set.
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