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
This diff is collapsed.
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