Commit 7beb4a65 authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'new-tools'

parents 071c70f7 25f5c310
FMC_BUS := $(shell scripts/check-submodule fmc-bus $(FMC_BUS))
ZIO := $(shell scripts/check-submodule zio $(ZIO))
SPEC_SW := $(shell scripts/check-submodule spec-sw $(SPEC_SW))
.PHONY: all clean modules install modules_install
.PHONY: all clean modules install modules_install default
.PHONY: gitmodules prereq prereq_install prereq_install_warn
DIRS = kernel tools lib
DIRS = kernel lib tools
all clean modules install modules_install: gitmodules
all clean modules install modules_install:
@if echo $@ | grep -q install; then $(MAKE) prereq_install_warn; fi
for d in $(DIRS); do $(MAKE) -C $$d $@ || exit 1; done
for d in $(DIRS); do $(MAKE) ZIO=$(ZIO) FMC_BUS=$(FMC_BUS) -C $$d $@ || exit 1; done
all modules: prereq
......@@ -15,15 +18,8 @@ CONFIG_WR_NIC=n
export CONFIG_WR_NIC
#### The following targets are used to manage prerequisite repositories
gitmodules:
@test -d fmc-bus/doc || echo "Checking out submodules"
@test -d fmc-bus/doc || git submodule update --init
@git submodule update
# The user can override, using environment variables, all these three:
FMC_BUS ?= fmc-bus
ZIO ?= zio
SPEC_SW ?= spec-sw
SUBMOD = $(FMC_BUS) $(ZIO) $(SPEC_SW)
prereq:
......@@ -36,3 +32,5 @@ prereq_install_warn:
prereq_install:
for d in $(SUBMOD); do $(MAKE) -C $$d modules_install || exit 1; done
touch .prereq_installed
include scripts/gateware.mk
......@@ -634,14 +634,21 @@ to access library internals from a user file just define
@item The driver header is called @code{fine-delay.h} while the user one
is @code{fdelay-lib.h}. The latter includes the former, which user
programs should not refer to. Both are different from the original
implementation (@code{fdelay_lib.h}) to avoid trying to compile older
code with new headers.
programs should not refer to.
@item The @i{tools} directory hosts the suggested command-line tools
to use the device for testing and quick access. They demonstrate use
of the library functions using internally-consistent command line
conventions. All command names begin with @t{fmc-fdelay-}
@item The @i{oldtools} directory includes tools that access @sc{zio}
directly. Their name begins with @code{fd-raw-} (but there is a
non-fine-delay tool to generate pulses on the parallel port, which has
a different name pattern).
directly; they are not built by default any more because they are now
deprecated; we also removed documentation for them, for the same
reason. We keep them for our previous users, in case they still want
to run previous scripts the saved in the past. The directory
also includes tools that used to be built withing @t{lib/} and
are deprecated as well. The old tools use
the name patterns @code{fd-raw-} and @code{fdelay-}
@item The @i{lib} directory contains the userspace library, providing a
simple C API to access the driver.
......@@ -818,7 +825,8 @@ The library offers the following functions that deal with the input stamps:
@end table
Example code: @code{fmc-fdelay-read} tool.
The test programs for the functions are in @i{oldtools/}, not built by
default.
@c ==========================================================================
@node Output Configuration
......@@ -902,10 +910,284 @@ Example code: @code{fmc-fdelay-pulse} tool.
@end table
@c ##########################################################################
@node Command line tools
@chapter Command line tools
@node Command Line Tools
@chapter Command Line Tools
This chapter describes the command line tools that come with the
driver and reside in the @code{tools/} subdirectory. They are provided
as diagnostic utilities and to demonstrate how to use the library.
@c ==========================================================================
@node General Command Line Conventions
@section General Command Line Conventions
Most tools accept the following command-line options, in a
consistent way:
@table @code
@item -d <devid>
@itemx -i <index>
Used to select one board among several. See the description
of @i{fdelay_open} in @ref{Initialization and Cleanup}. If no
argument is given, the ``first'' board is used (index is 0).
@end table
@c ==========================================================================
@node fmc-fdelay-list
@section fmc-fdelay-list
The command takes no arguments. It reports the list of available
boards in the current system:
@smallexample
spusa# ./tools/fmc-fdelay-list
./tools/fmc-fdelay-list: found 1 board
dev_id 0200, /dev/zio/zio-fd-0200, /sys/bus/zio/devices/zio-fd-0200
@end smallexample
@c ==========================================================================
@node fmc-fdelay-term
@section fmc-fdelay-term
The command can be used to activate or deactivate the 50 ohm
termination resistor.
In addition to the @t{-i} or @t{-d}
arguments, mandatory if more than one board is found on the
host system, the command receives one optional argument, either
@t{1} or @t{on} (activate termination) or @t{0} or @t{off}
(deactivate termination).
@smallexample
spusa# ./tools/fmc-fdelay-term on
./tools/fmc-fdelay-term: termination is on
@end smallexample
If no arguments are passed the termination status is reported back but
not changed.
@c ==========================================================================
@node fmc-fdelay-board-time
@section fmc-fdelay-board-time
The command is used to act on the time notion of the @sc{fine-delay} card.
In addition to the @t{-i} or @t{-d}
arguments, mandatory if more than one board is found on the
host system, the command receives one mandatory argument, that is
either a command or a floating point number. The number is the
time, in seconds, to be set in the card; the command is one of
the following ones:
@table @code
@item get
Read board time and print to @i{stdout}.
@item host
Set board time from host time
@item wr
Lock the boards to White Rabbit time. It may block if no White
Rabbit is there. No timeout is currently available.
@item local
Detach the board from White Rabbit, and run local time instead.
@end table
Examples:
@smallexample
spusa# ./lib/fdelay-board-time 25.5; ./lib/fdelay-board-time get
25.504007360
spusa# ./lib/fdelay-board-time get
34.111048968
spusa# ./lib/fdelay-board-time host
spusa# ./lib/fdelay-board-time get
1335974946.493415600
@end smallexample
@c ==========================================================================
@node fmc-fdelay-input
@section fmc-fdelay-input
The tool reports input pulses to stdout. It receives the
usual @t{-i} or @t{-d} arguments to select one board, mandatory
if more than one @sc{fine-delay} card is found.
It receives the following options:
@table @code
@item -c <count>
Number of pulses to print. Default (0) means run forever.
@item -n
Nonblocking mode: just print what is pending in the buffer.
@item -f
Floating point: print as a floatingpoint seconds.pico value.
The default is a human-readable string, where the decimal part
is split.
@item -r
Raw output: print the three hardware timestamps, in decimal.
@end table
This an example output, reading a pps signal through a 16ns cable:
@smallexample
spusa.root# ./tools/fmc-fdelay-input -c 3
seq 10921: time 11984:000,000,015,328 ps
seq 10922: time 11985:000,000,015,410 ps
seq 10923: time 11986:000,000,015,248 ps
spusa.root# ./tools/fmc-fdelay-input -c 3 -r
seq 10924: raw utc 11987, coarse 1, frac 3773
seq 10925: raw utc 11988, coarse 1, frac 3814
seq 10926: raw utc 11989, coarse 1, frac 3794
spusa.root# ./tools/fmc-fdelay-input -c 3 -f
seq 10927: time 11990.000000015328
seq 10928: time 11991.000000015410
seq 10929: time 11992.000000015410
@end smallexample
In a future release we'll support reading concurrently from several
boards.
@c ==========================================================================
@node fmc-fdelay-pulse
@section fmc-fdelay-pulse
The program can be used to program one of the output channels to
output a sequence of pulses. It can parse the following command-line
options:
@table @code
@item -o <output>
Output channels are numbered 1 to 4, as written on the device panel.
Each command invocation can set only one output channel; the
last @t{-o} specified takes precedence.
@item -c <count>
Output repeat count: 0 is the default and means forever
@item -m <mode>
Output mode. Can be @t{pulse}, @t{delay} or @t{disable}.
@item -r <reltime>
Output pulse at a relative time in the future. The time is
a fraction of a second, specified as For pulse mode,
the program adds the current board time in seconds. Please note that
for pulse mode the second is relative, but the fraction is absolute.
So ``@t{-r 1.5}'' will activate output at the middle of the
next second, according to board time. For @i{delay} mode, the
time is a relative delay.
@item -D <date>
Output pulse at a specified date. This is not currently
completed supported (no seconds are parsed, for example)
@c tom says: only seconds:nano
@c @item -f <frequency>
@c
@c Frequency of the output signal. A trailing @t{k} or @t{M}
@c means kilohertz or megaherts. Floating point is allowed
@c but internal approximation is not accounted for. So
@c @t{2.5M} will work, but 2.000001M will probably not.
@c The last frequency or period specified takes precedence.
@c Default frequency is 10Hz.
@item -T <period>
@itemx -w <width>
Period and width of the output signal. A trailing @t{m},
@t{u}, @t{n}, @t{p} means milli, micro, nano, pico, resp.
The parser supports additions and subtractions, e.g.
@t{50m-20n}.
The period defaults to 100ms and the width defaults to 8us
@item -t
Wait for the trigger to happen before returning. The boards reports
a trigger event when the requested pulse sequence is initiated,
either because the absolute time arrived or because an input
pulse was detected and the requested delay elapsed.
@item -p
@itemx -1
Pulse-per-seconds and 10MHz. These are shorthands setting many
parameters.
@item -v
Verbose: report action to stdout before telling the driver.
@end table
This is, for example, how verbose operation reports the request for a single pulse 300ns wide, 2 microseconds into the next second.:
@smallexample
spusa.root# ./tools/fmc-fdelay-board-time get; \
./tools/fmc-fdelay-pulse -i 0 -o 1 -m pulse -r 2u -w 300n -c 1 -t -v
WR Status: disabled.
Time: 13728.801090400
Channel 1, mode pulse, repeat 1
start time 13729:000,002,000,000 ps
end time 13729:000,002,300,000 ps
loop time 0:100,000,000,000 ps
Channel 1, mode pulse, repeat 1
start raw utc 13729, coarse 250, frac 0
end raw utc 13729, coarse 287, frac 2048
loop raw utc 0, coarse 12500000, frac 0
@end smallexample
@c ==========================================================================
@node fmc-fdelay-status
@section fmc-fdelay-status
The program reports the current output status of the four channels,
both in human-readable and raw format. The receives no arguments
besides the usual @t{-i} or @t{-d}.
Please note that the tool reads back hardware values, which are already
fixed for calibration delays. For example, this is the output
I get after the previously-shown activation command, that was for
13729 + 2 microseconds:
@smallexample
spusa.root# ./tools/fmc-fdelay-status
Channel 1, mode already-triggered, repeat 1
start time 13729:000,001,961,814 ps
end time 13729:000,002,261,814 ps
loop time 0:100,000,000,000 ps
Channel 1, mode already-triggered, repeat 1
start raw utc 13729, coarse 245, frac 929
end raw utc 13729, coarse 282, frac 2977
loop raw utc 0, coarse 12500000, frac 0
[...]
@end smallexample
The difference in value depends on the @t{delay-offset} value for
the channel, according to calibration.
This chapter describes the command line tools that come with the driver and reside in the @code{tools/} subdirectory. They are provided as diagnostic utilities and to demonstrate how to use the library.
@c ##########################################################################
@node Troubleshooting
......
LINUX ?= /lib/modules/$(shell uname -r)/build
ZIO ?= $(M)/../zio
FMC_BUS ?= $(M)/../fmc-bus
......
......@@ -154,10 +154,18 @@ static int fd_zio_info_output(struct device *dev, struct zio_attribute *zattr,
*usr_val = fd->ch_user_offset[ch];
return 0;
}
/* Reading the mode tells wether it triggered or not */
/* Reading the mode tells the current mode and whether it triggered or not */
if (zattr->id == FD_ATTR_OUT_MODE) {
int t = fd_ch_readl(fd, ch, FD_REG_DCR) & FD_DCR_PG_TRIG;
*usr_val = t ? 0x80 : 0; /* low bits will return mode */
uint32_t dcr = fd_ch_readl(fd, ch, FD_REG_DCR);
if(! (dcr & FD_DCR_ENABLE))
*usr_val = FD_OUT_MODE_DISABLED;
else if(dcr & FD_DCR_MODE)
*usr_val = FD_OUT_MODE_PULSE;
else
*usr_val = FD_OUT_MODE_DELAY;
if(dcr & FD_DCR_PG_TRIG)
*usr_val |= 0x80;
return 0;
}
......@@ -219,8 +227,11 @@ static int fd_zio_info_output(struct device *dev, struct zio_attribute *zattr,
static int fd_wr_mode(struct fd_dev *fd, int on)
{
unsigned long flags;
uint32_t tcr;
spin_lock_irqsave(&fd->lock, flags);
tcr = fd_readl(fd, FD_REG_TCR);
if (on) {
fd_writel(fd, FD_TCR_WR_ENABLE, FD_REG_TCR);
set_bit(FD_FLAG_WR_MODE, &fd->flags);
......@@ -231,8 +242,14 @@ static int fd_wr_mode(struct fd_dev *fd, int on)
fd_spi_xfer(fd, FD_CS_DAC, 24,
fd->calib.vcxo_default_tune & 0xffff, NULL);
}
spin_unlock_irqrestore(&fd->lock, flags);
return 0;
if(! (tcr & FD_TCR_WR_PRESENT))
return -EOPNOTSUPP;
else if( ! (tcr & FD_TCR_WR_LINK))
return -ENOLINK;
else
return 0;
}
static int fd_wr_query(struct fd_dev *fd)
......@@ -241,6 +258,8 @@ static int fd_wr_query(struct fd_dev *fd)
if (!ena)
return -ENODEV;
if (! (fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_LINK))
return -ENOLINK;
if (fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_LOCKED)
return 0;
return -EAGAIN;
......@@ -390,6 +409,10 @@ static int fd_zio_conf_set(struct device *dev, struct zio_attribute *zattr,
fd = zdev->priv_d;
if (zattr->id == FD_ATTR_DEV_UTC_H) {
/* no changing of the time when WR is on */
if (test_bit(FD_FLAG_WR_MODE, &fd->flags))
return -EAGAIN;
/* writing utc-h calls an atomic set-time */
t.utc = (uint64_t)attr[FD_ATTR_DEV_UTC_H].value << 32;
t.utc |= attr[FD_ATTR_DEV_UTC_L].value;
......@@ -404,6 +427,9 @@ static int fd_zio_conf_set(struct device *dev, struct zio_attribute *zattr,
switch(usr_val) {
case FD_CMD_HOST_TIME:
/* can't change the time when WR is on */
if(test_bit(FD_FLAG_WR_MODE, &fd->flags))
return -EAGAIN;
return fd_time_set(fd, NULL, NULL);
case FD_CMD_WR_ENABLE:
return fd_wr_mode(fd, 1);
......
*.a
.depend
fdelay-list
fdelay-board-time
fdelay-term
fdelay-read
fdelay-fread
fdelay-pulse
fdelay-open-by-lun
fdelay-pulse-tom
\ No newline at end of file
......@@ -6,26 +6,13 @@ LOBJ += fdelay-time.o
LOBJ += fdelay-tdc.o
LOBJ += fdelay-output.o
CFLAGS = -Wall -ggdb -O2 -I../kernel -I../zio/include
CFLAGS = -Wall -ggdb -O2 -I../kernel -I$(ZIO)/include
LDFLAGS = -L. -lfdelay
DEMOSRC := fdelay-list.c
DEMOSRC += fdelay-board-time.c
DEMOSRC += fdelay-term.c
DEMOSRC += fdelay-read.c
DEMOSRC += fdelay-fread.c
DEMOSRC += fdelay-pulse.c
DEMOSRC += fdelay-open-by-lun.c
DEMOSRC += fdelay-pulse-tom.c
DEMOS := $(DEMOSRC:.c=)
modules all: lib demos
modules all: lib
lib: $(LIB)
demos: $(DEMOS)
%: %.c $(LIB)
$(CC) $(CFLAGS) $*.c $(LDFLAGS) -o $@
......
......@@ -122,17 +122,20 @@ void fdelay_exit(void)
}
/* Open one specific device. -1 arguments mean "not installed" */
struct fdelay_board *fdelay_open(int offset, int dev_id)
struct fdelay_board *fdelay_open(int index, int dev_id)
{
struct __fdelay_board *b = NULL;
int i;
if (offset >= fd_nboards) {
if (fdelay_is_verbose())
fprintf(stderr, "called: %s(index %i, dev_id 0x%x);\n",
__func__, index, dev_id);
if (index >= fd_nboards) {
errno = ENODEV;
return NULL;
}
if (offset >= 0) {
b = fd_boards + offset;
if (index >= 0) {
b = fd_boards + index;
if (dev_id >= 0 && dev_id != b->dev_id) {
errno = EINVAL;
return NULL;
......@@ -166,6 +169,8 @@ struct fdelay_board *fdelay_open_by_lun(int lun)
char path[sizeof(path_pattern) + 1];
int dev_id;
if (fdelay_is_verbose())
fprintf(stderr, "called: %s(lun %i);\n", __func__, lun);
ret = snprintf(path, sizeof(path), path_pattern, lun);
if (ret < 0 || ret >= sizeof(path)) {
errno = EINVAL;
......@@ -184,6 +189,9 @@ int fdelay_close(struct fdelay_board *userb)
__define_board(b, userb);
int j;
if (fdelay_is_verbose())
fprintf(stderr, "called: %s(index %i, dev_id 0x%x);\n",
__func__, b - fd_boards, b->dev_id);
for (j = 0; j < ARRAY_SIZE(b->fdc); j++) {
if (b->fdc[j] >= 0)
close(b->fdc[j]);
......
......@@ -26,7 +26,8 @@ extern "C" {
numbers (as seen on the mezzanine's front panel) to convention used
by the drive (0..3). We keep 0..3 indexing to maintain library
compatibility. */
#define FDELAY_OUTPUT(out) ((out) + 1)
#define FDELAY_OUTPUT_HW_TO_USER(out) ((out) + 1)
#define FDELAY_OUTPUT_USER_TO_HW(out) ((out) - 1)
/* Opaque data type used as token */
struct fdelay_board;
......
......@@ -97,7 +97,7 @@ int fdelay_read(struct fdelay_board *userb, struct fdelay_time *t, int n,
t->frac = attrs[FD_ATTR_TDC_FRAC];
t->seq_id = attrs[FD_ATTR_TDC_SEQ];
t->channel = attrs[FD_ATTR_TDC_CHAN];
t++;
i++;
continue;
}
......
fd-raw-input
parport-burst
fd-raw-gettime
fd-raw-settime
fd-raw-output
fd-raw-perf
fdelay-list
fdelay-term
fdelay-board-time
fdelay-open-by-lun
fdelay-read
fdelay-fread
fdelay-pulse
fdelay-pulse-tom
# older user-space tools for spec-fine-delay
M = $(shell /bin/pwd)/../kernel
HOST_EXTRACFLAGS += -I$(M) -I../lib -I../zio/include -Wno-trigraphs -Wall -ggdb
HOSTCC ?= gcc
hostprogs-y := fd-raw-input
hostprogs-y += fd-raw-gettime
hostprogs-y += fd-raw-settime
hostprogs-y += parport-burst
hostprogs-y += fd-raw-output
hostprogs-y += fd-raw-perf
# programs that used to live in lib/
hostprogs-y += fdelay-list
hostprogs-y += fdelay-term
hostprogs-y += fdelay-board-time
hostprogs-y += fdelay-open-by-lun
hostprogs-y += fdelay-read
hostprogs-y += fdelay-fread
hostprogs-y += fdelay-pulse
hostprogs-y += fdelay-pulse-tom
# we are not in the kernel, so we need to piggy-back on "make modules"
all modules: $(hostprogs-y)
clean:
rm -f $(hostprogs-y) *.o *~
# make nothing for modules_install, but avoid errors
modules_install install:
# we need this as we are out of the kernel
%: %.c
$(HOSTCC) $(HOST_EXTRACFLAGS) -O2 -Wall $^ -L../lib -lfdelay -o $@
#!/bin/bash
repo_name=$1
repo_path=$2
if [ "$repo_path" != "" ]; then
echo "Using user-supplied submodule path for $repo_name [$repo_path]" 1>&2
path=$repo_path
elif [ -d "../$repo_name" ]; then
echo "Using Git repo in parent directory for $repo_name [../$repo_name]" 1>&2
path="../$repo_name"
else
echo "Using local submodule checkout for $repo_name" 1>&2
git submodule update --init $repo_name 1>&2
path=$repo_name
fi
echo `readlink -f $path`
\ No newline at end of file
GW_SPEC = spec-fine-delay-v2.0rc1-20140319.bin
GW_SVEC = svec-fine-delay-v2.0rc1-20140319.bin
GW_URL_SPEC = http://www.ohwr.org/attachments/download/2746/$(GW_SPEC)
GW_URL_SVEC = http://www.ohwr.org/attachments/download/2747/$(GW_SVEC)
FIRMWARE_PATH ?= /lib/firmware/fmc
gateware_install: bin/$(GW_SPEC) bin/$(GW_SVEC)
install -D bin/$(GW_SPEC) $(FIRMWARE_PATH)/$(GW_SPEC)
install -D bin/$(GW_SVEC) $(FIRMWARE_PATH)/$(GW_SVEC)
ln -sf $(GW_SPEC) $(FIRMWARE_PATH)/spec-fine-delay.bin
ln -sf $(GW_SVEC) $(FIRMWARE_PATH)/svec-fine-delay.bin
bin/$(GW_SPEC):
wget $(GW_URL_SPEC) -P bin
bin/$(GW_SVEC):
wget $(GW_URL_SVEC) -P bin
fd-raw-input
parport-burst
fd-raw-gettime
fd-raw-settime
fd-raw-output
fd-raw-perf
fmc-fdelay-list
fmc-fdelay-term
fmc-fdelay-board-time
fmc-fdelay-input
fmc-fdelay-pulse
fmc-fdelay-status
......@@ -2,16 +2,16 @@
M = $(shell /bin/pwd)/../kernel
HOST_EXTRACFLAGS += -I$(M) -I../zio/include -Wno-trigraphs -Wall -ggdb
HOST_EXTRACFLAGS += -I$(M) -I../lib -I$(ZIO)/include -Wno-trigraphs -Wall -ggdb
HOSTCC ?= gcc
hostprogs-y := fd-raw-input
hostprogs-y += fd-raw-gettime
hostprogs-y += fd-raw-settime
hostprogs-y += parport-burst
hostprogs-y += fd-raw-output
hostprogs-y += fd-raw-perf
hostprogs-y := fmc-fdelay-list
hostprogs-y += fmc-fdelay-term
hostprogs-y += fmc-fdelay-board-time
hostprogs-y += fmc-fdelay-input
hostprogs-y += fmc-fdelay-pulse
hostprogs-y += fmc-fdelay-status
# we are not in the kernel, so we need to piggy-back on "make modules"
all modules: $(hostprogs-y)
......@@ -19,9 +19,14 @@ all modules: $(hostprogs-y)
clean:
rm -f $(hostprogs-y) *.o *~
$(hostprogs-y): tools-util.o tools-common.h $(wildcard ../lib/*.[ch])
# make nothing for modules_install, but avoid errors
modules_install install:
# we need this as we are out of the kernel
%: %.c
$(HOSTCC) $(HOST_EXTRACFLAGS) -O2 -Wall $^ -o $@
%: %.c $(wildcard *.h)
$(HOSTCC) $(HOST_EXTRACFLAGS) -O2 -Wall $*.c tools-util.o \
-L../lib -lfdelay -o $@
%.o: %.c $(wildcard *.h)
$(HOSTCC) $(HOST_EXTRACFLAGS) -O2 -Wall -c $*.c -o $@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "fdelay-lib.h"
#include "tools-common.h"
void help(char *name)
{
fprintf(stderr, "fmc-fdelay-board-time: a tool for manipulating the FMC Fine Delay time base.\n");
fprintf(stderr, "Use: \"%s [-i <index>] [-d <dev>] <command>\"\n",
name);
fprintf(stderr, " where the <command> can be:\n"
" get - shows current time and White Rabbit status.\n"
" local - sets the time source to the card's local oscillator.\n"
" wr - sets the time source to White Rabbit.\n"
" host - sets the time source to local oscillator and coarsely\n"
" synchronizes the card to the system clock.\n"
" seconds:[nanoseconds]: - sets local time to the given value.\n");
exit(1);
}
int main(int argc, char **argv)
{
struct fdelay_board *b;
struct fdelay_time t;
int nboards, i, get = 0, host = 0, wr_on = 0, wr_off = 0;
int index = -1, dev = -1;
char *s;
/* Standard part of the file (repeated code) */
if (tools_need_help(argc, argv))
help(argv[0]);
nboards = fdelay_init();
if (nboards < 0) {
fprintf(stderr, "%s: fdelay_init(): %s\n", argv[0],
strerror(errno));
exit(1);
}
if (nboards == 0) {
fprintf(stderr, "%s: no boards found\n", argv[0]);
exit(1);
}
if (nboards == 1)
index = 0; /* so it works with no arguments */
tools_getopt_d_i(argc, argv, &dev, &index);
if (index < 0 && dev < 0) {
fprintf(stderr, "%s: several boards, please pass -i or -d\n",
argv[0]);
exit(1);
}
/* Parse the mandatory extra argument */
if (optind != argc - 1)
help(argv[0]);
s = argv[optind];
/* Crappy parser */
if (!strcmp(s, "get"))
get = 1;
else if (!strcmp(s, "host"))
host = 1;
else if (!strcmp(s, "wr"))
wr_on = 1;
else if (!strcmp(s, "local"))
wr_off = 1;
else {
double nano;
long long sec;
memset(&t, 0, sizeof(t));
i = sscanf(s, "%lli%lf\n", &sec, &nano);
if (i < 1) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], s);
exit(1);
}
t.utc = sec;
t.coarse = nano * 1000 * 1000 * 1000 / 8;
}
b = fdelay_open(index, dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
exit(1);
}
if (get) {
if (fdelay_get_time(b, &t) < 0) {
fprintf(stderr, "%s: fdelay_get_time(): %s\n", argv[0],
strerror(errno));
exit(1);
}
int err = fdelay_check_wr_mode(b);
printf("WR Status: ");
switch(err)
{
case ENODEV: printf("disabled.\n"); break;
case ENOLINK: printf("link down.\n"); break;
case EAGAIN: printf("synchronization in progress.\n"); break;
case 0: printf("synchronized.\n"); break;
default: printf("error: %s\n", strerror(errno)); break;
}
printf("Time: %lli.%09li\n", (long long)t.utc, (long)t.coarse * 8);
fdelay_close(b);
fdelay_exit();
return 0;
}
if (host) {
if (fdelay_set_host_time(b) < 0) {
fprintf(stderr, "%s: fdelay_set_host_time(): %s\n",
argv[0], strerror(errno));
exit(1);
}
fdelay_close(b);
fdelay_exit();
return 0;
}
if (wr_on) {
setbuf(stdout, NULL);
printf("Locking the card to WR: ");
int err = fdelay_wr_mode(b, 1);
if(err == ENOTSUP)
{
fprintf(stderr, "%s: no support for White Rabbit (check the gateware).\n",
argv[0]);
exit(1);
} else if (err) {
fprintf(stderr, "%s: fdelay_wr_mode(): %s\n",
argv[0], strerror(errno));
exit(1);
}
while ((err = fdelay_check_wr_mode(b)) != 0) {
if( err == ENOLINK )
{
fprintf(stderr, "%s: no White Rabbit link (check the cable and the switch).\n",
argv[0]);
exit(1);
}
printf(".");
sleep(1);
}
printf(" locked!\n");
fdelay_close(b);
fdelay_exit();
return 0;
}
if (wr_off) {
if (fdelay_wr_mode(b, 0) < 0) {
fprintf(stderr, "%s: fdelay_wr_mode(): %s\n",
argv[0], strerror(errno));
exit(1);
}
fdelay_close(b);
fdelay_exit();
return 0;
}
if (fdelay_set_time(b, &t) < 0) {
fprintf(stderr, "%s: fdelay_set_time(): %s\n",
argv[0], strerror(errno));
exit(1);
}
fdelay_close(b);
fdelay_exit();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fdelay-lib.h"
#include "tools-common.h"
void help(char *name)
{
fprintf(stderr, "%s: Use \"%s [-i <index>] [-d <dev>] [<opts>]\n",
name, name);
fprintf(stderr, " options:\n"
" -c <count> default is 0 and means forever\n"
" -n nonblocking: only empty buffer\n"
" -r raw mode: show hex timestamps\n"
" -f floating point (default): sec.nsec\n");
exit(1);
}
void dump_input(struct fdelay_time *t, int np, int umode)
{
int i;
for (i = 0; i < np; i++, t++) {
printf("seq %5i: ", t->seq_id);
tools_report_time("", t, umode);
}
}
int main(int argc, char **argv)
{
struct fdelay_board *b;
int nboards;
int opt, index = -1, dev = -1;
int nonblock = 0, count = 0;
int umode = TOOLS_UMODE_USER;
/* Standard part of the file (repeated code) */
if (tools_need_help(argc, argv))
help(argv[0]);
nboards = fdelay_init();
if (nboards < 0) {
fprintf(stderr, "%s: fdelay_init(): %s\n", argv[0],
strerror(errno));
exit(1);
}
if (nboards == 0) {
fprintf(stderr, "%s: no boards found\n", argv[0]);
exit(1);
}
if (nboards == 1)
index = 0; /* so it works with no arguments */
/* Parse our specific arguments, starting back from argv[1] */
while ((opt = getopt(argc, argv, "d:i:hc:nrf")) != -1) {
switch (opt) {
char *rest;
case 'i':
index = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'd':
dev = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'h':
help(argv[0]);
case 'c':
count = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'n':
nonblock = O_NONBLOCK;
break;
case 'r':
umode = TOOLS_UMODE_RAW;
break;
case 'f':
umode = TOOLS_UMODE_FLOAT;
break;
}
}
if (optind != argc)
help(argv[0]); /* too many arguments */
if (index < 0 && dev < 0) {
fprintf(stderr, "%s: several boards, please pass -i or -d\n",
argv[0]);
exit(1);
}
b = fdelay_open(index, dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
exit(1);
}
/* now read pulses, "np" at a time */
while (1) {
struct fdelay_time pdata[16];
int ret, np = 16;
if (count && count < np)
np = count;
ret = fdelay_read(b, pdata, np, nonblock);
if (ret < 0) {
fprintf(stderr, "%s: fdelay_read: %s\n", argv[0],
strerror(errno));
break;
}
if (!ret)
continue;
dump_input(pdata, ret, umode);
if (nonblock) /* non blocking: nothing more to do */
break;
if (!count) /* no count: forever */
continue;
count -= ret;
if (!count) /* asked that many, we are done */
break;
}
fdelay_close(b);
fdelay_exit();
return 0;
}
/* Silly thing that lists installed fine-delay boards */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define FDELAY_INTERNAL /* hack... */
#include "fdelay-lib.h"
#include "tools-common.h"
void help(char *name)
{
fprintf(stderr, "%s: Lists boards, takes no arguments\n", name);
exit(1);
}
int main(int argc, char **argv)
{
int i, j;
struct __fdelay_board *b;
struct fdelay_board *ub;
if (tools_need_help(argc, argv))
help(argv[0]);
if (argc > 1) {
fprintf(stderr, "%s: too many arguments (none expected)\n",
argv[0]);
exit(1);
}
i = fdelay_init();
if (i < 0) {
fprintf(stderr, "%s: fdelay_init(): %s\n", argv[0],
strerror(errno));
exit(1);
}
printf("%s: found %i board%s\n", argv[0], i, i ? "" : "s");
for (j = 0; j < i; j++) {
ub = fdelay_open(j, -1);
b = (typeof(b))ub;
printf(" dev_id %04x, %s, %s\n", b->dev_id, b->devbase,
b->sysbase);
}
fdelay_exit();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fdelay-lib.h"
#include "tools-common.h"
void help(char *name)
{
fprintf(stderr, "%s: Use \"%s [-i <index>] [-d <dev>] [<opts>]\n",
name, name);
fprintf(stderr, " options:\n"
" -o <output> ouput channel: 1..4 (default 1)\n"
" -c <count> default is 0 and means forever\n"
" -m <mode> \"pulse\" (default), \"delay\", \"disable\"\n"
" -r <reltime> relative time\n"
" -D <date> absolute time, <secs>:<nano>\n"
" -T <period> period, e.g. \"50m-20n\" -- use m,u,n,p and add/sub\n"
" -w <width> like period; defaults to 50%% period\n"
" -t wait for trigger before exiting\n"
" -p pulse per seconds (sets -D -T -w)\n"
" -1 10MHz (sets -D -T -w)\n"
" -v verbose (report action)\n");
exit(1);
}
struct fdelay_time t_width; /* save width here, add to start before acting */
/* This comes from oldtools/fdelay-pulse-tom.c, unchanged */
static void parse_time(char *s, struct fdelay_time *t)
{
int64_t time_ps = 0;
int64_t extra_seconds = 0;
int64_t sign = 1;
int64_t term = 0;
int64_t scale = 1;
const int64_t one_second = 1000000000000LL;
char c, *buf = s;
while ((c = *buf++) != 0) {
switch (c) {
case '+':
if (scale == one_second)
extra_seconds += sign * term;
else
time_ps += sign * term * scale;
term = 0;
sign = 1;
break;
case '-':
if (scale == one_second)
extra_seconds += sign * term;
else
time_ps += sign * term * scale;
term = 0;
sign = -1;
break;
case 's':
scale = one_second;
break;
case 'm':
scale = 1000000000LL;
break;
case 'u':
scale = 1000000LL;
break;
case 'n':
scale = 1000LL;
break;
case 'p':
scale = 1LL;
break;
default:
if (isdigit(c)) {
term *= 10LL;
term += (int64_t) (c - '0');
break;
} else {
fprintf(stderr,
"Error while parsing time string '%s'\n",
s);
exit(-1);
}
}
}
if (scale == one_second)
extra_seconds += sign * term;
else
time_ps += sign * term * scale;
while (time_ps < 0) {
time_ps += one_second;
extra_seconds--;
}
fdelay_pico_to_time((uint64_t *) & time_ps, t);
t->utc += extra_seconds;
if (0)
printf("dbg: raw %lld, %lld, converted: %lld s %d ns %d ps\n",
extra_seconds,time_ps, t->utc, t->coarse * 8,
t->frac * 8000 / 4096);
}
/* This comes from oldtools/fdelay-pulse-tom.c, unchanged */
static struct fdelay_time ts_add(struct fdelay_time a, struct fdelay_time b)
{
a.frac += b.frac;
if (a.frac >= 4096) {
a.frac -= 4096;
a.coarse++;
}
a.coarse += b.coarse;
if (a.coarse >= 125000000) {
a.coarse -= 125000000;
a.utc++;
}
a.utc += b.utc;
return a;
}
/*
* Some argument parsing is non-trivial, including setting
* the default. These helpers just return void and exit on error
*/
#define COARSE_PER_SEC (125 * 1000 * 1000)
void parse_default(struct fdelay_pulse *p)
{
memset(p, 0, sizeof(*p));
memset(&t_width, 0, sizeof(&t_width));
p->mode = FD_OUT_MODE_PULSE;
p->rep = -1; /* 1 pulse */
/* Default settings are for 10Hz, 1us width */
p->loop.coarse = COARSE_PER_SEC / 10;
t_width.coarse = 125;
}
void parse_pps(struct fdelay_pulse *p)
{
parse_default(p);
t_width.coarse = COARSE_PER_SEC / 100; /* 10ms width */
p->loop.coarse = 0;
p->loop.utc = 1;
}
void parse_10mhz(struct fdelay_pulse *p)
{
parse_default(p);
t_width.coarse = 6 /* 48ns */;
p->loop.coarse = 12 /* 96ns */;
p->loop.frac = 2048 /* 4ns */;
}
void parse_reltime(struct fdelay_pulse *p, char *s)
{
memset(&p->start, 0, sizeof(p->start));
parse_time(s, &p->start);
}
void parse_abstime(struct fdelay_pulse *p, char *s)
{
memset(&p->start, 0, sizeof(p->start));
parse_time(s, &p->start);
}
void parse_period(struct fdelay_pulse *p, char *s)
{
memset(&p->loop, 0, sizeof(p->loop));
parse_time(s, &p->loop);
}
void parse_width(struct fdelay_pulse *p, char *s)
{
memset(&t_width, 0, sizeof(&t_width));
parse_time(s, &t_width);
}
int main(int argc, char **argv)
{
struct fdelay_board *b;
int nboards;
int i, opt, index = -1, dev = -1;
/* our parameters */
int count = 0, channel = 1;
int trigger_wait = 0, verbose = 0;
struct fdelay_pulse p;
/* Standard part of the file (repeated code) */
if (tools_need_help(argc, argv))
help(argv[0]);
nboards = fdelay_init();
if (nboards < 0) {
fprintf(stderr, "%s: fdelay_init(): %s\n", argv[0],
strerror(errno));
exit(1);
}
if (nboards == 0) {
fprintf(stderr, "%s: no boards found\n", argv[0]);
exit(1);
}
if (nboards == 1)
index = 0; /* so it works with no arguments */
parse_default(&p);
/* Parse our specific arguments */
while ((opt = getopt(argc, argv, "d:i:ho:c:m:r:D:T:w:tp1v")) != -1) {
switch (opt) {
char *rest;
case 'i':
index = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'd':
dev = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'h':
help(argv[0]);
case 'o':
channel = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
if (channel < 1 || channel > 4) {
fprintf(stderr, "%s: channel \"%s\" out of range\n",
argv[0], optarg);
exit(1);
}
break;
case 'c':
count = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
p.rep = count ? count : -1 /* infinite */;
break;
case 'm':
if (!strcmp(optarg, "disable"))
p.mode = FD_OUT_MODE_DISABLED;
else if (!strcmp(optarg, "pulse"))
p.mode = FD_OUT_MODE_PULSE;
else if (!strcmp(optarg, "delay"))
p.mode = FD_OUT_MODE_DELAY;
else {
fprintf(stderr, "%s: invalid mode \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'r':
parse_reltime(&p, optarg);
break;
case 'D':
parse_abstime(&p, optarg);
break;
#if 0 /* no frequency */
case 'f':
parse_freq(&p, optarg);
break;
#endif
case 'T':
parse_period(&p, optarg);
break;
case 'w':
parse_width(&p, optarg);
break;
case 't':
trigger_wait = 1;
break;
case 'p':
parse_pps(&p);
break;
case '1':
parse_10mhz(&p);
break;
case 'v':
verbose = 1;
break;
}
}
if (optind != argc)
help(argv[0]); /* too many arguments */
if (index < 0 && dev < 0) {
fprintf(stderr, "%s: several boards, please pass -i or -d\n",
argv[0]);
exit(1);
}
b = fdelay_open(index, dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
exit(1);
}
/* Final fixes: if reltime in pulse mode, add current time */
if (p.mode == FD_OUT_MODE_PULSE && p.start.utc == 0) {
struct fdelay_time current_board_time;
fdelay_get_time(b, &current_board_time);
/* Start next second, or next again if too near to overlap */
p.start.utc = current_board_time.utc + 1;
if (current_board_time.coarse > COARSE_PER_SEC * 9 / 10)
p.start.utc++;
}
/* End is start + width, in every situation */
p.end = ts_add(p.start, t_width);
/* In delay mode, default is one pulse only; recover if wrong */
if (p.mode == FD_OUT_MODE_DELAY && p.rep <= 0)
p.rep = 1;
/* Done. Report verbosely and activate the information we parsed */
channel = FDELAY_OUTPUT_USER_TO_HW(channel);
if (verbose) {
report_output_config(channel, &p, TOOLS_UMODE_USER);
// tools_report_action(channel, &p, TOOLS_UMODE_RAW);
}
if (fdelay_config_pulse(b, channel, &p) < 0) {
fprintf(stderr, "%s: fdelay_config_pulse(): %s\n",
argv[0], strerror(errno));
exit(1);
}
while (trigger_wait) {
usleep(10 * 1000);
i = fdelay_has_triggered(b, channel);
if (i < 0) {
fprintf(stderr, "%s: waiting for trigger: %s\n",
argv[0], strerror(errno));
exit(1);
}
trigger_wait = !i;
}
fdelay_close(b);
fdelay_exit();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "fdelay-lib.h"
#include "tools-common.h"
void help(char *name)
{
fprintf(stderr, "fmc-fdelay-status: reports channel programming\n");
fprintf(stderr, "Use: \"%s [-i <index>] [-d <dev>] [-r]\"\n", name);
fprintf(stderr, " -r: display raw hardware configuration");
exit(1);
}
int main(int argc, char **argv)
{
struct fdelay_board *b;
struct fdelay_pulse p;
int nboards, ch, index = -1, dev = -1, raw = 0, opt;
/* Standard part of the file (repeated code) */
if (tools_need_help(argc, argv))
help(argv[0]);
nboards = fdelay_init();
if (nboards < 0) {
fprintf(stderr, "%s: fdelay_init(): %s\n", argv[0],
strerror(errno));
exit(1);
}
if (nboards == 0) {
fprintf(stderr, "%s: no boards found\n", argv[0]);
exit(1);
}
if (nboards == 1)
index = 0; /* so it works with no arguments */
while ((opt = getopt(argc, argv, "i:d:rh")) != -1) {
char *rest;
switch (opt) {
case 'i':
index = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'd':
dev = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'r':
raw = 1;
break;
case 'h':
help(argv[0]);
exit(0);
}
}
if (index < 0 && dev < 0) {
fprintf(stderr, "%s: several boards, please pass -i or -d\n",
argv[0]);
exit(1);
}
b = fdelay_open(index, dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
exit(1);
}
for (ch = 1; ch <= 4; ch++) {
if (fdelay_get_config_pulse(b, FDELAY_OUTPUT_USER_TO_HW(ch),
&p) < 0) {
fprintf(stderr, "%s: get_config(channel %i): %s\n",
argv[0], ch, strerror(errno));
}
/* pass hw number again, as the function is low-level */
report_output_config(FDELAY_OUTPUT_USER_TO_HW(ch),
&p, raw ? TOOLS_UMODE_RAW : TOOLS_UMODE_USER);
}
fdelay_close(b);
fdelay_exit();
return 0;
}
/* Simple demo that acts on the termination of the first board */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include "fdelay-lib.h"
#include "tools-common.h"
void help(char *name)
{
fprintf(stderr, "%s: Use \"%s [-i <index>] [-d <dev>] [on|off]\n",
name, name);
exit(1);
}
int main(int argc, char **argv)
{
struct fdelay_board *b;
int nboards, hwval, newval;
int index = -1, dev = -1;
/* Standard part of the file (repeated code) */
if (tools_need_help(argc, argv))
help(argv[0]);
nboards = fdelay_init();
if (nboards < 0) {
fprintf(stderr, "%s: fdelay_init(): %s\n", argv[0],
strerror(errno));
exit(1);
}
if (nboards == 0) {
fprintf(stderr, "%s: no boards found\n", argv[0]);
exit(1);
}
if (nboards == 1)
index = 0; /* so it works with no arguments */
tools_getopt_d_i(argc, argv, &dev, &index);
if (index < 0 && dev < 0) {
fprintf(stderr, "%s: several boards, please pass -i or -d\n",
argv[0]);
exit(1);
}
/* Parse the extra argument, if any */
newval = -1;
if (optind == argc - 1) {
char *s = argv[optind];
if (!strcmp(s, "0") || !strcmp(s, "off"))
newval = 0;
else if (!strcmp(s, "1") || !strcmp(s, "on"))
newval = 1;
else
help(argv[0]);
}
/* Finally work */
b = fdelay_open(index, dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
exit(1);
}
hwval = fdelay_get_config_tdc(b);
int err = 0;
switch(newval) {
case 1:
hwval |= FD_TDCF_TERM_50;
err = fdelay_set_config_tdc(b, hwval);
break;
case 0:
hwval &= ~FD_TDCF_TERM_50;
err = fdelay_set_config_tdc(b, hwval);
break;
}
if (err)
{
fprintf(stderr, "%s: error setting termination: %s", argv[0], strerror(errno));
exit(1);
}
printf("%s: termination is %s\n", argv[0],
hwval & FD_TDCF_TERM_50 ? "on" : "off");
fdelay_close(b);
fdelay_exit();
return 0;
}
#!/bin/bash
modprobe fmc
modprobe spec
insmod spec-fine-delay.ko wrc=1
/*
* Simple code that is repeated over several tools
*/
extern void tools_getopt_d_i(int argc, char **argv,
int *dev, int *index);
extern int tools_need_help(int argc, char **argv);
#define TOOLS_UMODE_USER 0
#define TOOLS_UMODE_RAW 1
#define TOOLS_UMODE_FLOAT 2
extern void tools_report_time(char *name, struct fdelay_time *t, int umode);
extern void report_output_config(int channel, struct fdelay_pulse *p, int umode);
extern void help(char *name); /* This is mandatory in all tools */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "fdelay-lib.h"
#include "tools-common.h"
extern void help(char *name); /* This is mandatory in all tools */
void tools_getopt_d_i(int argc, char **argv,
int *dev, int *index)
{
char *rest;
int opt;
while ((opt = getopt(argc, argv, "d:i:h")) != -1) {
switch (opt) {
case 'i':
*index = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'd':
*dev = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'h':
help(argv[0]);
}
}
}
int tools_need_help(int argc, char **argv)
{
if (argc != 2)
return 0;
if (!strcmp(argv[1], "--help"))
return 1;
return 0;
}
void tools_report_time(char *name, struct fdelay_time *t, int umode)
{
unsigned long long picoseconds =
t->coarse * 8000ULL +
t->frac * 8000ULL / 4096ULL;
printf("%s ", name);
switch(umode) {
case TOOLS_UMODE_USER:
printf ("%10llu:%03llu,%03llu,%03llu,%03llu ps\n",
(long long)(t->utc),
(picoseconds / (1000LL * 1000 * 1000)),
(picoseconds / (1000LL * 1000) % 1000),
(picoseconds / (1000LL) % 1000),
(picoseconds % 1000LL));
break;
case TOOLS_UMODE_FLOAT:
printf ("float %10llu.%012llu\n", (long long)(t->utc),
picoseconds);
break;
case TOOLS_UMODE_RAW:
printf("raw utc %10lli, coarse %9li, frac %9li\n",
(long long)t->utc, (long)t->coarse, (long)t->frac);
break;
}
}
static struct fdelay_time fd_ts_sub(struct fdelay_time a, struct fdelay_time b)
{
struct fdelay_time rv;
int f, c = 0;
int64_t u = 0;
f = a.frac - b.frac;
if(f < 0)
{
f += 4096;
c--;
}
c += a.coarse - b.coarse;
if(c < 0)
{
c += 125 * 1000 * 1000;
u--;
}
u += a.utc - b.utc;
rv.utc = u;
rv.coarse = c;
rv.frac = f;
rv.seq_id = 0;
rv.channel = 0;
return rv;
}
static void report_output_config_human(int channel, struct fdelay_pulse *p)
{
struct fdelay_time width;
printf("Channel %i: ", FDELAY_OUTPUT_HW_TO_USER(channel));
int m = p->mode & 0x7f;
switch(m)
{
case FD_OUT_MODE_DISABLED:
printf("disabled\n");
return;
case FD_OUT_MODE_PULSE:
printf("pulse generator mode");
break;
case FD_OUT_MODE_DELAY:
printf("delay mode");
break;
default:
printf("unknown mode\n");
return;
}
if(p->mode & 0x80)
printf(" (triggered) ");
tools_report_time(m == FD_OUT_MODE_DELAY ? "\n delay: " : "\n start at: ",
&p->start, TOOLS_UMODE_USER);
width = fd_ts_sub(p->end, p->start);
tools_report_time(" pulse width: ", &width, TOOLS_UMODE_USER);
if(p->rep != 1)
{
printf(" repeat: ");
if(p->rep == -1)
printf("infinite\n");
else
printf("%d times\n", p->rep);
tools_report_time(" period: ", &p->loop, TOOLS_UMODE_USER);
}
}
void report_output_config_raw(int channel, struct fdelay_pulse *p, int umode)
{
char mode[80];
int m = p->mode & 0x7f;
if (m == FD_OUT_MODE_DISABLED) strcpy(mode, "disabled");
else if (m == FD_OUT_MODE_PULSE) strcpy(mode, "pulse");
else if (m == FD_OUT_MODE_DELAY) strcpy(mode, "delay");
else sprintf(mode, "%i (0x%04x)", p->mode, p->mode);
if (p->mode & 0x80)
strcat(mode, " (triggered)");
printf("Channel %i, mode %s, repeat %i %s\n",
FDELAY_OUTPUT_HW_TO_USER(channel), mode,
p->rep, p->rep == -1 ? "(infinite)" : "");
tools_report_time("start", &p->start, umode);
tools_report_time("end ", &p->end, umode);
tools_report_time("loop ", &p->loop, umode);
}
void report_output_config(int channel, struct fdelay_pulse *p, int umode)
{
switch(umode)
{
case TOOLS_UMODE_USER:
report_output_config_human(channel, p);
break;
case TOOLS_UMODE_RAW:
case TOOLS_UMODE_FLOAT:
report_output_config_raw(channel, p, umode);
default:
break;
}
}
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