Commit 856497c1 authored by Federico Vaga's avatar Federico Vaga

remove lib and libtools

The driver's users are supposed to use the generic `adc-lib`
library from OHWR.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent e3fc1b13
......@@ -4,7 +4,7 @@ CURDIR:=$(shell /bin/pwd)
REPO_PARENT ?= $(CURDIR)/..
-include $(REPO_PARENT)/parent_common.mk
all: kernel tools lib libtools
all: kernel tools
FMC_BUS ?= fmc-bus
ZIO ?= zio
......@@ -24,11 +24,9 @@ export ZIO_ABS
export SVEC_SW_ABS
export VMEBUS_ABS
DIRS = $(FMC_BUS_ABS) $(ZIO_ABS) kernel tools lib libtools
DIRS = $(FMC_BUS_ABS) $(ZIO_ABS) kernel tools
kernel: $(FMC_BUS_ABS) $(ZIO_ABS)
lib: $(ZIO_ABS)
tools libtools: lib
.PHONY: all clean modules install modules_install $(DIRS)
.PHONY: gitmodules prereq_install prereq_install_warn
......
.depend
\ No newline at end of file
# This is not a kbuild Makefile. It is a plain Makefile so it can be copied
# If it exists includes Makefile.specific. In this Makefile, you should put
# specific Makefile code that you want to run before this. For example,
# build a particular environment.
-include Makefile.specific
# include parent_common.mk for buildsystem's defines
REPO_PARENT ?= ../..
-include $(REPO_PARENT)/parent_common.mk
ZIO ?= ../zio
ZIO_ABS ?= $(abspath $(ZIO) )
GIT_VERSION := $(shell git describe --dirty --long --tags)
ZIO_GIT_VERSION := $(shell cd $(ZIO_ABS); git describe --dirty --long --tags)
LIB = libfmcadc.a
LOBJ := route.o
LOBJ += init.o
LOBJ += boards.o
LOBJ += config-zio.o
LOBJ += buffer-zio.o
LOBJ += lib.o
LOBJ += fmc-adc-100m14b4cha.o
CFLAGS = -Wall -ggdb -O2 -fPIC -I../kernel -I$(ZIO_ABS)/include $(EXTRACFLAGS)
CFLAGS += -DGIT_VERSION="\"$(GIT_VERSION)\""
CFLAGS += -DZIO_GIT_VERSION="\"$(ZIO_GIT_VERSION)\""
LDFLAGS = -L. -lfmcadc
CC ?= $(CROSS_COMPILE)gcc
modules all: $(LIB)
%: %.c $(LIB)
$(CC) $(CFLAGS) $*.c $(LDFLAGS) -o $@
$(LIB): $(LOBJ)
$(AR) r $@ $^
clean:
rm -f $(LIB) .depend *.o *~
.depend: Makefile $(wildcard *.c *.h ../*.h)
$(CC) $(CFLAGS) -M $(LOBJ:.o=.c) -o $@
install modules_install:
-include .depend
/*
* All the boards in the library
*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include "fmcadc-lib.h"
#include "fmcadc-lib-int.h"
#define FMCADC_ZIO_TRG_MASK (1LL << FMCADC_CONF_TRG_SOURCE) | \
(1LL << FMCADC_CONF_TRG_SOURCE_CHAN) | \
(1LL << FMCADC_CONF_TRG_THRESHOLD) | \
(1LL << FMCADC_CONF_TRG_POLARITY) | \
(1LL << FMCADC_CONF_TRG_DELAY)
#define FMCADC_ZIO_ACQ_MASK (1LL << FMCADC_CONF_ACQ_N_SHOTS) | \
(1LL << FMCADC_CONF_ACQ_POST_SAMP) | \
(1LL << FMCADC_CONF_ACQ_PRE_SAMP) | \
(1LL << FMCADC_CONF_ACQ_DECIMATION) | \
(1LL << FMCADC_CONF_ACQ_FREQ_HZ) | \
(1LL << FMCADC_CONF_ACQ_N_BITS)
#define FMCADC_ZIO_CHN_MASK (1LL << FMCADC_CONF_CHN_RANGE) | \
(1LL << FMCADC_CONF_CHN_TERMINATION) | \
(1LL << FMCADC_CONF_CHN_OFFSET)
#define FMCADC_ZIO_BRD_MASK (1LL << FMCADC_CONF_BRD_STATE_MACHINE_STATUS) | \
(1LL << FMCADC_CONF_BRD_N_CHAN) | \
(1LL << FMCADC_CONF_UTC_TIMING_BASE_S) | \
(1LL << FMCADC_CONF_UTC_TIMING_BASE_T)
struct fmcadc_operations fa_100ms_4ch_14bit_op = {
.open = fmcadc_zio_open,
.close = fmcadc_zio_close,
.acq_start = fmcadc_zio_acq_start,
.acq_poll = fmcadc_zio_acq_poll,
.acq_stop = fmcadc_zio_acq_stop,
.apply_config = fmcadc_zio_apply_config,
.retrieve_config = fmcadc_zio_retrieve_config,
.get_param = fmcadc_zio_get_param,
.set_param = fmcadc_zio_set_param,
.request_buffer = fmcadc_zio_request_buffer,
.fill_buffer = fmcadc_zio_fill_buffer,
.tstamp_buffer = fmcadc_zio_tstamp_buffer,
.release_buffer = fmcadc_zio_release_buffer,
};
struct fmcadc_board_type fmcadc_100ms_4ch_14bit = {
.name = "fmc-adc-100m14b4cha", /* for library open() */
.devname = "adc-100m14b", /* for device named in /dev/zio */
.driver_type = "zio",
.capabilities = {
FMCADC_ZIO_TRG_MASK,
FMCADC_ZIO_ACQ_MASK,
FMCADC_ZIO_CHN_MASK,
FMCADC_ZIO_BRD_MASK,
},
.fa_op = &fa_100ms_4ch_14bit_op,
};
/*
* The following array is the main entry point into the boards
*/
static const struct fmcadc_board_type *fmcadc_board_types[] = {
&fmcadc_100ms_4ch_14bit,
/* add new boards here */
};
static const struct fmcadc_board_type *find_board(char *name)
{
int i;
for (i = 0; i < ARRAY_SIZE(fmcadc_board_types); i++)
if (!strcmp(name, fmcadc_board_types[i]->name))
return fmcadc_board_types[i];
errno = ENODEV;
return NULL;
}
/* Open should choose the buffer type (FIXME) */
struct fmcadc_dev *fmcadc_open(char *name, unsigned int dev_id,
unsigned long buffersize,
unsigned int nbuffer,
unsigned long flags)
{
const struct fmcadc_board_type *b;
b = find_board(name);
if (!b)
return NULL;
return b->fa_op->open(b, dev_id, buffersize, nbuffer, flags);
}
#define FMCADC_PATH_PATTERN "/dev/%s.%d"
/* Open by lun should lookup a database */
struct fmcadc_dev *fmcadc_open_by_lun(char *name, int lun,
unsigned long buffersize,
unsigned int nbuffer,
unsigned long flags)
{
ssize_t ret;
char dev_id_str[8];
char path[PATH_MAX];
int dev_id;
ret = snprintf(path, sizeof(path), "/dev/%s.%d",
"adc-100m14b" /* FIXME: this must be generic */,
lun);
if (ret < 0 || ret >= sizeof(path)) {
errno = EINVAL;
return NULL;
}
ret = readlink(path, dev_id_str, sizeof(dev_id_str));
if (sscanf(dev_id_str, "%4x", &dev_id) != 1) {
errno = ENODEV;
return NULL;
}
return fmcadc_open(name, dev_id, buffersize, nbuffer, flags);
}
int fmcadc_close(struct fmcadc_dev *dev)
{
struct fmcadc_gid *b = (struct fmcadc_gid *)dev;
return b->board->fa_op->close(dev);
}
/*
* ZIO-wide buffer management (device-independent)
*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <linux/zio-user.h>
#include "fmcadc-lib.h"
#include "fmcadc-lib-int.h"
/* Internal function to read the control, already allocated in the buffer */
static int fmcadc_zio_read_ctrl(struct __fmcadc_dev_zio *fa,
struct fmcadc_buffer *buf)
{
struct zio_control *ctrl;
int i;
i = read(fa->fdc, buf->metadata, sizeof(struct zio_control));
switch (i) {
case sizeof(struct zio_control):
return 0; /* ok */
case -1:
if (fa->flags & FMCADC_FLAG_VERBOSE)
fprintf(stderr, "%s: read: %s\n", __func__,
strerror(errno));
return -1;
case 0:
if (fa->flags & FMCADC_FLAG_VERBOSE)
fprintf(stderr, "%s: unexpected EOF\n", __func__);
return -1;
default:
if (fa->flags & FMCADC_FLAG_VERBOSE)
fprintf(stderr, "%s: read: %i bytes (expected %zi)\n",
__func__, i, sizeof(ctrl));
return -1;
}
}
/* Internal function to read or map the data, already allocated in the buffer */
static int fmcadc_zio_read_data(struct __fmcadc_dev_zio *fa,
struct fmcadc_buffer *buf)
{
struct zio_control *ctrl = buf->metadata;
int datalen;
int samplesize = buf->samplesize; /* Careful: includes n_chan */
int i;
/* we allocated buf->nsamples, we can have more or less */
if (buf->nsamples < ctrl->nsamples)
datalen = samplesize * buf->nsamples;
else
datalen = samplesize * ctrl->nsamples;
if (fa->flags & FMCADC_FLAG_MMAP) {
unsigned long mapoffset = ctrl->mem_offset;
unsigned long pagemask = fa->pagesize - 1;
if (buf->mapaddr) /* unmap previous block */
munmap(buf->mapaddr, buf->maplen);
buf->maplen = (mapoffset & pagemask) + datalen;
buf->mapaddr = mmap(0, buf->maplen, PROT_READ, MAP_SHARED,
fa->fdd, mapoffset & ~pagemask);
if (buf->mapaddr == MAP_FAILED)
return -1;
buf->data = buf->mapaddr + (mapoffset & pagemask);
return 0;
}
/* read */
i = read(fa->fdd, buf->data, datalen);
if (i == datalen)
return 0;
if (i > 0) {
if (fa->flags & FMCADC_FLAG_VERBOSE)
fprintf(stderr, "%s: read %i bytes (exp. %i)\n",
__func__, i, datalen);
buf->nsamples = i / fa->samplesize;
/* short read is allowed */
return 0;
}
if (i == 0) {
if (fa->flags & FMCADC_FLAG_VERBOSE)
fprintf(stderr, "%s: unexpected EOF\n", __func__);
errno = ENODATA;
return -1;
}
if (fa->flags & FMCADC_FLAG_VERBOSE)
fprintf(stderr, "%s: %s\n", __func__, strerror(errno));
return -1;
}
/* externally-called: malloc buffer and metadata, do your best with data */
struct fmcadc_buffer *fmcadc_zio_request_buffer(struct fmcadc_dev *dev,
int nsamples,
void *(*alloc)(size_t),
unsigned int flags)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
struct fmcadc_buffer *buf;
char s[16];
/* If this is the first buffer, we need to know which kind it is */
if ((fa->flags & (FMCADC_FLAG_MALLOC | FMCADC_FLAG_MMAP)) == 0) {
fmcadc_get_param(dev, "cset0/current_buffer", s, NULL);
if (!strcmp(s, "vmalloc"))
fa->flags |= FMCADC_FLAG_MMAP;
else
fa->flags |= FMCADC_FLAG_MALLOC;
}
buf = calloc(1, sizeof(*buf));
if (!buf) {
errno = ENOMEM;
return NULL;
}
buf->metadata = calloc(1, sizeof(struct zio_control));
if (!buf->metadata) {
free(buf);
errno = ENOMEM;
return NULL;
}
/* Allocate data: custom allocator, or malloc, or mmap */
if (!alloc && fa->flags & FMCADC_FLAG_MALLOC)
alloc = malloc;
if (alloc) {
buf->data = alloc(nsamples * fa->samplesize);
if (!buf->data) {
free(buf->metadata);
free(buf);
errno = ENOMEM;
return NULL;
}
} else {
/* mmap is done later */
buf->data = NULL;
}
/* Copy other information */
buf->samplesize = fa->samplesize;
buf->nsamples = nsamples;
buf->dev = (void *)&fa->gid;
buf->flags = flags;
return buf;
}
int fmcadc_zio_fill_buffer(struct fmcadc_dev *dev,
struct fmcadc_buffer *buf,
unsigned int flags,
struct timeval *to)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
struct pollfd p;
int to_ms, ret;
/* So, first sample and blocking read. Wait.. */
p.fd = fa->fdc;
p.events = POLLIN | POLLERR;
if (!to)
to_ms = -1;
else
to_ms = to->tv_sec / 1000 + (to->tv_usec + 500) / 1000;
ret = poll(&p, 1, to_ms);
switch (ret) {
case 0:
errno = EAGAIN;
/* fall through */
case -1:
return -1;
}
if (p.revents & POLLERR) {
errno = FMCADC_EDISABLED;
return -1;
}
ret = fmcadc_zio_read_ctrl(fa, buf);
if (ret < 0)
return ret;
ret = fmcadc_zio_read_data(fa, buf);
if (ret < 0)
return ret;
return 0;
}
struct fmcadc_timestamp *fmcadc_zio_tstamp_buffer(struct fmcadc_buffer *buf,
struct fmcadc_timestamp *ts)
{
struct zio_control *ctrl = buf->metadata;
if (ts) {
memcpy(ts, &ctrl->tstamp, sizeof(*ts)); /* FIXME: endianness */
return ts;
}
return (struct fmcadc_timestamp *)&ctrl->tstamp;
}
int fmcadc_zio_release_buffer(struct fmcadc_dev *dev,
struct fmcadc_buffer *buf,
void (*free_fn)(void *))
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
free(buf->metadata);
if (!free_fn && fa->flags & FMCADC_FLAG_MALLOC)
free_fn = free;
if (free_fn)
free_fn(buf->data);
else if (buf->mapaddr && buf->mapaddr != MAP_FAILED)
munmap(buf->mapaddr, buf->maplen);
free(buf);
return 0;
}
/*
* ZIO-specific configuration (mostly device-independent)
*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fmcadc-lib.h"
#include "fmcadc-lib-int.h"
#define FMCADC_CONF_GET 0
#define FMCADC_CONF_SET 1
/*
* Internal functions to read and write a string.
* Trailing newlines are added/removed as needed
*/
static int __fa_zio_sysfs_set(struct __fmcadc_dev_zio *fa, char *name,
char *val, int maxlen)
{
char pathname[128];
char newval[maxlen + 1];
int fd, ret, len;
snprintf(pathname, sizeof(pathname), "%s/%s", fa->sysbase, name);
len = sprintf(newval, "%s\n", val);
fd = open(pathname, O_WRONLY);
if (fd < 0)
return -1;
ret = write(fd, newval, len);
close(fd);
if (ret < 0)
return -1;
if (ret == len)
return 0;
errno = EIO; /* short write */
return -1;
}
static int __fa_zio_sysfs_get(struct __fmcadc_dev_zio *fa, char *name,
char *val /* no maxlen: reader knows */ )
{
char pathname[128];
int fd, ret;
snprintf(pathname, sizeof(pathname), "%s/%s", fa->sysbase, name);
fd = open(pathname, O_RDONLY);
if (fd < 0)
return -1;
ret = read(fd, val, 128 /* well... user knows... */);
close(fd);
if (ret < 0)
return -1;
if (val[ret - 1] == '\n')
val[ret - 1] = '\0';
return 0;
}
/*
* Public functions (through ops and ./route.c).
* They manage both strings and integers
*/
int fmcadc_zio_set_param(struct fmcadc_dev *dev, char *name,
char *sptr, int *iptr)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
char istr[12];
int len;
if (sptr)
return __fa_zio_sysfs_set(fa, name, sptr, strlen(sptr + 2));
len = sprintf(istr, "%i", *iptr);
return __fa_zio_sysfs_set(fa, name, istr, len + 2);
}
int fmcadc_zio_get_param(struct fmcadc_dev *dev, char *name,
char *sptr, int *iptr)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
char istr[12];
int ret;
if (sptr)
return __fa_zio_sysfs_get(fa, name, sptr);
ret = __fa_zio_sysfs_get(fa, name, istr);
if (ret < 0)
return ret;
if (sscanf(istr, "%i", iptr) == 1)
return 0;
errno = EINVAL;
return -1;
}
/*
* Previous functions, now based on the public ones above
* Note: they are swapped: get, then set (above is set then get)
* FIXME: code using these must be refactored using data structures
*/
static int fa_zio_sysfs_get(struct __fmcadc_dev_zio *fa, char *name,
uint32_t *resp)
{
struct fmcadc_dev *dev = (struct fmcadc_dev *)&fa->gid; /* hack: back and forth.. */
int ret;
int val;
ret = fmcadc_zio_get_param(dev, name, NULL, &val);
if (!ret) {
*resp = val; /* different type */
return 0;
}
if (!(fa->flags & FMCADC_FLAG_VERBOSE))
return ret;
/* verbose tail */
if (ret)
fprintf(stderr, "lib-fmcadc: Error reading %s (%s)\n",
name, strerror(errno));
else
fprintf(stderr, "lib-fmcadc: %08x %5i <- %s\n",
(int)*resp, (int)*resp, name);
return ret;
}
int fa_zio_sysfs_set(struct __fmcadc_dev_zio *fa, char *name,
uint32_t *value)
{
struct fmcadc_dev *dev = (struct fmcadc_dev *)&fa->gid; /* hack: back and forth.. */
int ret;
int val = *value; /* different type */
ret = fmcadc_zio_set_param(dev, name, NULL, &val);
if (!ret)
return 0;
if (!(fa->flags & FMCADC_FLAG_VERBOSE))
return ret;
/* verbose tail */
if (ret)
fprintf(stderr, "lib-fmcadc: Error writing %s (%s)\n",
name, strerror(errno));
else
fprintf(stderr, "lib-fmcadc: %08x %5i -> %s\n",
(int)*value, (int)*value, name);
return ret;
}
static int fmcadc_zio_config_trg(struct __fmcadc_dev_zio *fa,
unsigned int index, uint32_t *value, unsigned int direction)
{
switch (index) {
case FMCADC_CONF_TRG_SOURCE:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/trigger/external",
value);
else
return fa_zio_sysfs_get(fa, "cset0/trigger/external",
value);
break;
case FMCADC_CONF_TRG_SOURCE_CHAN:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/trigger/int-channel",
value);
else
return fa_zio_sysfs_get(fa, "cset0/trigger/int-channel",
value);
break;
case FMCADC_CONF_TRG_THRESHOLD:
if (direction)
return fa_zio_sysfs_set(fa,
"cset0/trigger/int-threshold", value);
else
return fa_zio_sysfs_get(fa,
"cset0/trigger/int-threshold", value);
break;
case FMCADC_CONF_TRG_POLARITY:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/trigger/polarity",
value);
else
return fa_zio_sysfs_get(fa, "cset0/trigger/polarity",
value);
break;
case FMCADC_CONF_TRG_DELAY:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/trigger/delay",
value);
else
return fa_zio_sysfs_get(fa, "cset0/trigger/delay",
value);
break;
case FMCADC_CONF_TRG_THRESHOLD_FILTER:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/trigger/int-threshold-filter",
value);
else
return fa_zio_sysfs_get(fa, "cset0/trigger/int-threshold-filter",
value);
break;
default:
errno = FMCADC_ENOCAP;
return -1;
}
}
static int fmcadc_zio_config_acq(struct __fmcadc_dev_zio *fa,
unsigned int index, uint32_t *value, unsigned int direction)
{
switch (index) {
case FMCADC_CONF_ACQ_N_SHOTS:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/trigger/nshots",
value);
else
return fa_zio_sysfs_get(fa, "cset0/trigger/nshots",
value);
break;
case FMCADC_CONF_ACQ_POST_SAMP:
if (direction)
return fa_zio_sysfs_set(fa,
"cset0/trigger/post-samples", value);
else
return fa_zio_sysfs_get(fa,
"cset0/trigger/post-samples", value);
break;
case FMCADC_CONF_ACQ_PRE_SAMP:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/trigger/pre-samples",
value);
else
return fa_zio_sysfs_get(fa, "cset0/trigger/pre-samples",
value);
break;
case FMCADC_CONF_ACQ_DECIMATION:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/sample-decimation",
value);
else
return fa_zio_sysfs_get(fa, "cset0/sample-decimation",
value);
break;
case FMCADC_CONF_ACQ_FREQ_HZ:
if (direction) {
errno = FMCADC_ENOSET;
return -1;
} else {
*value = 100000000; /* 100Mhz */
return 0;
}
break;
case FMCADC_CONF_ACQ_N_BITS:
if (direction) {
errno = FMCADC_ENOSET;
return -1;
} else {
*value = 14;
return 0;
}
break;
default:
errno = FMCADC_ENOCAP;
return -1;
}
}
static int fmcadc_zio_config_chn(struct __fmcadc_dev_zio *fa, unsigned int ch,
unsigned int index, uint32_t *value, unsigned int direction)
{
char path[128];
switch (index) {
case FMCADC_CONF_CHN_RANGE:
sprintf(path, "cset%d/ch%d-vref", fa->cset, ch);
if (direction)
return fa_zio_sysfs_set(fa, path, value);
else
return fa_zio_sysfs_get(fa, path, value);
break;
case FMCADC_CONF_CHN_TERMINATION:
sprintf(path, "cset%d/ch%d-50ohm-term", fa->cset, ch);
if (direction)
return fa_zio_sysfs_set(fa, path, value);
else
return fa_zio_sysfs_get(fa, path, value);
break;
case FMCADC_CONF_CHN_OFFSET:
sprintf(path, "cset%d/ch%d-offset", fa->cset, ch);
if (direction)
return fa_zio_sysfs_set(fa, path, value);
else
return fa_zio_sysfs_get(fa, path, value);
break;
case FMCADC_CONF_CHN_SATURATION:
sprintf(path, "cset%d/ch%d-saturation", fa->cset, ch);
if (direction)
return fa_zio_sysfs_set(fa, path, value);
else
return fa_zio_sysfs_get(fa, path, value);
break;
default:
errno = FMCADC_ENOCAP;
return -1;
}
return 0;
}
static int fmcadc_zio_config_brd(struct __fmcadc_dev_zio *fa,
unsigned int index, uint32_t *value, unsigned int direction)
{
switch (index) {
case FMCADC_CONF_UTC_TIMING_BASE_S:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/tstamp-base-s",
value);
else
return fa_zio_sysfs_get(fa, "cset0/tstamp-base-s",
value);
break;
case FMCADC_CONF_UTC_TIMING_BASE_T:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/tstamp-base-t",
value);
else
return fa_zio_sysfs_get(fa, "cset0/tstamp-base-t",
value);
break;
case FMCADC_CONF_BRD_STATE_MACHINE_STATUS:
if (!direction)
return fa_zio_sysfs_get(fa, "cset0/fsm-state",
value);
errno = EINVAL;
return -1;
case FMCADC_CONF_BRD_N_CHAN:
if (!direction) {
*value = 4;
return 0;
}
errno = EINVAL;
return -1;
default:
errno = FMCADC_ENOCAP;
return -1;
}
}
static int fmcadc_zio_config(struct __fmcadc_dev_zio *fa, unsigned int flags,
struct fmcadc_conf *conf, unsigned int direction)
{
int err = 0, i;
uint32_t enabled;
/* Disabling the trigger before changing configuration */
if (direction) {
err = fa_zio_sysfs_get(fa, "cset0/trigger/enable", &enabled);
if (err)
return err;
if (enabled) {
enabled = 0;
err = fa_zio_sysfs_set(fa, "cset0/trigger/enable", &enabled);
/* restore the initial value */
enabled = 1;
}
}
for (i = 0; i < __FMCADC_CONF_LEN; ++i) {
if (!(conf->mask & (1LL << i)))
continue;
/* Parameter to configure */
switch (conf->type) {
case FMCADC_CONF_TYPE_TRG:
err = fmcadc_zio_config_trg(fa, i, &conf->value[i],
direction);
break;
case FMCADC_CONF_TYPE_ACQ:
err = fmcadc_zio_config_acq(fa, i, &conf->value[i],
direction);
break;
case FMCADC_CONF_TYPE_CHN:
if (conf->route_to > 3) {
errno = FMCADC_ENOCHAN;
return -1;
}
err = fmcadc_zio_config_chn(fa, conf->route_to,
i, &conf->value[i],
direction);
break;
case FMCADC_CONT_TYPE_BRD:
err = fmcadc_zio_config_brd(fa, i, &conf->value[i],
direction);
break;
default:
errno = FMCADC_ENOCFG;
return -1;
}
if (err)
break; /* stop the config process: an error occurs */
}
/* if the trigger was enabled restore it */
if (direction && enabled)
err = fa_zio_sysfs_set(fa, "cset0/trigger/enable", &enabled);
return err;
}
int fmcadc_zio_apply_config(struct fmcadc_dev *dev, unsigned int flags,
struct fmcadc_conf *conf)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
return fmcadc_zio_config(fa, flags, conf, FMCADC_CONF_SET);
}
int fmcadc_zio_retrieve_config(struct fmcadc_dev *dev,
struct fmcadc_conf *conf)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
return fmcadc_zio_config(fa, 0, conf, FMCADC_CONF_GET);
}
/*
* The ADC library for the specific card
*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <linux/zio-user.h>
#include <fmc-adc-100m14b4cha.h>
#include "fmcadc-lib.h"
#include "fmcadc-lib-int.h"
#define ZIO_SYS_PATH "/sys/bus/zio/devices"
#define FMCADC_NCHAN 4
static int fmcadc_flush_input(struct __fmcadc_dev_zio *fa)
{
struct zio_control ctrl;
struct pollfd p = {
.fd = fa->fdc,
.events = POLLIN | POLLERR,
};
int i;
/* Read the control until one is there; data is discarded by zio */
while (1) {
i = poll(&p, 1, 0);
if (i < 0)
return -1;
if ((p.revents & POLLIN) == 0)
return 0;
read(fa->fdc, &ctrl, sizeof(ctrl));
}
}
struct fmcadc_dev *fmcadc_zio_open(const struct fmcadc_board_type *b,
unsigned int dev_id,
unsigned long totalsamples,
unsigned int nbuffer,
unsigned long flags)
{
struct __fmcadc_dev_zio *fa;
struct stat st;
char *syspath, *devpath, fname[128];
int udev_zio_dir = 1;
/* Check if device exists by looking in sysfs */
asprintf(&syspath, "%s/%s-%04x", ZIO_SYS_PATH, b->devname, dev_id);
if (stat(syspath, &st))
goto out_fa_stat; /* ENOENT or equivalent */
/* ZIO char devices are in /dev/zio or just /dev (older udev) */
if (stat("/dev/zio", &st) < 0)
udev_zio_dir = 0;
asprintf(&devpath, "%s/%s-%04x", (udev_zio_dir ? "/dev/zio" : "/dev"),
b->devname, dev_id);
/* Sysfs path exists, so device is there, hopefully */
fa = calloc(1, sizeof(*fa));
if (!fa)
goto out_fa_alloc;
fa->sysbase = syspath;
fa->devbase = devpath;
fa->cset = 0;
/* Open char devices */
sprintf(fname, "%s-0-i-ctrl", fa->devbase);
fa->fdc = open(fname, O_RDONLY);
sprintf(fname, "%s-0-i-data", fa->devbase);
fa->fdd = open(fname, O_RDONLY);
if (fa->fdc < 0 || fa->fdd < 0)
goto out_fa_open;
if (flags & FMCADC_F_FLUSH)
if (fmcadc_flush_input(fa) < 0)
goto out_fa_open;
fa->gid.board = b;
/*
* We need to save the page size and samplesize.
* Samplesize includes the nchan in the count.
*/
fa->samplesize = 8; /* FIXME: should read sysfs instead -- where? */
fa->pagesize = getpagesize();
/* Support verbose operation (turn user flag into internal flag)*/
if (flags & FMCADC_F_VERBOSE || getenv("LIB_FMCADC_VERBOSE"))
fa->flags |= FMCADC_FLAG_VERBOSE;
return (void *) &fa->gid;
out_fa_open:
if (fa->fdc >= 0)
close(fa->fdc);
if (fa->fdd >= 0)
close(fa->fdd);
free(fa);
out_fa_alloc:
free(devpath);
out_fa_stat:
free(syspath);
return NULL;
}
int fmcadc_zio_close(struct fmcadc_dev *dev)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
close(fa->fdc);
close(fa->fdd);
free(fa->sysbase);
free(fa->devbase);
free(fa);
return 0;
}
/* poll is used by start, so it's defined first */
int fmcadc_zio_acq_poll(struct fmcadc_dev *dev,
unsigned int flags, struct timeval *to)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
struct pollfd p;
int to_ms, ret;
/* So, first sample and blocking read. Wait.. */
p.fd = fa->fdc;
p.events = POLLIN | POLLERR;
if (!to)
to_ms = -1;
else
to_ms = to->tv_sec / 1000 + (to->tv_usec + 500) / 1000;
ret = poll(&p, 1, to_ms);
switch (ret) {
case 0:
errno = EAGAIN;
/* fall through */
case -1:
return -1;
}
if (p.revents & POLLERR) {
errno = FMCADC_EDISABLED;
return -1;
}
return 0;
}
int fmcadc_zio_acq_start(struct fmcadc_dev *dev,
unsigned int flags, struct timeval *timeout)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
uint32_t cmd = 1; /* hw command for "start" */
int err;
if (flags & FMCADC_F_FLUSH)
if (fmcadc_flush_input(fa) < 0)
return -1;
err = fa_zio_sysfs_set(fa, "cset0/fsm-command", &cmd);
if (err)
return err;
if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
return 0;
return fmcadc_zio_acq_poll(dev, flags, timeout);
}
int fmcadc_zio_acq_stop(struct fmcadc_dev *dev, unsigned int flags)
{
struct __fmcadc_dev_zio *fa = to_dev_zio(dev);
uint32_t cmd = 2; /* hw command for "stop" */
return fa_zio_sysfs_set(fa, "cset0/fsm-command", &cmd);
}
/*
* Copyright CERN 2013
* Author: Federico Vaga <federico.vaga@gmail.com>
*/
#ifndef FMCADC_LIB_INT_H_
#define FMCADC_LIB_INT_H_
/*
* offsetof and container_of come from kernel.h header file
*/
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = ((void *)ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define to_dev_zio(dev) (container_of(dev, struct __fmcadc_dev_zio, gid))
/* ->open takes different args than open(), so fa a fun to use tpyeof */
struct fmcadc_board_type;
struct fmcadc_dev *fmcadc_internal_open(const struct fmcadc_board_type *b,
unsigned int dev_id,
unsigned long totalsamples,
unsigned int nbuffer,
unsigned long flags);
/*
* The operations structure is the device-specific backend of the library
*/
struct fmcadc_operations {
typeof(fmcadc_internal_open) *open;
typeof(fmcadc_close) *close;
typeof(fmcadc_acq_start) *acq_start;
typeof(fmcadc_acq_poll) *acq_poll;
typeof(fmcadc_acq_stop) *acq_stop;
typeof(fmcadc_apply_config) *apply_config;
typeof(fmcadc_retrieve_config) *retrieve_config;
typeof(fmcadc_get_param) *get_param;
typeof(fmcadc_set_param) *set_param;
typeof(fmcadc_request_buffer) *request_buffer;
typeof(fmcadc_fill_buffer) *fill_buffer;
typeof(fmcadc_tstamp_buffer) *tstamp_buffer;
typeof(fmcadc_release_buffer) *release_buffer;
};
/*
* This structure describes the board supported by the library
* @name name of the board type, for example "fmc-adc-100MS"
* @devname name of the device in Linux
* @driver_type: the kind of driver that hanlde this kind of board (e.g. ZIO)
* @capabilities bitmask of device capabilities for trigger, channel
* acquisition
* @fa_op pointer to a set of operations
*/
struct fmcadc_board_type {
char *name;
char *devname;
char *driver_type;
uint32_t capabilities[__FMCADC_CONF_TYPE_LAST_INDEX];
struct fmcadc_operations *fa_op;
};
/*
* Generic Instance Descriptor
*/
struct fmcadc_gid {
const struct fmcadc_board_type *board;
};
/* Definition of board types */
extern struct fmcadc_board_type fmcadc_100ms_4ch_14bit;
/* Internal structure (ZIO specific, for ZIO drivers only) */
struct __fmcadc_dev_zio {
unsigned int cset;
int fdc;
int fdd;
uint32_t dev_id;
unsigned long flags;
char *devbase;
char *sysbase;
unsigned long samplesize;
unsigned long pagesize;
/* Mandatory field */
struct fmcadc_gid gid;
};
/* Note: bit 16 and up are passed by users, see fmcadc-lib.h */
#define FMCADC_FLAG_VERBOSE 0x00000001
#define FMCADC_FLAG_MALLOC 0x00000002 /* allocate data */
#define FMCADC_FLAG_MMAP 0x00000004 /* mmap data */
/* The board-specific functions are defined in fmc-adc-100m14b4cha.c */
struct fmcadc_dev *fmcadc_zio_open(const struct fmcadc_board_type *b,
unsigned int dev_id,
unsigned long totalsamples,
unsigned int nbuffer,
unsigned long flags);
int fmcadc_zio_close(struct fmcadc_dev *dev);
int fmcadc_zio_acq_start(struct fmcadc_dev *dev,
unsigned int flags, struct timeval *timeout);
int fmcadc_zio_acq_poll(struct fmcadc_dev *dev, unsigned int flags,
struct timeval *timeout);
int fmcadc_zio_acq_stop(struct fmcadc_dev *dev,
unsigned int flags);
struct fmcadc_buffer *fmcadc_zio_request_buffer(struct fmcadc_dev *dev,
int nsamples,
void *(*alloc)(size_t),
unsigned int flags);
int fmcadc_zio_fill_buffer(struct fmcadc_dev *dev,
struct fmcadc_buffer *buf,
unsigned int flags,
struct timeval *timeout);
struct fmcadc_timestamp *fmcadc_zio_tstamp_buffer(struct fmcadc_buffer *buf,
struct fmcadc_timestamp *);
int fmcadc_zio_release_buffer(struct fmcadc_dev *dev,
struct fmcadc_buffer *buf,
void (*free_fn)(void *));
/* The following functions are in config-zio.c */
int fmcadc_zio_apply_config(struct fmcadc_dev *dev, unsigned int flags,
struct fmcadc_conf *conf);
int fmcadc_zio_retrieve_config(struct fmcadc_dev *dev,
struct fmcadc_conf *conf);
int fmcadc_zio_set_param(struct fmcadc_dev *dev, char *name,
char *sptr, int *iptr);
int fmcadc_zio_get_param(struct fmcadc_dev *dev, char *name,
char *sptr, int *iptr);
int fa_zio_sysfs_set(struct __fmcadc_dev_zio *fa, char *name,
uint32_t *value);
#endif /* FMCADC_LIB_INT_H_ */
/*
* Copyright CERN 2013
* Author: Federico Vaga <federico.vaga@gmail.com>
*/
#ifndef FMCADC_LIB_H_
#define FMCADC_LIB_H_
#ifdef __cplusplus
#pragma GCC diagnostic ignored "-Wwrite-strings"
extern "C" {
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
/* Error codes start from 1024 to void conflicting with libc codes */
#define __FMCADC_ERRNO_START 1024
#define FMCADC_ENOP 1024
#define FMCADC_ENOCAP 1025
#define FMCADC_ENOCFG 1026
#define FMCADC_ENOGET 1027
#define FMCADC_ENOSET 1028
#define FMCADC_ENOCHAN 1029
#define FMCADC_ENOMASK 1030
#define FMCADC_EDISABLED 1031
struct fmcadc_dev;
enum fmcadc_supported_board {
FMCADC_100MS_4CH_14BIT,
__FMCADC_SUPPORTED_BOARDS_LAST_INDEX,
};
/* The buffer hosts data and metadata, plus informative fields */
struct fmcadc_buffer {
void *data;
void *metadata;
int samplesize;
int nsamples;
struct fmcadc_dev *dev;
void *mapaddr;
unsigned long maplen;
unsigned long flags; /* internal to the library */
};
/* This is exactly the zio_timestamp, there is no depency on zio here */
struct fmcadc_timestamp {
uint64_t secs;
uint64_t ticks;
uint64_t bins;
};
/* The following enum can be use to se the mask of valid configurations */
enum fmcadc_configuration_trigger {
FMCADC_CONF_TRG_SOURCE = 0,
FMCADC_CONF_TRG_SOURCE_CHAN,
FMCADC_CONF_TRG_THRESHOLD,
FMCADC_CONF_TRG_POLARITY,
FMCADC_CONF_TRG_DELAY,
FMCADC_CONF_TRG_THRESHOLD_FILTER,
__FMCADC_CONF_TRG_ATTRIBUTE_LAST_INDEX,
};
enum fmcadc_configuration_acquisition {
FMCADC_CONF_ACQ_N_SHOTS = 0,
FMCADC_CONF_ACQ_POST_SAMP,
FMCADC_CONF_ACQ_PRE_SAMP,
FMCADC_CONF_ACQ_DECIMATION,
FMCADC_CONF_ACQ_FREQ_HZ,
FMCADC_CONF_ACQ_N_BITS,
__FMCADC_CONF_ACQ_ATTRIBUTE_LAST_INDEX,
};
enum fmcadc_configuration_channel {
FMCADC_CONF_CHN_RANGE = 0,
FMCADC_CONF_CHN_TERMINATION,
FMCADC_CONF_CHN_OFFSET,
FMCADC_CONF_CHN_SATURATION,
__FMCADC_CONF_CHN_ATTRIBUTE_LAST_INDEX,
};
enum fmcadc_board_status {
FMCADC_CONF_BRD_STATUS = 0,
FMCADC_CONF_BRD_MAX_FREQ_HZ,
FMCADC_CONF_BRD_MIN_FREQ_HZ,
FMCADC_CONF_BRD_STATE_MACHINE_STATUS,
FMCADC_CONF_BRD_N_CHAN,
FMCADC_CONF_UTC_TIMING_BASE_S,
FMCADC_CONF_UTC_TIMING_BASE_T,
FMCADC_CONF_UTC_TIMING_BASE_B,
__FMCADC_CONF_BRD_ATTRIBUTE_LAST_INDEX,
};
enum fmcadc_configuration_type {
FMCADC_CONF_TYPE_TRG = 0, /* Trigger */
FMCADC_CONF_TYPE_ACQ, /* Acquisition */
FMCADC_CONF_TYPE_CHN, /* Channel */
FMCADC_CONF_TYPE_BRD, /* Board */
__FMCADC_CONF_TYPE_LAST_INDEX,
};
/* @deprecated: old typo, keep it for compatibility */
#define FMCADC_CONT_TYPE_BRD FMCADC_CONF_TYPE_BRD
#define __FMCADC_CONF_LEN 64 /* number of allocated items in each structure */
struct fmcadc_conf {
enum fmcadc_configuration_type type;
uint32_t dev_type;
uint32_t route_to;
uint32_t flags; /* how to identify invalid? */
uint64_t mask;
uint32_t value[__FMCADC_CONF_LEN];
};
static inline void fmcadc_set_conf_mask(struct fmcadc_conf *conf,
unsigned int conf_index)
{
conf->mask |= (1LL << conf_index);
}
/* assign a configuration item, and its mask */
static inline void fmcadc_set_conf(struct fmcadc_conf *conf,
unsigned int conf_index, uint32_t val)
{
conf->value[conf_index] = val;
fmcadc_set_conf_mask(conf, conf_index);
}
/* retieve a configuration item */
static inline int fmcadc_get_conf(struct fmcadc_conf *conf,
unsigned int conf_index,
uint32_t *val)
{
if (conf->mask & (1LL << conf_index)) {
*val = conf->value[conf_index];
return 0;
} else {
return -1;
}
}
/* Flags used in open/acq/config -- note: low-bits are used by lib-int.h */
#define FMCSDC_F_USERMASK 0xffff0000
#define FMCADC_F_FLUSH 0x00010000
#define FMCADC_F_VERBOSE 0x00020000
/*
* Actual functions follow
*/
extern int fmcadc_init(void);
extern void fmcadc_exit(void);
extern char *fmcadc_strerror(int errnum);
extern struct fmcadc_dev *fmcadc_open(char *name, unsigned int dev_id,
unsigned long totalsamples,
unsigned int nbuffer,
unsigned long flags);
extern struct fmcadc_dev *fmcadc_open_by_lun(char *name, int lun,
unsigned long totalsamples,
unsigned int nbuffer,
unsigned long flags);
extern int fmcadc_close(struct fmcadc_dev *dev);
extern int fmcadc_acq_start(struct fmcadc_dev *dev, unsigned int flags,
struct timeval *timeout);
extern int fmcadc_acq_poll(struct fmcadc_dev *dev, unsigned int flags,
struct timeval *timeout);
extern int fmcadc_acq_stop(struct fmcadc_dev *dev, unsigned int flags);
extern int fmcadc_reset_conf(struct fmcadc_dev *dev, unsigned int flags,
struct fmcadc_conf *conf);
extern int fmcadc_apply_config(struct fmcadc_dev *dev, unsigned int flags,
struct fmcadc_conf *conf);
extern int fmcadc_retrieve_config(struct fmcadc_dev *dev,
struct fmcadc_conf *conf);
extern int fmcadc_get_param(struct fmcadc_dev *dev, char *name,
char *sptr, int *iptr);
extern int fmcadc_set_param(struct fmcadc_dev *dev, char *name,
char *sptr, int *iptr);
extern struct fmcadc_buffer *fmcadc_request_buffer(struct fmcadc_dev *dev,
int nsamples,
void *(*alloc_fn)(size_t),
unsigned int flags);
extern int fmcadc_fill_buffer(struct fmcadc_dev *dev,
struct fmcadc_buffer *buf,
unsigned int flags,
struct timeval *timeout);
extern struct fmcadc_timestamp *fmcadc_tstamp_buffer(struct fmcadc_buffer *buf,
struct fmcadc_timestamp *);
extern int fmcadc_release_buffer(struct fmcadc_dev *dev,
struct fmcadc_buffer *buf,
void (*free_fn)(void *));
extern char *fmcadc_get_driver_type(struct fmcadc_dev *dev);
/* libfmcadc version string */
extern const char * const libfmcadc_version_s;
/* zio version string used during compilation of libfmcadc */
extern const char * const libfmcadc_zio_version_s;
static inline int fmcadc_mshot_buf_max_size_get(struct fmcadc_dev *dev,
int *value)
{
return fmcadc_get_param(dev, "cset0/max-sample-mshot", NULL, value);
}
static inline int fmcadc_buffer_type_get(struct fmcadc_dev *dev, char *buf_type)
{
return fmcadc_get_param(dev, "cset0/current_buffer", buf_type, NULL);
}
static inline int fmcadc_buffer_maximum_size_get(struct fmcadc_dev *dev,
int *size)
{
char s[16];
int err;
err = fmcadc_buffer_type_get(dev, s);
if (err)
return -1;
if (!strcmp(s, "vmalloc")) {
return fmcadc_get_param(dev,
"cset0/chani/buffer/max-buffer-kb",
NULL, size);
} else if (!strcmp(s, "kmalloc")) {
return 4 * 1024; /* MiB => KiB */
}
return -1;
}
static inline int fmcadc_buffer_maximum_size_set(struct fmcadc_dev *dev,
int size)
{
char s[16];
int err;
err = fmcadc_buffer_type_get(dev, s);
if (err)
return -1;
if (!strcmp(s, "vmalloc")) {
return fmcadc_set_param(dev,
"cset0/chani/buffer/max-buffer-kb",
NULL, &size);
} else if (!strcmp(s, "kmalloc")) {
return -1; /* cannot be changed */
}
return -1;
}
/**
* Get the current software trigger enable status
* @param[in] dev adc device token
* @param[out] enable enable status
* @return 0 on success. -1 on error and errno is set appropriately
*/
static inline int fmcadc_trigger_sw_status(struct fmcadc_dev *dev,
unsigned int *enable)
{
return fmcadc_get_param(dev, "cset0/trigger/sw-trg-enable",
NULL, (int *)enable);
}
/**
* Set the current software trigger enable status
* @param[in] dev adc device token
* @param[in] enable 0 disable, 1 enable
* @return 0 on success. -1 on error and errno is set appropriately
*/
static inline int fmcadc_trigger_sw_enable(struct fmcadc_dev *dev,
unsigned int enable)
{
int value = !!enable;
return fmcadc_set_param(dev, "cset0/trigger/sw-trg-enable",
NULL, &value);
}
/**
* Execute a software trigger
* @param[in] dev adc device token
* @return 0 on success. -1 on error and errno is set appropriately
*/
static inline int fmcadc_trigger_sw_fire(struct fmcadc_dev *dev)
{
int value = 1;
return fmcadc_set_param(dev, "cset0/trigger/sw-trg-fire",
NULL, &value);
}
#ifdef __cplusplus
}
#endif
#endif /* FMCADC_LIB_H_ */
/*
* Copyright CERN 2013, GNU GPL 2 or later.
* Author: Alessandro Rubini
*/
#include "fmcadc-lib.h"
const char * const libfmcadc_version_s = "libfmcadc version: " GIT_VERSION;
const char * const libfmcadc_zio_version_s = "libfmcadc is using zio version: " ZIO_GIT_VERSION;
/* We currently do nothing in init/exit. We might check /proc/meminfo... */
int fmcadc_init(void)
{
return 0;
}
void fmcadc_exit(void)
{
return;
}
/*
* Initializing and cleaning up the fmc adc library
*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <string.h>
#include "fmcadc-lib.h"
#include "fmcadc-lib-int.h"
/* * * * * * * * * * * * * * * * Utilities * * * * * * * * * * * * * * * * */
/*
* fmcadc_strerror
* @dev: device for which you want to know the meaning of the error
* @errnum: error number
*/
static struct fmcadc_errors {
int num;
char *str;
} fmcadc_errors[] = {
{ FMCADC_ENOP, "Operation not supported"},
{ FMCADC_ENOCAP, "Capabilities not supported"},
{ FMCADC_ENOCFG, "Configuration type not supported"},
{ FMCADC_ENOGET, "Cannot get capabilities information"},
{ FMCADC_ENOSET, "Cannot set capabilities information"},
{ FMCADC_ENOCHAN, "Invalid channel"},
{ FMCADC_ENOMASK, "Missing configuration mask"},
{ FMCADC_EDISABLED, "Trigger is disabled: I/O aborted"},
{ 0, }
};
char *fmcadc_strerror(int errnum)
{
struct fmcadc_errors *p;
if (errnum < __FMCADC_ERRNO_START)
return strerror(errnum);
for (p = fmcadc_errors; p->num; p++)
if (p->num == errnum)
return p->str;
return "Unknown error code";
}
/*
* fmcadc_get_driver_type
* @dev: device which want to know the driver type
*/
char *fmcadc_get_driver_type(struct fmcadc_dev *dev)
{
struct fmcadc_gid *b = (void *)dev;
return b->board->driver_type;
}
/*
* Routing public functions to device-specific code
*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fmcadc-lib.h"
#include "fmcadc-lib-int.h"
int fmcadc_acq_start(struct fmcadc_dev *dev,
unsigned int flags,
struct timeval *timeout)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
return b->fa_op->acq_start(dev, flags, timeout);
}
int fmcadc_acq_poll(struct fmcadc_dev *dev, unsigned int flags,
struct timeval *timeout)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
return b->fa_op->acq_poll(dev, flags, timeout);
}
int fmcadc_acq_stop(struct fmcadc_dev *dev, unsigned int flags)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
return b->fa_op->acq_stop(dev, flags);
}
int fmcadc_apply_config(struct fmcadc_dev *dev, unsigned int flags,
struct fmcadc_conf *conf)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
uint64_t cap_mask;
if (!conf->mask) {
errno = FMCADC_ENOMASK;
return -1; /* Nothing to do */
}
cap_mask = b->capabilities[conf->type];
if ((cap_mask & conf->mask) != conf->mask) {
/* Unsupported capabilities */
errno = FMCADC_ENOCAP;
return -1;
}
return b->fa_op->apply_config(dev, flags, conf);
}
int fmcadc_retrieve_config(struct fmcadc_dev *dev, struct fmcadc_conf *conf)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
uint64_t cap_mask;
if (!conf->mask) {
errno = FMCADC_ENOMASK;
return -1; /* Nothing to do */
}
cap_mask = b->capabilities[conf->type];
if ((cap_mask & conf->mask) != conf->mask) {
/* Unsupported capabilities */
errno = FMCADC_ENOCAP;
return -1;
}
return b->fa_op->retrieve_config(dev, conf);
}
int fmcadc_get_param(struct fmcadc_dev *dev, char *name,
char *sptr, int *iptr)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
return b->fa_op->get_param(dev, name, sptr, iptr);
}
int fmcadc_set_param(struct fmcadc_dev *dev, char *name,
char *sptr, int *iptr)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
return b->fa_op->set_param(dev, name, sptr, iptr);
}
struct fmcadc_buffer *fmcadc_request_buffer(struct fmcadc_dev *dev,
int nsamples,
void *(*alloc)(size_t),
unsigned int flags)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
return b->fa_op->request_buffer(dev, nsamples, alloc, flags);
}
int fmcadc_fill_buffer(struct fmcadc_dev *dev,
struct fmcadc_buffer *buf,
unsigned int flags,
struct timeval *timeout)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
return b->fa_op->fill_buffer(dev, buf, flags, timeout);
}
struct fmcadc_timestamp *fmcadc_tstamp_buffer(struct fmcadc_buffer *buf,
struct fmcadc_timestamp *ts)
{
struct fmcadc_gid *g = (struct fmcadc_gid *)buf->dev;
const struct fmcadc_board_type *b = g->board;
return b->fa_op->tstamp_buffer(buf, ts);
}
int fmcadc_release_buffer(struct fmcadc_dev *dev, struct fmcadc_buffer *buf,
void (*free)(void *))
{
struct fmcadc_gid *g = (struct fmcadc_gid *)dev;
const struct fmcadc_board_type *b = g->board;
if (!buf)
return 0;
return b->fa_op->release_buffer(dev, buf, free);
}
fald-simple-acq
fald-test
fald-simple-get-conf
fald-acq
fald-trg-cfg
fald-bad-clock
\ No newline at end of file
# If it exists includes Makefile.specific. In this Makefile, you should put
# specific Makefile code that you want to run before this. For example,
# build a particular environment.
-include Makefile.specific
# include parent_common.mk for buildsystem's defines
REPO_PARENT ?= ../..
-include $(REPO_PARENT)/parent_common.mk
DESTDIR ?= /usr/local
LIBADC = ../lib/
ZIO ?= ../zio
ZIO_ABS ?= $(abspath $(ZIO) )
GIT_VERSION := $(shell git describe --dirty --long --tags)
ZIO_GIT_VERSION := $(shell cd $(ZIO_ABS); git describe --dirty --long --tags)
CFLAGS = -Wall -g -ggdb -I$(LIBADC) -I$(ZIO_ABS)/include -I../kernel $(EXTRACFLAGS)
CFLAGS += -DGIT_VERSION="\"$(GIT_VERSION)\""
CFLAGS += -DZIO_GIT_VERSION="\"$(ZIO_GIT_VERSION)\""
LDFLAGS = -L$(LIBADC)
LDLIBS = -lfmcadc -lpthread -lrt
DEMOS := fald-simple-acq fald-acq fald-trg-cfg
DEMOS += fald-simple-get-conf
DEMOS += fald-test
DEMOS += fald-bad-clock
all: demo
demo: $(DEMOS)
install:
install -d $(DESTDIR)/bin
install -D $(DEMOS) $(DESTDIR)/bin
%: %.c $(LIBADC)/libfmcadc.a
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(LDLIBS)
# make nothing for modules_install, but avoid errors
modules_install:
clean:
rm -f $(DEMOS) *.o *~
.PHONY: all, clean
/* Copyright 2013 CERN
* Author: Federico Vaga <federico.vaga@gmail.com>
* License: GPLv2
*
* This is a simple program to configure the FMC ADC trigger. It is not bug
* aware because it is only a demo program
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <pthread.h>
#include <time.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/zio-user.h>
#include <fmcadc-lib.h>
#include <fmc-adc-100m14b4cha.h>
#ifdef DEBUG
#define fald_print_debug(format, ...) \
fprintf(stdout, "%s(%d)" format, __func__, __LINE__, ##__VA_ARGS__)
#else
#define fald_print_debug(format, ...)
#endif
static char git_version[] = "version: " GIT_VERSION;
static char zio_git_version[] = "zio version: " ZIO_GIT_VERSION;
static void fald_acq_stop(struct fmcadc_dev *adc, char *called_from);
static void fald_help()
{
printf("\nfald-simple-acq [OPTIONS] 0x<device-id>\n\n");
printf(" <device-id>: FMC identifier (e.g.: \"0x0400\")\n");
printf(" --before|-b <num> number of pre samples\n");
printf(" --after|-a <num> n. of post samples (default: 16)\n");
printf(" --nshots|-n <num> number of trigger shots\n");
printf(" --delay|-d <num> delay sample after trigger\n");
printf(" --under-sample|-u|-D <num> pick 1 sample every <num>\n");
printf(" --external|-e use external trigger\n");
printf(" --threshold|-t <num> internal trigger threshold\n");
printf(" --channel|-c <num> channel used as trigger (1..4)\n");
printf(" --range|-r <num> channel input range: "
"100(100mv) 1(1v) 10(10v)\n");
printf(" --sw-trigger|-w <num> ms to wait before generating "
"a software trigger\n");
printf(" --tiemout|-T <millisec> timeout for acquisition\n");
printf(" --negative-edge internal trigger is falling edge\n");
printf(" --binary|-B <file> save binary to <file>\n");
printf(" --multi-binary|-M <file> save two files per shot: "
"<file>.0000.ctrl etc\n");
printf(" --dont-read|-N config-only, use with zio-dump\n");
printf(" --loop|-l <num> number of loop before exiting\n");
printf(" --show-data|-s <num> how many data to display: "
">0 from head, <0 from tail\n");
printf(" --graph|-g <chnum> plot the desired channel\n");
printf(" --X11|-X Gnuplot will use X connection\n");
printf(" --version|-V print version information\n");
printf(" --help|-h show this help\n\n");
}
static int trg_cfgval[__FMCADC_CONF_LEN]; /* FIXME: this is not used */
static struct option options[] = {
{"before", required_argument, 0, 'b'},
{"after", required_argument, 0, 'a'},
{"nshots", required_argument, 0, 'n'},
{"delay", required_argument, 0, 'd'},
{"under-sample",required_argument, 0, 'u'},
{"external", no_argument,
&trg_cfgval[FMCADC_CONF_TRG_SOURCE], 1},
{"threshold", required_argument, 0, 't'},
{"channel", required_argument, 0, 'c'},
{"timeout", required_argument, 0, 'T'},
{"negative-edge", no_argument,
&trg_cfgval[FMCADC_CONF_TRG_POLARITY], 1},
{"sw-trigger", required_argument, 0, 'w'},
/* new options, to help stress-test */
{"binary", required_argument, 0, 'B'},
{"multi-binary",required_argument, 0, 'M'},
{"dont-read", no_argument, 0, 'N'},
{"loop", required_argument, 0, 'l'},
{"show-data", required_argument, 0, 's'},
{"graph", required_argument, 0, 'g'},
{"X11 display", no_argument, 0, 'X'},
{"input-range", required_argument, 0, 'r'},
/* backward-compatible options */
{"pre", required_argument, 0, 'p'},
{"post", required_argument, 0, 'P'},
{"decimation", required_argument, 0, 'D'},
/* loop for stess test */
{"loop", required_argument, 0, 'l'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
#define GETOPT_STRING "b:a:n:d:u:t:c:T:B:M:N:l:s:r:g:X:p:P:D:Vhew:"
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s %s\n", pname, zio_git_version);
printf("%s\n", libfmcadc_version_s);
printf("%s\n", libfmcadc_zio_version_s);
}
/* variables shared between threads */
unsigned int devid = 0;
static pthread_mutex_t mtx;
static pthread_cond_t readyToPollCondVar;
static pthread_cond_t readyToReadOrCfgCondVar;
static int adc_wait_thread_ready;
static int adc_state;
static int poll_state;
static int new_config = 0;
static struct fmcadc_conf trg_cfg, acq_cfg, ch_cfg;
static int show_ndata = INT_MAX; /* by default all values are displayed */
static int plot_chno = -1;
static int x_display;
static int binmode;
static int timeout = -1;
static int loop = 1;
static char *basefile;
#define MAX_BUF 512
static char buf_fifo[MAX_BUF];
static char *_argv[16];
static int _argc;
static unsigned int sw_trigger_enable;
static unsigned int sw_trigger_enable_old;
static unsigned int sw_trigger_wait;
#define ADC_STATE_START_ACQ (1 << 0)
#define ADC_STATE_CHANGE_CFG (1 << 1)
#define ADC_STATE_FAILURE (1 << 2)
#define START_POLL 1
/* default is 1 V*/
static double bit_scale = 0.5/(1<<15);
/**
* It writes data on file
* @param[in] filename file where write data
* @param[in] ch the channel data to write
* @param[in] pdata data from ADC (is interleaved)
* @param[in] n_sample number of sample in pdata (is interleaved)
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
static int write_file(const char *filename, int ch, int16_t *pdata,
unsigned int n_sample)
{
FILE *filp;
int i;
double val;
int mask = umask(0); /* set umask to have a file with 0666 mode */
filp = fopen(filename, "w");
umask(mask); /* restore previous umask */
if (filp == NULL) {
printf("fopen %s failed: %s", filename, strerror(errno));
return -1;
}
for (i = 0, pdata += (ch - 1); i < n_sample; ++i, pdata += 4) {
val = (*pdata)*bit_scale;
fprintf(filp, "%d %g\n", i, val);
}
if (fclose(filp) < 0)
return -1;
return 0;
}
/**
* It parses command line arguments and consequential it configures the device
* @param[in] argc number of arguments
* @param[in] argv arguments
*/
static void fald_acq_parse_args_and_configure(int argc, char *argv[])
{
int c, opt_index, val;
optind = 1; /* set to 1 to make getopt_long happy */
/* Parse options */
while ((c = getopt_long(argc, argv, GETOPT_STRING, options, &opt_index))
>= 0 ) {
switch (c) {
case 'b': case 'p': /* before */
fprintf(stdout, "FMCADC_CONF_ACQ_PRE_SAMP: %d\n",
atoi(optarg));
fmcadc_set_conf(&acq_cfg, FMCADC_CONF_ACQ_PRE_SAMP,
atoi(optarg));
break;
case 'a': case 'P': /* after */
fprintf(stdout, "FMCADC_CONF_ACQ_POST_SAMP: %d\n",
atoi(optarg));
fmcadc_set_conf(&acq_cfg, FMCADC_CONF_ACQ_POST_SAMP,
atoi(optarg));
break;
case 'n':
fprintf(stdout, "FMCADC_CONF_ACQ_N_SHOTS: %d\n",
atoi(optarg));
fmcadc_set_conf(&acq_cfg, FMCADC_CONF_ACQ_N_SHOTS,
atoi(optarg));
break;
case 'd':
fprintf(stdout, "FMCADC_CONF_TRG_DELAY: %d\n",
atoi(optarg));
fmcadc_set_conf(&trg_cfg, FMCADC_CONF_TRG_DELAY,
atoi(optarg));
break;
case 'u': case 'D':
fprintf(stdout, "FMCADC_CONF_ACQ_DECIMATION: %d\n",
atoi(optarg));
fmcadc_set_conf(&acq_cfg, FMCADC_CONF_ACQ_DECIMATION,
atoi(optarg));
break;
case 't':
fprintf(stdout, "FMCADC_CONF_TRG_THRESHOLD: %d\n",
atoi(optarg));
fmcadc_set_conf(&trg_cfg, FMCADC_CONF_TRG_THRESHOLD,
atoi(optarg));
break;
/*
* in-range
* 0x23 (35): 100mV range
* 0x11 (17): 1V range
* 0x45 (69): 10V range
* 0x00 (0): Open input
*/
case 'r':
val = atoi(optarg);
switch (val) {
case 100:
val = 0x23;
bit_scale = 0.05/(1<<15);
break;
case 1:
val = 0x11;
bit_scale = 0.5/(1<<15);
break;
case 10:
val = 0x45;
bit_scale = 5.0/(1<<15);
break;
}
fprintf(stdout, "FMCADC_CONF_CHN_RANGE: %d\n", val);
fmcadc_set_conf(&ch_cfg, FMCADC_CONF_CHN_RANGE,
val);
break;
case 'c':
val = atoi(optarg);
if (val < 1 || val > 4) {
fprintf(stderr, "Invalid channel %d\n", val);
fald_help();
exit(1);
}
fprintf(stdout, "FMCADC_CONF_TRG_SOURCE_CHAN: %d\n",
atoi(optarg));
/* set internal, and then the channel */
trg_cfgval[FMCADC_CONF_TRG_SOURCE] = 0; /* set later */
fmcadc_set_conf(&trg_cfg, FMCADC_CONF_TRG_SOURCE_CHAN,
val - 1);
break;
case 'e':
trg_cfgval[FMCADC_CONF_TRG_SOURCE] = 1;
break;
case 'T':
timeout = atoi(optarg);
break;
case 'B':
binmode = 1; /* do binary (default is 0) */
basefile = optarg;
break;
case 'M':
binmode = 2; /* do many binaries */
basefile = optarg;
break;
case 'N':
binmode = -1;
break;
case 'l':
loop = atoi(optarg);
break;
case 's':
show_ndata = atoi(optarg);
break;
case 'g':
plot_chno = atoi(optarg);
if (plot_chno < 1 || plot_chno > 4) {
fprintf(stderr, "Invalid channel %d\n",
plot_chno);
fald_help();
exit(1);
}
fprintf(stdout, "Plot channel %d\n", plot_chno);
break;
case 'X':
x_display = 1;
fprintf(stdout, "Gnuplot will use X display\n");
break;
case 'V':
print_version(argv[0]);
exit(0);
case 'w':
sw_trigger_enable = 1;
sw_trigger_wait = atoi(optarg);
break;
case 'h': case '?':
fald_help();
exit(1);
break;
}
}
/* Configure trigger (pick trigger polarity from external array) */
fmcadc_set_conf(&trg_cfg, FMCADC_CONF_TRG_POLARITY,
trg_cfgval[FMCADC_CONF_TRG_POLARITY]);
fmcadc_set_conf(&trg_cfg, FMCADC_CONF_TRG_SOURCE,
trg_cfgval[FMCADC_CONF_TRG_SOURCE]);
}
/**
* It applies the configuration for trigger, acquisition and channel
* @param[in] adc fmc-adc-100m device
* @param[in] trg_cfg trigger configuration status
* @param[in] acq_cfg acquisition configuration status
* @param[in] ch_cfg channel configuration status
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
static void fald_acq_apply_config(struct fmcadc_dev *adc,
struct fmcadc_conf *trg_cfg,
struct fmcadc_conf *acq_cfg,
struct fmcadc_conf *ch_cfg)
{
int err;
err = fmcadc_apply_config(adc, 0 , trg_cfg);
if (err && errno != FMCADC_ENOMASK) {
fprintf(stderr, "%s: cannot configure trigger: %s\n",
_argv[0], fmcadc_strerror(errno));
exit(1);
}
/* Configure acquisition parameter */
err = fmcadc_apply_config(adc, 0 , acq_cfg);
if (err && errno != FMCADC_ENOMASK) {
fprintf(stderr, "%s: cannot configure acquisition: %s\n",
_argv[0], fmcadc_strerror(errno));
exit(1);
}
/* Configure channel parameter */
err = fmcadc_apply_config(adc, 0 , ch_cfg);
if (err && errno != FMCADC_ENOMASK) {
fprintf(stderr, "%s: cannot configure channel0: %s\n",
_argv[0], fmcadc_strerror(errno));
exit(1);
}
// raise new_config flag
pthread_mutex_lock(&mtx);
new_config = 1;
pthread_mutex_unlock(&mtx);
}
/**
* It starts an acquisition
* @param[in] arg fmc-adc-100m device
* @param[in] called_from identifier of the parent function
* @param[in] flag flag for the fmcadc_acq_start() function
*/
static void fald_acq_start(struct fmcadc_dev *adc, char *called_from, int flag)
{
int try = 5, err;
struct timeval tv = {0, 0};
fald_print_debug("%s : call fmcadc_acq_start with %s\n",
called_from, ((flag) ? "flush" : "no flush"));
while (try) {
err = fmcadc_acq_start(adc, flag, &tv);
if (!err)
break;
/* Cannot start acquisition right now */
fprintf(stderr, "%s: cannot start acquisition: %s\n(Retry)\n",
_argv[0], fmcadc_strerror(errno));
/* Instead of leaving try another stop/start sequence */
fald_acq_stop(adc, "start_adc");
/* give a chance to breath in case the error persists */
sleep(1);
try--;
}
/*
* If also the last try fails, then set FAILURE state
* Otherwise, start polling
*/
if (!try) {
fald_print_debug("%s: Cannot start acquisition. Exit\n");
pthread_mutex_lock(&mtx);
adc_state |= ADC_STATE_FAILURE;
pthread_mutex_unlock(&mtx);
} else {
/* Start the poll */
pthread_mutex_lock(&mtx);
poll_state = START_POLL; /* adc has been flushed and started */
pthread_mutex_unlock(&mtx);
pthread_cond_signal(&readyToPollCondVar);
fald_print_debug("%s send signal to readyToPollCondVar\n", called_from);
}
}
/**
* It stops an acquisition
* @param[in] arg fmc-adc-100m device
* @param[in] called_from identifier of the parent function
*/
static void fald_acq_stop(struct fmcadc_dev *adc, char *called_from)
{
int try = 5, err;
/* stop any pending acquisition */
fald_print_debug("%s: call fmcadc_acq_stop\n", called_from);
while (try) {
err = fmcadc_acq_stop(adc, 0);
if (!err)
break;
fprintf(stderr, "%s: cannot stop acquisition: %s\n(Retry)\n",
_argv[0], fmcadc_strerror(errno));
try--;
}
/* If also the last try fails, then set FAILURE state */
if (!try) {
fald_print_debug("%s: Cannot stop acquisition. Exit\n");
pthread_mutex_lock(&mtx);
adc_state |= ADC_STATE_FAILURE;
pthread_mutex_unlock(&mtx);
}
}
static void adc_trigger_sw(struct fmcadc_dev *adc, unsigned int sdelay)
{
sleep(sdelay);
fmcadc_trigger_sw_fire(adc);
}
/**
* It waits until data is ready, then it send a signal and wait again for the
* next block of data
* @param[in] arg pointer to fmc-adc-100m device
*/
static void *adc_wait_thread(void *arg)
{
struct fmcadc_dev *adc = arg;
int err;
for (;;) {
pthread_mutex_lock(&mtx);
while (!poll_state) {
fald_print_debug("cond_wait readyToPollCondVar\n");
adc_wait_thread_ready = 1;
pthread_cond_wait(&readyToPollCondVar, &mtx);
}
poll_state = 0;
pthread_mutex_unlock(&mtx);
if (sw_trigger_enable)
adc_trigger_sw(adc, sw_trigger_wait);
fald_print_debug("It's time to call fmcadc_acq_poll\n");
err = fmcadc_acq_poll(adc, 0 , NULL);
if (err) {
if (errno == FMCADC_EDISABLED) {
fprintf(stderr, "fmcadc_acq_poll has been aborted due to a triiger stop: err:%d errno:%s(%d)\n",
err, fmcadc_strerror(errno), errno);
continue;
} else {
fprintf(stderr, "fmcadc_acq_poll failed: err:%d errno:%s(%d)\n",
err, strerror(errno), errno);
exit(-1);
}
}
fald_print_debug("fmc-adc_poll ends normally, send signal to readyToReadOrCfgCondVar requesting to read data\n");
pthread_mutex_lock(&mtx);
adc_state |= ADC_STATE_START_ACQ; /* means start acquisition */
pthread_mutex_unlock(&mtx);
// Wake up the change config thread
pthread_cond_signal(&readyToReadOrCfgCondVar);
}
}
/**
* It configures the device. It applies configurations coming from a temporary
* files. Other process may write configurations on this file.
* @param[in] arg pointer to fmc-adc-100m device
*/
static void *change_config_thread(void *arg)
{
struct fmcadc_dev *adc = arg;
int fd, ret;
char adcfifo[128];
char *s, *t;
char buf[MAX_BUF];
if (access(adcfifo, F_OK) == -1) {
sprintf(adcfifo, "/tmp/adcfifo-%04x", devid);
/* create the FIFO (named pipe) */
mkfifo(adcfifo, 0666);
}
/* open, read, and display the message from the FIFO */
fd = open(adcfifo, O_RDONLY);
for (;;) {
memset(buf, 0, MAX_BUF);
ret = read(fd, buf, MAX_BUF);
if (ret > 0) {
_argc = 1;
memcpy(buf_fifo, buf, MAX_BUF); /* for future parsing */
s = buf_fifo;
while ((t = strtok(s, " ")) != NULL) {
s = NULL;
_argv[_argc++] = t;
}
/* async way of changing trig config */
fald_acq_stop(adc, "change_config");
fald_acq_parse_args_and_configure(_argc, _argv);
fald_acq_apply_config(adc, &trg_cfg, &acq_cfg, &ch_cfg);
fprintf(stdout, "mainThread: Change trig config ................. done\n");
fald_acq_start(adc, "change_config", FMCADC_F_FLUSH) ;
} else {
fprintf(stdout, "read returns %d\n", ret);
/* writer close the fifo. Colse the reader side */
close(fd);
/* should block until the writer is back */
fd = open(adcfifo, O_RDONLY);
}
}
/* function never returns, but return NULL to avoid warning */
return NULL;
}
/**
* It creates threads for configuration and to wait data. We do not really
* need these threads but we did it on purpose in order to emulate a complex
* scenario and stress the library/driver.
* @param[in] adc fmc-adc-100m device
*/
static void create_thread(struct fmcadc_dev *adc)
{
/* Config thread */
pthread_attr_t thread_attr;
pthread_t tid;
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
int res = pthread_create(&tid, &thread_attr, change_config_thread, (void *)adc);
if (res)
fprintf(stderr, "Cannot create 'change_config_thread' (%d)\n",
res);
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
res = pthread_create(&tid, &thread_attr, adc_wait_thread, (void *)adc);
if (res)
fprintf(stderr, "Cannot create 'adc_wait_thread' (%d)\n", res);
// initialize condition variables
pthread_condattr_t condVarAttr;
pthread_condattr_init(&condVarAttr);
pthread_cond_init(&readyToPollCondVar, &condVarAttr);
pthread_condattr_destroy(&condVarAttr);
pthread_condattr_init(&condVarAttr);
pthread_cond_init(&readyToReadOrCfgCondVar, &condVarAttr);
pthread_condattr_destroy(&condVarAttr);
// initialize mutexes
pthread_mutexattr_t mtxAttr;
pthread_mutexattr_init(&mtxAttr);
pthread_mutex_init(&mtx, &mtxAttr);
pthread_mutexattr_destroy(&mtxAttr);
/* Give a chance to newly created thread to be up and running */
// sleep(1);
}
/**
* It retreive the current configuration of the library/driver
* @param[in] adc fmc-adc-100m device
* @param[out] trg_cfg trigger configuration status
* @param[out] acq_cfg acquisition configuration status
* @param[out] ch_cfg channel configuration status
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
static int fald_acq_get_configuration(struct fmcadc_dev *adc,
struct fmcadc_conf *trg_cfg,
struct fmcadc_conf *acq_cfg,
struct fmcadc_conf *ch_cfg)
{
int err;
/* Retreive trigger configuration */
memset(trg_cfg, 0, sizeof(struct fmcadc_conf));
trg_cfg->type = FMCADC_CONF_TYPE_TRG;
fmcadc_set_conf_mask(trg_cfg, FMCADC_CONF_TRG_SOURCE);
fmcadc_set_conf_mask(trg_cfg, FMCADC_CONF_TRG_SOURCE_CHAN);
fmcadc_set_conf_mask(trg_cfg, FMCADC_CONF_TRG_THRESHOLD);
fmcadc_set_conf_mask(trg_cfg, FMCADC_CONF_TRG_POLARITY);
fmcadc_set_conf_mask(trg_cfg, FMCADC_CONF_TRG_DELAY);
err = fmcadc_retrieve_config(adc, trg_cfg);
if (err) {
fprintf(stderr, "Cannot get trigger config: %s\n",
fmcadc_strerror(errno));
return -1;
}
/* Retreive acquisition configuration */
memset(acq_cfg, 0, sizeof(struct fmcadc_conf));
acq_cfg->type = FMCADC_CONF_TYPE_ACQ;
fmcadc_set_conf_mask(acq_cfg, FMCADC_CONF_ACQ_N_SHOTS);
fmcadc_set_conf_mask(acq_cfg, FMCADC_CONF_ACQ_POST_SAMP);
fmcadc_set_conf_mask(acq_cfg, FMCADC_CONF_ACQ_PRE_SAMP);
fmcadc_set_conf_mask(acq_cfg, FMCADC_CONF_ACQ_DECIMATION);
err = fmcadc_retrieve_config(adc, acq_cfg);
if (err) {
fprintf(stderr, "Cannot get acquisition config: %s\n",
fmcadc_strerror(errno));
return -1;
}
/* Retreive channel configuration */
memset(ch_cfg, 0, sizeof(struct fmcadc_conf));
ch_cfg->type = FMCADC_CONF_TYPE_CHN;
ch_cfg->route_to = 0; /* channel 0 */
fmcadc_set_conf_mask(ch_cfg, FMCADC_CONF_CHN_RANGE);
fmcadc_set_conf_mask(ch_cfg, FMCADC_CONF_CHN_TERMINATION);
fmcadc_set_conf_mask(ch_cfg, FMCADC_CONF_CHN_OFFSET);
err = fmcadc_retrieve_config(adc, ch_cfg);
if (err) {
fprintf(stderr, "Cannot get channel config: %s\n",
fmcadc_strerror(errno));
return -1;
}
return 0;
}
/**
* It prints data to stdout
* @param[in] ctrl
* @param[in] buf buffer to print
* @param[in] acq_cfg acquisition configuration associated to the buffer
*/
static void fald_acq_print_data(struct fmcadc_buffer *buf,
struct fmcadc_conf *acq_cfg,
unsigned int n)
{
struct zio_control *ctrl;
int j, ch;
int16_t *data; /* FMC-ADC-100M sample size is 14bit, 16bit for ZIO */
if (n == 0)
return;
ctrl = buf->metadata;
if (ctrl->nsamples / 4 != buf->nsamples) {
fprintf(stdout, "discrepancy between ctrl->nsamples: %d and buf->nsamples: %d\n",
ctrl->nsamples, buf->nsamples);
return;
}
data = buf->data;
/* Print data */
for (j = 0; j < ctrl->nsamples / 4; j++) {
if ( (n > 0 && j < n) ||
(n < 0 && (ctrl->nsamples / 4 - j) <= (-n)) ) {
printf("%5i ", j - acq_cfg->value[FMCADC_CONF_ACQ_PRE_SAMP]);
for (ch = 0; ch < 4; ch++)
printf("%7i", *(data++));
printf("\n");
} else {
data += 4;
}
}
}
/**
* Save data to a single file
* @param[in] buf buffer to store
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
static int fald_acq_write_single(struct fmcadc_buffer *buf)
{
struct zio_control *ctrl;
char fname[PATH_MAX];
int16_t *data; /* FMC-ADC-100M sample size is 14bit, 16bit for ZIO */
FILE *f;
int err = 0;
sprintf(fname, "%s", basefile);
f = fopen(fname, "a");
if (!f) {
fprintf(stderr, "%s: %s\n",
fname, strerror(errno));
exit(1);
}
ctrl = buf->metadata;
if (fwrite(ctrl, sizeof(struct zio_control), 1, f) != 1)
err++;
data = buf->data;
if (fwrite(data, ctrl->ssize, ctrl->nsamples, f)
!= ctrl->nsamples)
err++;
if (err) {
fprintf(stderr, "write(%s): short write\n",
basefile);
return -1;
}
return 0;
}
/**
* Sava data to different file for control and data for each shot
* @param[in] buf buffer to store
* @param[in] shot_i i-th shot acquisition
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
static int fald_acq_write_multiple(struct fmcadc_buffer *buf,
unsigned int shot_i)
{
char fname[PATH_MAX];
struct zio_control *ctrl;
uint16_t *data;
FILE *f;
sprintf(fname, "%s.%03i.ctrl", basefile, shot_i);
f = fopen(fname, "w");
if (!f) {
fprintf(stderr, "%s: %s\n",
fname, strerror(errno));
return -1;
}
ctrl = buf->metadata;
if (fwrite(ctrl, sizeof(struct zio_control), 1, f) != 1) {
fprintf(stderr, "write(%s): short write\n", fname);
return -1;
}
fclose(f);
sprintf(fname, "%s.%03i.data", basefile, shot_i);
f = fopen(fname, "w");
if (!f) {
fprintf(stderr, "%s: %s\n",
fname, strerror(errno));
return -1;
}
data = buf->data;
if (fwrite(data, ctrl->ssize, ctrl->nsamples, f)
!= ctrl->nsamples) {
fprintf(stderr, "write(%s): short write\n", fname);
return -1;
}
fclose(f);
return 0;
}
/**
* Plot data using gnuplot
* @param[in] buf buffer to plot
* @param[in] ch channel to show
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
static void fald_acq_plot_data(struct fmcadc_buffer *buf, unsigned int ch)
{
struct zio_control *ctrl = buf->metadata;
int16_t *data = buf->data;
char fname[PATH_MAX];
char cmd[256];
snprintf(fname, sizeof(fname), "/tmp/fmcadc.0x%04x.ch%d.dat", devid, ch);
if (write_file(fname, ch, data, (ctrl->nsamples)/4) < 0) {
printf("Cannot plot data. Write data into file %s failed.\n", fname);
return;
}
snprintf(cmd, sizeof(cmd), "echo \"%s plot '%s' with lines "
"\" | gnuplot -persist",
(x_display == 1 ? "set term x11; " : "set term dumb; "),
fname);
cmd[sizeof(cmd) - 1] = '\0';
system(cmd);
}
/**
* It handles a a shot. Retreive data from the driver and show data
*/
static int fald_acq_handle_shot(struct fmcadc_dev *adc,
struct fmcadc_conf *acq_cfg,
struct fmcadc_buffer *buf,
unsigned int shot_i)
{
struct zio_control *ctrl;
int err;
if (binmode < 0) /* no data must be acquired */
return -1;
err = fmcadc_fill_buffer(adc, buf, 0, NULL);
if (err) {
if (errno == FMCADC_EDISABLED) {
fprintf(stdout, "mainThread: leaves fmcadc_fill_buffer with errno=FMCADC_EDISABLED\n");
return 0;
}
fprintf(stderr, "shot %i/%i: cannot fill buffer: %s\n", shot_i + 1,
acq_cfg->value[FMCADC_CONF_ACQ_N_SHOTS],
fmcadc_strerror(errno));
return -1;
}
ctrl = buf->metadata;
/* FIXME adc-lib should provide enums to retrive
* attributes values */
fprintf(stderr, "Acquisition started at secs:%u ticks:%u\n",
ctrl->attr_channel.ext_val[FA100M14B4C_DATTR_ACQ_START_S],
ctrl->attr_channel.ext_val[FA100M14B4C_DATTR_ACQ_START_C]);
fprintf(stderr, "Read %d samples from shot %i/%i secs:%lld ticks:%lld (loop: %d)\n",
ctrl->nsamples,
shot_i + 1, acq_cfg->value[FMCADC_CONF_ACQ_N_SHOTS],
(long long)ctrl->tstamp.secs, (long long)ctrl->tstamp.ticks, loop);
/* print/store data*/
switch(binmode) {
default:
fald_acq_print_data(buf, acq_cfg, show_ndata);
break;
case 1:
err = fald_acq_write_single(buf);
break;
case 2:
err = fald_acq_write_multiple(buf, shot_i);
break;
}
if (err)
return -1;
return 0;
}
int main(int argc, char *argv[])
{
struct fmcadc_dev *adc;
struct fmcadc_buffer *buf;
int i, err;
if (argc == 1) {
fprintf(stderr, "%s: DEVICE-ID is a mandatory argument\n",
argv[0]);
fald_help();
exit(1);
}
/* parsing of arguments is done after fmcadc_open, so we have to check
* here whether we should print help */
if ((argc >= 2) && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
fald_help();
exit(1);
}
/* parsing of arguments is done after fmcadc_open, so we have to check
* here whether we should print version */
if ((argc >= 2) &&
(!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) {
print_version(argv[0]);
exit(0);
}
/* set local _argv[0] with pg name */
_argv[0] = argv[0];
/* devid is the last arg */
sscanf(argv[argc-1], "%x", &devid);
/* Open the ADC */
adc = fmcadc_open("fmc-adc-100m14b4cha", devid,
/* nshots * (presamples + postsamples) */
/*
acq.value[FMCADC_CONF_ACQ_N_SHOTS] *
( acq.value[FMCADC_CONF_ACQ_PRE_SAMP] +
acq.value[FMCADC_CONF_ACQ_POST_SAMP] )*/ 0,
/*acq.value[FMCADC_CONF_ACQ_N_SHOTS]*/ 0,
FMCADC_F_FLUSH /*0*/);
if (!adc) {
fprintf(stderr, "%s: cannot open device: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
fmcadc_trigger_sw_status(adc, &sw_trigger_enable_old);
if (sw_trigger_enable) {
fmcadc_trigger_sw_enable(adc, sw_trigger_enable);
}
/* Before parsing args : */
/* First retrieve current config in case the program */
/* is launched with a subset of options */
err = fald_acq_get_configuration(adc, &trg_cfg, &acq_cfg, &ch_cfg);
if (err) {
exit(1);
}
/* get the new given trigger and acq config */
/* Only the ones provided will override the current ones */
fald_acq_parse_args_and_configure(argc, argv);
/* fmc-adc-100m work only with ZIO framework */
if (strcmp(fmcadc_get_driver_type(adc), "zio")) {
fprintf(stderr, "%s: not a zio driver, aborting\n", argv[0]);
exit(1);
}
/* create the various thread and sync mechanism */
create_thread(adc);
while (!adc_wait_thread_ready)
nanosleep((struct timespec[]){{0, 10000}}, NULL);
fprintf(stdout, "adc_wait_thread_ready\n");
/* configure adc */
fald_acq_stop(adc, "main");
fald_acq_apply_config(adc, &trg_cfg, &acq_cfg, &ch_cfg);
/* Allocate a first buffer in the default way */
buf = fmcadc_request_buffer(adc,
acq_cfg.value[FMCADC_CONF_ACQ_PRE_SAMP] +
acq_cfg.value[FMCADC_CONF_ACQ_POST_SAMP],
NULL /* alloc */, 0);
if (!buf) {
fprintf(stderr, "Cannot allocate buffer (%s)\n",
fmcadc_strerror(errno));
exit(1);
}
fald_acq_start(adc, "main", FMCADC_F_FLUSH);
while (loop > 0) {
pthread_mutex_lock(&mtx);
while (!adc_state) {
fald_print_debug("mainThread: cond_wait readyToReadOrCfgCondVar\n");
pthread_cond_wait(&readyToReadOrCfgCondVar, &mtx);
fald_print_debug("mainThread: waked up adc_state:%d\n", adc_state);
}
fald_print_debug("mainThread: wakeup readyToReadOrCfgCondVar with adc_state: %s\n",
((adc_state==1)?"Read data":"Change trigger config"));
/* If the system fails stop the loop and close the program */
if (adc_state & ADC_STATE_FAILURE) {
pthread_mutex_unlock(&mtx);
break;
}
/* time to acquire data */
adc_state &= ~ADC_STATE_START_ACQ; /* ack time to acquire data */
if (new_config && buf != NULL) {
/* first release previous buffer */
fmcadc_release_buffer(adc, buf, NULL);
buf = NULL;
new_config = 0;
}
pthread_mutex_unlock(&mtx);
if (buf == NULL) { /* buf has been released due to a change of trig config */
/* Allocate a buffer in the default way */
buf = fmcadc_request_buffer(adc,
acq_cfg.value[FMCADC_CONF_ACQ_PRE_SAMP] +
acq_cfg.value[FMCADC_CONF_ACQ_POST_SAMP],
NULL /* alloc */, 0);
if (!buf) {
fprintf(stderr, "Cannot allocate buffer (%s)\n",
fmcadc_strerror(errno));
exit(1);
}
}
/* Fill the buffer once for each shot */
for (i = 0; i < acq_cfg.value[FMCADC_CONF_ACQ_N_SHOTS]; ++i) {
err = fald_acq_handle_shot(adc, &acq_cfg, buf, i);
if (err)
exit(1);
}
--loop;
if (loop > 0)
fald_acq_start(adc, "End of data processing", 0);
else if (plot_chno != -1) /* Plot only the last Acquisition */
fald_acq_plot_data(buf, plot_chno);
}
fmcadc_trigger_sw_enable(adc, sw_trigger_enable_old);
fmcadc_close(adc);
exit(0);
}
/*
* Copyright CERN 2014
* Author: Federico Vaga <federico.vaga@gmail.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <linux/zio-user.h>
#include <fmcadc-lib.h>
#include <fmc-adc-100m14b4cha.h>
static char git_version[] = "version: " GIT_VERSION;
static char zio_git_version[] = "zio version: " ZIO_GIT_VERSION;
/* Subtract the `struct timespec' values X and Y,
storing the result in RESULT.
Return 1 if the difference is negative, otherwise 0. */
int timespec_subtract (result, x, y)
struct timespec *result, *x, *y;
{
/* Perform the carry for the later subtraction by updating y. */
if (x->tv_nsec < y->tv_nsec) {
int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
y->tv_nsec -= 1000000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_nsec - y->tv_nsec > 1000000000) {
int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
y->tv_nsec += 1000000000 * nsec;
y->tv_sec -= nsec;
}
/* Compute the time remaining to wait.
tv_nsec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_nsec = x->tv_nsec - y->tv_nsec;
/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}
static void fald_help()
{
printf("\nfald-bad-clock [OPTIONS] <devid>\n\n");
printf(" -i <seconds> observation interval\n\n");
printf(" -h show this help\n\n");
printf(" -V show version information\n\n");
exit(1);
}
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s %s\n", pname, zio_git_version);
printf("%s\n", libfmcadc_version_s);
printf("%s\n", libfmcadc_zio_version_s);
}
int main (int argc, char *argv[])
{
struct fmcadc_dev *adc;
struct fmcadc_conf brd_cfg;
struct timespec sys_start, sys_cur, adc_cur, dlt_ts, dlt_dlt_ts = {0, 0};
int err, devid, interval = 360;
uint32_t adc_sec, adc_ticks;
char c;
/* Prepare the board timing base configuration */
memset(&brd_cfg, 0, sizeof(brd_cfg));
brd_cfg.type = FMCADC_CONT_TYPE_BRD;
while ((c = getopt(argc, argv, "i:hV")) >= 0) {
switch (c) {
case 'i':
err = sscanf(optarg, "%d", &interval);
if (err != 1)
fald_help();
break;
case '?':
case 'h':
fald_help();
break;
case 'V':
print_version(argv[0]);
exit(0);
}
}
sscanf(argv[argc-1], "%x", &devid);
adc = fmcadc_open("fmc-adc-100m14b4cha", devid, 0, 0, FMCADC_F_FLUSH);
if (!adc) {
fprintf(stderr, "%s: cannot open device: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
do {
err = clock_gettime(CLOCK_REALTIME, &sys_start);
if (err) {
fprintf(stderr, "%s: cannot get real time: %s",
argv[0], strerror(errno));
exit(1);
}
} while (sys_start.tv_nsec > 1000);
/* Configure ADC internal clock */
adc_sec = sys_start.tv_sec;
adc_ticks = sys_start.tv_nsec / FA100M14B4C_UTC_CLOCK_NS;
fmcadc_set_conf(&brd_cfg, FMCADC_CONF_UTC_TIMING_BASE_T, adc_ticks);
fmcadc_set_conf(&brd_cfg, FMCADC_CONF_UTC_TIMING_BASE_S, adc_sec);
err = fmcadc_apply_config(adc, 0 , &brd_cfg);
if (err && errno != FMCADC_ENOMASK) {
fprintf(stderr, "%s: cannot configure board %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
fprintf(stdout,
"ADC clock configured: %010li s %010li ns ( %i %ins ticks)\n",
sys_start.tv_sec, sys_start.tv_nsec,
adc_ticks, FA100M14B4C_UTC_CLOCK_NS);
/* Measure how clock diverge */
while (interval--) {
/* Get the system clock */
err = clock_gettime(CLOCK_REALTIME, &sys_cur);
if (err) {
fprintf(stderr, "%s: cannot get real time: %s",
argv[0], strerror(errno));
exit(1);
}
/* Get the ADC clock */
err = fmcadc_retrieve_config(adc, &brd_cfg);
if (err) {
fprintf(stderr, "%s: cannot get trigger config: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
fmcadc_get_conf(&brd_cfg, FMCADC_CONF_UTC_TIMING_BASE_S,
&adc_sec);
fmcadc_get_conf(&brd_cfg, FMCADC_CONF_UTC_TIMING_BASE_T,
&adc_ticks);
adc_cur.tv_sec = adc_sec;
adc_cur.tv_nsec = adc_ticks * FA100M14B4C_UTC_CLOCK_NS;
/* Get the difference between system and ADC clock */
timespec_subtract(&dlt_ts, &sys_cur, &adc_cur);
/* How bad is? */
timespec_subtract(&dlt_dlt_ts, &dlt_ts, &dlt_dlt_ts);
/* Show time stamps and delta */
printf(" sys %ld.%.9ld s\n", sys_cur.tv_sec,
sys_cur.tv_nsec);
printf(" adc %ld.%.9ld s\n", adc_cur.tv_sec,
adc_cur.tv_nsec);
printf("|dlt| %ld.%.9ld s (%ld.%.9ld s)\n",
dlt_ts.tv_sec, dlt_ts.tv_nsec,
dlt_dlt_ts.tv_sec, dlt_dlt_ts.tv_nsec);
dlt_dlt_ts = dlt_ts;
if (dlt_ts.tv_sec) {
timespec_subtract(&dlt_dlt_ts, &sys_cur, &sys_start);
printf("Clock diverged of %ld.%.9ld s in %ld.%.9ld s\n",
dlt_ts.tv_sec, dlt_ts.tv_nsec,
dlt_dlt_ts.tv_sec, dlt_dlt_ts.tv_nsec);
break;
}
printf(" sleep 1 s\n");
sleep(1);
}
exit(0);
}
/* Copyright 2013 CERN
* Author: Federico Vaga <federico.vaga@gmail.comZ
* License: GPLv2
*
* This is a simple program to configure the FMC ADC trigger. It is not bug
* aware because it is only a demo program to show you how you can handle the
* trigger.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <linux/zio-user.h>
#include <fmcadc-lib.h>
static char git_version[] = "version: " GIT_VERSION;
static char zio_git_version[] = "zio version: " ZIO_GIT_VERSION;
static void fald_help()
{
printf("\nfald-simple-acq [OPTIONS] <DEVID>\n\n");
printf(" <DEVID>: hexadecimal identifier (e.g.: \"0x200\")\n");
printf(" --before|-b <num> number of pre samples\n");
printf(" --after|-a <num> n. of post samples (default: 16)\n");
printf(" --nshots|-n <num> number of trigger shots\n");
printf(" --delay|-d <num> delay sample after trigger\n");
printf(" --under-sample|-U <num> pick 1 sample every <num>\n");
printf(" --threshold|-t <num> internal trigger threshold\n");
printf(" --channel|-c <num> channel used as trigger (0..3)\n");
printf(" --tiemout|-T <millisec> timeout for acquisition\n");
printf(" --negative-edge internal trigger is falling edge\n");
printf(" --binary|-B <file> save binary to <file>\n");
printf(" --multi-binary|-M <file> save two files per shot: "
"<file>.0000.ctrl etc\n");
printf(" --dont-read|-N config-only, use with zio-dump\n");
printf(" --version|-V print version information\n");
printf(" --help|-h show this help\n\n");
}
static int trgval[__FMCADC_CONF_LEN]; /* FIXME: this is not used */
static struct option options[] = {
{"before", required_argument, 0, 'b'},
{"after", required_argument, 0, 'a'},
{"nshots", required_argument, 0, 'n'},
{"delay", required_argument, 0, 'd'},
{"under-sample",required_argument, 0, 'u'},
{"threshold", required_argument, 0, 't'},
{"channel", required_argument, 0, 'c'},
{"timeout", required_argument, 0, 'T'},
{"negative-edge", no_argument, &trgval[FMCADC_CONF_TRG_POLARITY], 1},
/* new options, to help stress-test */
{"binary", required_argument, 0, 'B'},
{"multi-binary",required_argument, 0, 'M'},
{"dont-read", no_argument, 0, 'N'},
/* backward-compatible options */
{"pre", required_argument, 0, 'p'},
{"post", required_argument, 0, 'P'},
{"decimation", required_argument, 0, 'D'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
#define GETOPT_STRING "b:a:n:d:u:t:c:T:B:M:Np:P:D:Vh"
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s %s\n", pname, zio_git_version);
printf("%s\n", libfmcadc_version_s);
printf("%s\n", libfmcadc_zio_version_s);
}
int main(int argc, char *argv[])
{
struct fmcadc_buffer *buf;
struct fmcadc_dev *adc;
struct fmcadc_conf trg, acq;
int i, c, err, opt_index, binmode = 0;
int nshots = 1, presamples = 0, postsamples = 16;
int timeout = -1;
unsigned int dev_id = 0;
char *basefile = NULL;
char fname[PATH_MAX];
FILE *f = NULL;
if (argc == 1) {
fald_help();
exit(1);
}
/* reset attributes and provide defaults */
memset(&trg, 0, sizeof(trg));
trg.type = FMCADC_CONF_TYPE_TRG;
fmcadc_set_conf(&trg, FMCADC_CONF_TRG_SOURCE, 1); /* external */
memset(&acq, 0, sizeof(acq));
acq.type = FMCADC_CONF_TYPE_ACQ;
fmcadc_set_conf(&acq, FMCADC_CONF_ACQ_POST_SAMP, postsamples);
fmcadc_set_conf(&acq, FMCADC_CONF_ACQ_N_SHOTS, nshots);
/* Parse options */
while ((c = getopt_long(argc, argv, GETOPT_STRING,
options, &opt_index)) >=0) {
switch (c) {
case 'b': case 'p': /* before */
presamples = atoi(optarg);
fmcadc_set_conf(&acq, FMCADC_CONF_ACQ_PRE_SAMP,
presamples);
break;
case 'a': case 'P': /* after */
postsamples = atoi(optarg);
fmcadc_set_conf(&acq, FMCADC_CONF_ACQ_POST_SAMP,
postsamples);
break;
case 'n':
nshots = atoi(optarg);
fmcadc_set_conf(&acq, FMCADC_CONF_ACQ_N_SHOTS,
nshots);
break;
case 'd':
fmcadc_set_conf(&trg, FMCADC_CONF_TRG_DELAY,
atoi(optarg));
break;
case 'u': case 'D':
fmcadc_set_conf(&acq, FMCADC_CONF_ACQ_DECIMATION,
atoi(optarg));
break;
case 't':
fmcadc_set_conf(&trg, FMCADC_CONF_TRG_THRESHOLD,
atoi(optarg));
break;
case 'c':
/* set internal, and then the channel */
fmcadc_set_conf(&trg, FMCADC_CONF_TRG_SOURCE, 0);
fmcadc_set_conf(&trg, FMCADC_CONF_TRG_SOURCE_CHAN,
atoi(optarg));
break;
case 'T':
timeout = atoi(optarg);
break;
case 'B':
binmode = 1; /* do binary (default is 0) */
basefile = optarg;
break;
case 'M':
binmode = 2; /* do many binaries */
basefile = optarg;
break;
case 'N':
binmode = -1;
break;
case 'V':
print_version(argv[0]);
exit(0);
case 'h': case '?':
fald_help();
exit(1);
break;
}
}
if (optind != argc - 1) {
fprintf(stderr, "%s: DEVICE-ID is a mandatory argument\n",
argv[0]);
fald_help();
exit(1);
} else {
sscanf(argv[optind], "%x", &dev_id);
}
/* Open the ADC */
adc = fmcadc_open("fmc-adc-100m14b4cha", dev_id,
nshots * (presamples + postsamples),
nshots,
FMCADC_F_FLUSH);
if (!adc) {
fprintf(stderr, "%s: cannot open device: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
if (strcmp(fmcadc_get_driver_type(adc), "zio")) {
fprintf(stderr, "%s: not a zio driver, aborting\n", argv[0]);
exit(1);
}
/* If we save to a a file, open it now to error out soon */
if (binmode > 0) {
char *s;
s = basefile;
if (binmode == 2) {
sprintf(fname, "%s.000.ctrl", basefile);
s = fname;
}
f = fopen(s, "a");
if (!f) {
fprintf(stderr, "%s: %s: %s\n", argv[0], s,
strerror(errno));
exit(1);
}
if (binmode == 2)
fclose(f);
}
/* Configure trigger (pick trigger polarity from external array) */
fmcadc_set_conf(&trg, FMCADC_CONF_TRG_POLARITY,
trgval[FMCADC_CONF_TRG_POLARITY]);
err = fmcadc_apply_config(adc, 0 , &trg);
if (err && errno != FMCADC_ENOMASK) {
fprintf(stderr, "%s: cannot configure trigger: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
/* Configure acquisition parameter */
err = fmcadc_apply_config(adc, 0 , &acq);
if (err && errno != FMCADC_ENOMASK) {
fprintf(stderr, "%s: cannot configure acquisition: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
if (timeout < 0) {
/* Start acquisition and wait until it completes */
err = fmcadc_acq_start(adc, 0 , NULL);
} else {
/* Start acquisition and don't wait. We use acq_poll() later */
struct timeval tv = {0, 0};
err = fmcadc_acq_start(adc, 0 , &tv);
}
if (err) {
fprintf(stderr, "%s: cannot start acquisition: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
/* Now, if a timeout was specified, use the poll method */
if (timeout >= 0) {
struct timeval tv = {timeout / 1000, timeout % 1000};
err = fmcadc_acq_poll(adc, 0 , &tv);
}
if (err) {
fprintf(stderr, "%s: timeout after %i ms: %s\n", argv[0],
timeout, strerror(errno));
exit(1);
}
/* Allocate a buffer in the default way */
buf = fmcadc_request_buffer(adc, presamples + postsamples,
NULL /* alloc */, 0);
if (!buf) {
fprintf(stderr, "Cannot allocate buffer (%s)\n",
fmcadc_strerror(errno));
exit(1);
}
/* Fill the buffer once for each shot */
for (i = 0; i < acq.value[FMCADC_CONF_ACQ_N_SHOTS]; ++i) {
struct zio_control *ctrl;
int j, ch;
int16_t *data;
if (binmode < 0) /* no data must be acquired */
break;
err = fmcadc_fill_buffer(adc, buf, 0, NULL);
if (err) {
fprintf(stderr, "%s: shot %i/%i: cannot fill buffer:"
" %s\n", argv[0], i + i,
acq.value[FMCADC_CONF_ACQ_N_SHOTS],
fmcadc_strerror(errno));
exit(1);
}
ctrl = buf->metadata;
data = buf->data;
fprintf(stderr, "Read %d samples from shot %i/%i\n",
ctrl->nsamples,
i + 1, acq.value[FMCADC_CONF_ACQ_N_SHOTS]);
if (binmode == 1) { /* append everything to a single file */
if (fwrite(ctrl, sizeof(*ctrl), 1, f) != 1)
err++;
if (fwrite(data, ctrl->ssize, ctrl->nsamples, f)
!= ctrl->nsamples)
err++;
if (err) {
fprintf(stderr, "%s: write(%s): short write\n",
argv[0], basefile);
exit(1);
}
continue; /* next shot please */
}
if (binmode == 2) { /* several files */
sprintf(fname, "%s.%03i.ctrl", basefile, i);
f = fopen(fname, "w");
if (!f) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], fname, strerror(errno));
exit(1);
}
if (fwrite(ctrl, sizeof(*ctrl), 1, f) != 1) {
fprintf(stderr, "%s: write(%s): short write\n",
argv[0], fname);
exit(1);
}
fclose(f);
sprintf(fname, "%s.%03i.data", basefile, i);
f = fopen(fname, "w");
if (!f) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], fname, strerror(errno));
exit(1);
}
if (fwrite(data, ctrl->ssize, ctrl->nsamples, f)
!= ctrl->nsamples) {
fprintf(stderr, "%s: write(%s): short write\n",
argv[0], fname);
exit(1);
}
fclose(f);
continue;
}
/*
* Finally, binmode = 0.
* We lazily know samplesize is 2 bytes and chcount is 4
*/
for (j = 0; j < ctrl->nsamples / 4; j++) {
printf("%5i ", j - presamples);
for (ch = 0; ch < 4; ch++)
printf("%7i", *(data++));
printf("\n");
}
}
if (binmode == 1)
fclose(f);
fmcadc_release_buffer(adc, buf, NULL);
fmcadc_close(adc);
exit(0);
}
/* Copyright 2013 CERN
* Author: Federico Vaga <federico.vaga@gmail.comZ
* License: GPLv2
*
* This is a simple program to configure the FMC ADC trigger. It is not bug
* aware because it is only a demo program to show you how you can handle the
* trigger.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/zio-user.h>
#include <fmcadc-lib.h>
static char git_version[] = "version: " GIT_VERSION;
static char zio_git_version[] = "zio version: " ZIO_GIT_VERSION;
static void fald_help()
{
printf("\nfald-simple-get-conf [OPTIONS] 0x<DEVICE ID>\n\n");
printf(" <DEVICE>: hexadecimal string which represent the device "
"identificator of an fmc-adc\n");
printf(" --version|-V: show version information\n");
printf(" --help|-h: show this help\n\n");
}
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s %s\n", pname, zio_git_version);
printf("%s\n", libfmcadc_version_s);
printf("%s\n", libfmcadc_zio_version_s);
}
int main(int argc, char *argv[])
{
struct fmcadc_dev *adc;
struct fmcadc_conf trg, acq, brd, chn;
static struct option options[] = {
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
int opt_index = 0, err = 0, i;
unsigned int dev_id = 0;
char c;
if (argc == 1) {
fald_help();
exit(1);
}
/* reset attribute's mask */
trg.mask = 0;
acq.mask = 0;
/* Parse options */
while((c = getopt_long(argc, argv, "hV", options, &opt_index)) >= 0) {
switch (c) {
case 'V':
print_version(argv[0]);
exit(0);
case 'h':
fald_help();
exit(1);
break;
}
}
if (optind != argc - 1) {
fprintf(stderr, "%s: DEVICE-ID is a mandatory argument\n",
argv[0]);
fald_help();
exit(1);
} else {
sscanf(argv[optind], "0x%x", &dev_id);
}
printf("Open ADC fmc-adc-100m14b4cha dev_id 0x%04x ...\n", dev_id);
/* Open the ADC */
adc = fmcadc_open("fmc-adc-100m14b4cha", dev_id,
/* no buffers expexted */ 0, 0,
/* no flush either */ 0);
if (!adc) {
fprintf(stderr, "%s: cannot open device: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
printf("Get Trigger Configuration ...\n");
/* Configure Trigger parameter to retrieve */
trg.type = FMCADC_CONF_TYPE_TRG;
fmcadc_set_conf_mask(&trg, FMCADC_CONF_TRG_SOURCE);
fmcadc_set_conf_mask(&trg, FMCADC_CONF_TRG_SOURCE_CHAN);
fmcadc_set_conf_mask(&trg, FMCADC_CONF_TRG_THRESHOLD);
fmcadc_set_conf_mask(&trg, FMCADC_CONF_TRG_POLARITY);
fmcadc_set_conf_mask(&trg, FMCADC_CONF_TRG_DELAY);
err = fmcadc_retrieve_config(adc, &trg);
if (err) {
fprintf(stderr, "%s: cannot get trigger config: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
printf(" source: %s\n",
trg.value[FMCADC_CONF_TRG_SOURCE] ? "external" : "internal");
printf(" channel: %d\n", trg.value[FMCADC_CONF_TRG_SOURCE_CHAN]);
printf(" threshold: %d\n", trg.value[FMCADC_CONF_TRG_THRESHOLD]);
printf(" polarity: %d\n", trg.value[FMCADC_CONF_TRG_POLARITY]);
printf(" delay: %d\n", trg.value[FMCADC_CONF_TRG_DELAY]);
printf("Get Acquisition Configuration ...\n");
/* Configure acquisition parameter */
acq.type = FMCADC_CONF_TYPE_ACQ;
fmcadc_set_conf_mask(&acq, FMCADC_CONF_ACQ_N_SHOTS);
fmcadc_set_conf_mask(&acq, FMCADC_CONF_ACQ_POST_SAMP);
fmcadc_set_conf_mask(&acq, FMCADC_CONF_ACQ_PRE_SAMP);
fmcadc_set_conf_mask(&acq, FMCADC_CONF_ACQ_DECIMATION);
fmcadc_set_conf_mask(&acq, FMCADC_CONF_ACQ_FREQ_HZ);
fmcadc_set_conf_mask(&acq, FMCADC_CONF_ACQ_N_BITS);
err = fmcadc_retrieve_config(adc, &acq);
if (err) {
fprintf(stderr, "%s: cannot get acquisition config: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
printf(" n-shots: %d\n", acq.value[FMCADC_CONF_ACQ_N_SHOTS]);
printf(" post-sample: %d\n", acq.value[FMCADC_CONF_ACQ_POST_SAMP]);
printf(" pre-sample: %d\n", acq.value[FMCADC_CONF_ACQ_PRE_SAMP]);
printf(" decimation: %d\n", acq.value[FMCADC_CONF_ACQ_DECIMATION]);
printf(" frequency: %dHz\n", acq.value[FMCADC_CONF_ACQ_FREQ_HZ]);
printf(" n-bits: %d\n", acq.value[FMCADC_CONF_ACQ_N_BITS]);
printf("Get Board Configuration ...\n");
/* Configure acquisition parameter */
brd.type = FMCADC_CONT_TYPE_BRD;
fmcadc_set_conf_mask(&brd, FMCADC_CONF_BRD_STATE_MACHINE_STATUS);
fmcadc_set_conf_mask(&brd, FMCADC_CONF_BRD_N_CHAN);
err = fmcadc_retrieve_config(adc, &brd);
if (err) {
fprintf(stderr, "%s: cannot get board config: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
printf(" n-chan: %d\n", brd.value[FMCADC_CONF_BRD_N_CHAN]);
printf(" State Machine: %d\n",
brd.value[FMCADC_CONF_BRD_STATE_MACHINE_STATUS]);
for (i = 0; i < brd.value[FMCADC_CONF_BRD_N_CHAN]; ++i) {
printf("Get Channel %d Configuration ...\n", i);
/* Configure acquisition parameter */
chn.type = FMCADC_CONF_TYPE_CHN;
chn.route_to = i;
fmcadc_set_conf_mask(&chn, FMCADC_CONF_CHN_RANGE);
fmcadc_set_conf_mask(&chn, FMCADC_CONF_CHN_TERMINATION);
fmcadc_set_conf_mask(&chn, FMCADC_CONF_CHN_OFFSET);
err = fmcadc_retrieve_config(adc, &chn);
if (err) {
fprintf(stderr, "%s: cannot get channel config: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
printf(" range: %d\n", chn.value[FMCADC_CONF_CHN_RANGE]);
printf(" 50Ohm Termination: %s\n",
chn.value[FMCADC_CONF_CHN_TERMINATION] ? "yes" : "no");
printf(" offset: %d\n", chn.value[FMCADC_CONF_CHN_OFFSET]);
}
fmcadc_close(adc);
exit(0);
}
/* Copyright 2013 CERN
* Author: Federico Vaga <federico.vaga@gmail.com>
* License: GPLv2
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <linux/zio-user.h>
#include <fmcadc-lib.h>
/* Global configuration*/
#define N_CHAN 4
#define CARD_NAME "fmc-adc-100m14b4cha"
static char git_version[] = "version: " GIT_VERSION;
static char zio_git_version[] = "zio version: " ZIO_GIT_VERSION;
unsigned nshots = 1;
unsigned presamples = 10;
unsigned postsamples = 10;
int print_data = 1;
void print_buffer_content(struct fmcadc_buffer *buf);
int read_with_one_buffer(struct fmcadc_dev *dev);
int read_with_n_buffer(struct fmcadc_dev *dev);
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s %s\n", pname, zio_git_version);
printf("%s\n", libfmcadc_version_s);
printf("%s\n", libfmcadc_zio_version_s);
}
int main(int argc, char *argv[])
{
unsigned long totalsamples = nshots * (presamples + postsamples);
unsigned int dev_id, n_buffers = nshots;
struct fmcadc_conf acq, trg;
struct fmcadc_dev *dev;
int test = 0, err;
if ((argc >= 2) && (!strcmp(argv[1], "-V"))) {
print_version(argv[0]);
exit(0);
}
if (argc != 3) {
fprintf(stderr, "%s: Use \"%s [-V] <dev_id> <testnr>\n",
argv[0], argv[0]);
exit(1);
}
sscanf(argv[1], "%x", &dev_id);
sscanf(argv[2], "%i", &test);
/* Change parameters from environment */
if (getenv("FALD_TEST_NSHOTS"))
nshots = atoi(getenv("FALD_TEST_NSHOTS"));
if (getenv("FALD_TEST_PRE_S"))
presamples = atoi(getenv("FALD_TEST_PRE_S"));
if (getenv("FALD_TEST_POST_S"))
postsamples = atoi(getenv("FALD_TEST_POST_S"));
if (getenv("FALD_TEST_NOPRINT"))
print_data = 0;
fmcadc_init();
dev = fmcadc_open(CARD_NAME, dev_id, totalsamples, n_buffers,
FMCADC_F_FLUSH);
if (!dev) {
fprintf(stderr, "%s: fmcadc_open(%s, 0x%x): %s\n", argv[0],
CARD_NAME, dev_id, strerror(errno));
exit(1);
}
if (strcmp(fmcadc_get_driver_type(dev), "zio")) {
fprintf(stderr, "%s: not a zio driver, aborting\n", argv[0]);
exit(1);
}
if (0) { /* We can't change buffer, because chardevs are open */
err = fmcadc_set_param(dev, "cset0/current_buffer", argv[3], 0);
if (err) {
fprintf(stderr, "%s: cannot set '%s' as buffer: %s\n",
argv[0], argv[3], fmcadc_strerror(errno));
exit(1);
}
}
/* FIXME: use nshots to set cset0/chani/buffer/max-buffer-len */
/* FIXME: use maxsize to set cset0/chani/buffer/max-buffer-kb */
/* configure acquisition parameters */
memset(&acq, 0, sizeof(acq));
acq.type = FMCADC_CONF_TYPE_ACQ;
fmcadc_set_conf(&acq, FMCADC_CONF_ACQ_N_SHOTS, nshots);
fmcadc_set_conf(&acq, FMCADC_CONF_ACQ_PRE_SAMP, presamples);
fmcadc_set_conf(&acq, FMCADC_CONF_ACQ_POST_SAMP, postsamples);
err = fmcadc_apply_config(dev, 0, &acq);
if (err) {
fprintf(stderr, "%s: apply_config(acq): %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
/* configure trigger parameters */
memset(&trg, 0, sizeof(trg));
trg.type = FMCADC_CONF_TYPE_TRG;
fmcadc_set_conf(&trg, FMCADC_CONF_TRG_SOURCE, 1); /* external */
err = fmcadc_apply_config(dev, 0, &trg);
if (err) {
fprintf(stderr, "%s: apply_config(trigger): %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
/* Start the acquisition */
err = fmcadc_acq_start(dev, 0 , NULL);
if (err) {
fprintf(stderr, "%s: cannot start acquisition: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
switch (test) {
case 0:
err = read_with_one_buffer(dev);
break;
case 1:
err = read_with_n_buffer(dev);
break;
}
if (err) {
fprintf(stderr, "%s: problem with read buffer: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
/* Stop acquisition, close device and exit from library */
fmcadc_acq_stop(dev, 0);
fmcadc_close(dev);
fmcadc_exit();
exit(0);
}
/* Read all shots with a single buffer and then release it */
int read_with_one_buffer(struct fmcadc_dev *dev)
{
struct fmcadc_buffer *buf;
int err = 0, i;
buf = fmcadc_request_buffer(dev, presamples + postsamples, NULL, 0);
for (i = 0; i < nshots; ++i) {
err = fmcadc_fill_buffer(dev, buf, 0, NULL);
if (err)
break;
print_buffer_content(buf);
}
fmcadc_release_buffer(dev, buf, NULL);
return err;
}
/* Read all shots with a multiple buffer and then release them
* request, fill and release are separated in different loop to show that
* are not strictly consecutive operations
*/
int read_with_n_buffer(struct fmcadc_dev *dev)
{
struct fmcadc_buffer *buf[nshots] ;
int err = 0, i;
/* Allocate all buffers before the use */
for (i = 0; i < nshots; ++i)
buf[i] = fmcadc_request_buffer(dev,
presamples + postsamples, NULL, 0);
/* Fill all buffers */
for (i = 0; i < nshots; ++i) {
err = fmcadc_fill_buffer(dev, buf[i], 0, NULL);
if (err)
break;
print_buffer_content(buf[i]);
}
/* Release all buffers */
for (i = 0; i < nshots; ++i)
fmcadc_release_buffer(dev, buf[i], NULL);
return err;
}
void print_buffer_content(struct fmcadc_buffer *buf)
{
int16_t *data = buf->data; /* get data */
struct fmcadc_timestamp *ts;
int i, ch;
ts = fmcadc_tstamp_buffer(buf, NULL);
printf("timestamp %lli:%lli:%lli\n",
(long long)ts->secs,
(long long)ts->ticks,
(long long)ts->bins);
if (!print_data)
return;
for (i = 0; i < presamples + postsamples; i++) {
printf("%5i ", i - presamples);
for (ch = 0; ch < N_CHAN; ch++)
printf("%7i", *(data++));
printf("\n");
}
}
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define FALD_TRG_ARGC 2
static char git_version[] = "version: " GIT_VERSION;
static char zio_git_version[] = "zio version: " ZIO_GIT_VERSION;
void send_config(int fd, char *msg)
{
/* removing newline at the end */
if (msg[strlen(msg)-1] == '\n')
msg[strlen(msg)-1] = '\0';
if (strlen(msg)) {
write(fd, msg, strlen(msg));
fprintf(stdout, "New trig setting sent: %s(len: %d)\n",
msg, (int)strlen(msg));
} else {
fprintf(stdout, "Nothing sent due to an empty user input\n");
}
}
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s %s\n", pname, zio_git_version);
}
int main(int argc, char *argv[])
{
int i, fd;
char adcfifo[128];
char msg[512], *ptr;
unsigned int devid;
if ((argc >= 2) && (!strcmp(argv[1], "-V"))) {
print_version(argv[0]);
exit(0);
}
if (argc < FALD_TRG_ARGC) {
fprintf(stderr, "\nUsage:\nfald-trg-cfg [-V] <dev_id> [options]\n");
return -1;
}
sscanf(argv[FALD_TRG_ARGC - 1], "%x", &devid);
if (access(adcfifo, F_OK) == -1) {
sprintf(adcfifo, "/tmp/adcfifo-%04x", devid);
/* create the FIFO (named pipe) */
mkfifo(adcfifo, 0666);
}
fd = open(adcfifo, O_WRONLY);
if (fd == -1) {
fprintf(stdout, "open %s failed errno:%d\n", adcfifo, errno);
exit(1);
}
/*
* If we have parameters from the command line, then send them
* immediately and close the program. This allow external program to
* invoke this one for the configuration instead of interactive input
*/
if (argc > FALD_TRG_ARGC) {
memset(msg, 0, 512);
for (i = 2; i < argc; ++i) {
strcat(msg, argv[i]);
strcat(msg, " ");
}
send_config(fd, msg);
close(fd);
return 0;
}
/* get user input */
while (1) {
memset(msg, 0, 512);
fprintf(stdout, "Change trig config using standard args: -a -b -c -n -e\n >>>: ");
ptr = fgets(msg, sizeof(msg), stdin);
if (!ptr) {
fprintf(stderr, "Error while reading options\n");
break;
}
send_config(fd, msg);
}
close(fd);
/* don't remove the FIFO to not break the reader side */
//unlink(adcfifo);
return 0;
}
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