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 .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 @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 all modules: prereq
...@@ -15,15 +18,8 @@ CONFIG_WR_NIC=n ...@@ -15,15 +18,8 @@ CONFIG_WR_NIC=n
export CONFIG_WR_NIC export CONFIG_WR_NIC
#### The following targets are used to manage prerequisite repositories #### 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: # 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) SUBMOD = $(FMC_BUS) $(ZIO) $(SPEC_SW)
prereq: prereq:
...@@ -36,3 +32,5 @@ prereq_install_warn: ...@@ -36,3 +32,5 @@ prereq_install_warn:
prereq_install: prereq_install:
for d in $(SUBMOD); do $(MAKE) -C $$d modules_install || exit 1; done for d in $(SUBMOD); do $(MAKE) -C $$d modules_install || exit 1; done
touch .prereq_installed touch .prereq_installed
include scripts/gateware.mk
This diff is collapsed.
LINUX ?= /lib/modules/$(shell uname -r)/build LINUX ?= /lib/modules/$(shell uname -r)/build
ZIO ?= $(M)/../zio ZIO ?= $(M)/../zio
FMC_BUS ?= $(M)/../fmc-bus FMC_BUS ?= $(M)/../fmc-bus
......
...@@ -154,10 +154,18 @@ static int fd_zio_info_output(struct device *dev, struct zio_attribute *zattr, ...@@ -154,10 +154,18 @@ static int fd_zio_info_output(struct device *dev, struct zio_attribute *zattr,
*usr_val = fd->ch_user_offset[ch]; *usr_val = fd->ch_user_offset[ch];
return 0; 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) { if (zattr->id == FD_ATTR_OUT_MODE) {
int t = fd_ch_readl(fd, ch, FD_REG_DCR) & FD_DCR_PG_TRIG; uint32_t dcr = fd_ch_readl(fd, ch, FD_REG_DCR);
*usr_val = t ? 0x80 : 0; /* low bits will return mode */ 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; return 0;
} }
...@@ -219,8 +227,11 @@ static int fd_zio_info_output(struct device *dev, struct zio_attribute *zattr, ...@@ -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) static int fd_wr_mode(struct fd_dev *fd, int on)
{ {
unsigned long flags; unsigned long flags;
uint32_t tcr;
spin_lock_irqsave(&fd->lock, flags); spin_lock_irqsave(&fd->lock, flags);
tcr = fd_readl(fd, FD_REG_TCR);
if (on) { if (on) {
fd_writel(fd, FD_TCR_WR_ENABLE, FD_REG_TCR); fd_writel(fd, FD_TCR_WR_ENABLE, FD_REG_TCR);
set_bit(FD_FLAG_WR_MODE, &fd->flags); set_bit(FD_FLAG_WR_MODE, &fd->flags);
...@@ -231,8 +242,14 @@ static int fd_wr_mode(struct fd_dev *fd, int on) ...@@ -231,8 +242,14 @@ static int fd_wr_mode(struct fd_dev *fd, int on)
fd_spi_xfer(fd, FD_CS_DAC, 24, fd_spi_xfer(fd, FD_CS_DAC, 24,
fd->calib.vcxo_default_tune & 0xffff, NULL); fd->calib.vcxo_default_tune & 0xffff, NULL);
} }
spin_unlock_irqrestore(&fd->lock, flags); 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) static int fd_wr_query(struct fd_dev *fd)
...@@ -241,6 +258,8 @@ static int fd_wr_query(struct fd_dev *fd) ...@@ -241,6 +258,8 @@ static int fd_wr_query(struct fd_dev *fd)
if (!ena) if (!ena)
return -ENODEV; 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) if (fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_LOCKED)
return 0; return 0;
return -EAGAIN; return -EAGAIN;
...@@ -390,6 +409,10 @@ static int fd_zio_conf_set(struct device *dev, struct zio_attribute *zattr, ...@@ -390,6 +409,10 @@ static int fd_zio_conf_set(struct device *dev, struct zio_attribute *zattr,
fd = zdev->priv_d; fd = zdev->priv_d;
if (zattr->id == FD_ATTR_DEV_UTC_H) { 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 */ /* writing utc-h calls an atomic set-time */
t.utc = (uint64_t)attr[FD_ATTR_DEV_UTC_H].value << 32; t.utc = (uint64_t)attr[FD_ATTR_DEV_UTC_H].value << 32;
t.utc |= attr[FD_ATTR_DEV_UTC_L].value; 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, ...@@ -404,6 +427,9 @@ static int fd_zio_conf_set(struct device *dev, struct zio_attribute *zattr,
switch(usr_val) { switch(usr_val) {
case FD_CMD_HOST_TIME: 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); return fd_time_set(fd, NULL, NULL);
case FD_CMD_WR_ENABLE: case FD_CMD_WR_ENABLE:
return fd_wr_mode(fd, 1); return fd_wr_mode(fd, 1);
......
*.a *.a
.depend .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 ...@@ -6,26 +6,13 @@ LOBJ += fdelay-time.o
LOBJ += fdelay-tdc.o LOBJ += fdelay-tdc.o
LOBJ += fdelay-output.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 LDFLAGS = -L. -lfdelay
DEMOSRC := fdelay-list.c modules all: lib
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
lib: $(LIB) lib: $(LIB)
demos: $(DEMOS)
%: %.c $(LIB) %: %.c $(LIB)
$(CC) $(CFLAGS) $*.c $(LDFLAGS) -o $@ $(CC) $(CFLAGS) $*.c $(LDFLAGS) -o $@
......
...@@ -122,17 +122,20 @@ void fdelay_exit(void) ...@@ -122,17 +122,20 @@ void fdelay_exit(void)
} }
/* Open one specific device. -1 arguments mean "not installed" */ /* 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; struct __fdelay_board *b = NULL;
int i; 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; errno = ENODEV;
return NULL; return NULL;
} }
if (offset >= 0) { if (index >= 0) {
b = fd_boards + offset; b = fd_boards + index;
if (dev_id >= 0 && dev_id != b->dev_id) { if (dev_id >= 0 && dev_id != b->dev_id) {
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
...@@ -166,6 +169,8 @@ struct fdelay_board *fdelay_open_by_lun(int lun) ...@@ -166,6 +169,8 @@ struct fdelay_board *fdelay_open_by_lun(int lun)
char path[sizeof(path_pattern) + 1]; char path[sizeof(path_pattern) + 1];
int dev_id; int dev_id;
if (fdelay_is_verbose())
fprintf(stderr, "called: %s(lun %i);\n", __func__, lun);
ret = snprintf(path, sizeof(path), path_pattern, lun); ret = snprintf(path, sizeof(path), path_pattern, lun);
if (ret < 0 || ret >= sizeof(path)) { if (ret < 0 || ret >= sizeof(path)) {
errno = EINVAL; errno = EINVAL;
...@@ -184,6 +189,9 @@ int fdelay_close(struct fdelay_board *userb) ...@@ -184,6 +189,9 @@ int fdelay_close(struct fdelay_board *userb)
__define_board(b, userb); __define_board(b, userb);
int j; 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++) { for (j = 0; j < ARRAY_SIZE(b->fdc); j++) {
if (b->fdc[j] >= 0) if (b->fdc[j] >= 0)
close(b->fdc[j]); close(b->fdc[j]);
......
...@@ -26,7 +26,8 @@ extern "C" { ...@@ -26,7 +26,8 @@ extern "C" {
numbers (as seen on the mezzanine's front panel) to convention used 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 by the drive (0..3). We keep 0..3 indexing to maintain library
compatibility. */ 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 */ /* Opaque data type used as token */
struct fdelay_board; struct fdelay_board;
......
...@@ -97,7 +97,7 @@ int fdelay_read(struct fdelay_board *userb, struct fdelay_time *t, int n, ...@@ -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->frac = attrs[FD_ATTR_TDC_FRAC];
t->seq_id = attrs[FD_ATTR_TDC_SEQ]; t->seq_id = attrs[FD_ATTR_TDC_SEQ];
t->channel = attrs[FD_ATTR_TDC_CHAN]; t->channel = attrs[FD_ATTR_TDC_CHAN];
t++;
i++; i++;
continue; 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 fmc-fdelay-list
parport-burst fmc-fdelay-term
fd-raw-gettime fmc-fdelay-board-time
fd-raw-settime fmc-fdelay-input
fd-raw-output fmc-fdelay-pulse
fd-raw-perf fmc-fdelay-status
...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
M = $(shell /bin/pwd)/../kernel 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 HOSTCC ?= gcc
hostprogs-y := fd-raw-input hostprogs-y := fmc-fdelay-list
hostprogs-y += fd-raw-gettime hostprogs-y += fmc-fdelay-term
hostprogs-y += fd-raw-settime hostprogs-y += fmc-fdelay-board-time
hostprogs-y += parport-burst hostprogs-y += fmc-fdelay-input
hostprogs-y += fd-raw-output hostprogs-y += fmc-fdelay-pulse
hostprogs-y += fd-raw-perf hostprogs-y += fmc-fdelay-status
# we are not in the kernel, so we need to piggy-back on "make modules" # we are not in the kernel, so we need to piggy-back on "make modules"
all modules: $(hostprogs-y) all modules: $(hostprogs-y)
...@@ -19,9 +19,14 @@ all modules: $(hostprogs-y) ...@@ -19,9 +19,14 @@ all modules: $(hostprogs-y)
clean: clean:
rm -f $(hostprogs-y) *.o *~ rm -f $(hostprogs-y) *.o *~
$(hostprogs-y): tools-util.o tools-common.h $(wildcard ../lib/*.[ch])
# make nothing for modules_install, but avoid errors # make nothing for modules_install, but avoid errors
modules_install install: modules_install install:
# we need this as we are out of the kernel # we need this as we are out of the kernel
%: %.c %: %.c $(wildcard *.h)
$(HOSTCC) $(HOST_EXTRACFLAGS) -O2 -Wall $^ -o $@ $(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