Commit 974102de authored by Federico Vaga's avatar Federico Vaga

lib: remove library (is going to be a sub-module)

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 2e0da081
.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
ZIO ?= ../zio
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 -I../kernel -I$(ZIO)/include $(EXTRACFLAGS)
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 = (void *)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;
}
This diff is collapsed.
/*
* 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
extern "C" {
#endif
#include <stdint.h>
#include <stdlib.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_CONT_TYPE_BRD, /* Board */
__FMCADC_CONF_TYPE_LAST_INDEX,
};
#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);
#ifdef __cplusplus
}
#endif
#endif /* FMCADC_LIB_H_ */
/*
* Copyright CERN 2013, GNU GPL 2 or later.
* Author: Alessandro Rubini
*/
#include "fmcadc-lib.h"
/* 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 = (void *)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 = (void *)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 = (void *)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 = (void *)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 = (void *)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 = (void *)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 = (void *)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 = (void *)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 = (void *)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 = (void *)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 = (void *)dev;
const struct fmcadc_board_type *b = g->board;
if (!buf)
return 0;
return b->fa_op->release_buffer(dev, buf, free);
}
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