Commit 16e6a7bc authored by Jorge Machado's avatar Jorge Machado

Merge branch 'dio_extension' of https://ohwr.org/project/fmc-dio-6chttla into dio_extension

parents 11cd4f6f 0c2eba80
......@@ -53,3 +53,4 @@ modules.order
# Project Specifi #
###################
wr-dio.mod*
irq-demo
\ No newline at end of file
This diff is collapsed.
......@@ -3,6 +3,7 @@ files = ["wr_dio_wb.vhd",
"wr_dio.vhd",
"wr_dio_pkg.vhd",
"pulse_gen_pl.vhd",
"immed_pulse_counter.vhd",
"dummy_time.vhd" ]
"immed_pulse_counter.vhd",
"dummy_time.vhd",
"imm_pulse_train_gen.vhd" ]
......@@ -15,6 +15,8 @@ export FMC_BUS_ABS
DIRS = $(FMC_BUS_ABS) kernel tools
CFLAGS += $(WR_DIO_CFLAGS)
.PHONY: all clean modules install modules_install $(DIRS)
all clean modules install modules_install: $(DIRS)
......
CFLAGS += -I./dep
irq-demo: irq-demo.c ./dep/*.c
gcc -o irq-demo irq-demo.c ./dep/*.c $(CFLAGS) -lm
clean:
-rm irq-demo
-rm .irq-demo.log
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FILE_LOG_PRIVATE_H__
#define __FILE_LOG_PRIVATE_H__
struct file_log_private {
FILE *fp;
char *path;
};
static int check_file_log_priv(log_device dev);
static struct file_log_private * get_private_info(log_device dev);
static void init_file_log_device(log_device dev);
static void send_to_file_log_device(log_device, const char *msg);
static void deinit_file_log_device(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include "log-device.h"
#include "file-log-private.h"
static struct log_device_iface _file_log_iface =
{
.init_log_device = init_file_log_device,
.send_to_log_device = send_to_file_log_device,
.clear_log_device = NULL,
.deinit_log_device = deinit_file_log_device,
};
static const log_device_interface file_log_iface = &_file_log_iface;
log_device create_file_log_device(const char *path)
{
return create_log_device((void *)path, file_log_iface);
}
static void init_file_log_device(log_device dev)
{
struct file_log_private *priv;
priv = calloc(1, sizeof(*priv));
priv->path = dev->private;
priv->fp = fopen(priv->path, "w+");
dev->private = priv;
}
static void send_to_file_log_device(log_device dev, const char *msg)
{
struct file_log_private *priv;
if(!check_file_log_priv(dev)) {
priv = get_private_info(dev);
fputs(msg, priv->fp);
fputs("\n", priv->fp);
}
}
static void deinit_file_log_device(log_device dev)
{
struct file_log_private *priv;
if(dev->private) {
priv = get_private_info(dev);
fclose(priv->fp);
free(dev->private);
}
}
static int check_file_log_priv(log_device dev)
{
return (dev->private != NULL) ? 0 : 1;
}
static struct file_log_private * get_private_info(log_device dev)
{
return (struct file_log_private *)dev->private;
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FILE_LOG_H__
#define __FILE_LOG_H__
log_device create_file_log_device(const char *file);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FMC_DIO_DEVICE_PRIVATE_H__
#define __FMC_DIO_DEVICE_PRIVATE_H__
#include "../../kernel/fmc-dio.h"
#define MAX_TMP_BUF 1024
#define FMC_DIO_N_CH 5
#define NS_IN_A_SEC 1000000000
struct fmc_dio_dev {
char *dev_name;
int fd;
log_device *logs;
unsigned int n_logs;
int enabled_log;
unsigned int total_n_ts;
unsigned int partial_n_ts;
struct wr_dio_cmd cmd;
};
static const fmc_dio_device BAD_FMC_DEVICE = NULL;
static int check_fmc_dio_device(fmc_dio_device dev);
static int enable_fmc_dio_device_hw_irq(fmc_dio_device dev,
int ch, int en);
static int setup_fmc_dio_device_hw_irq(fmc_dio_device dev,
unsigned long period,
long count);
static int get_hw_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts);
static int get_kernel_leaps_info(fmc_dio_device dev);
static void log_msg(fmc_dio_device dev, const char *msg);
static void LOG(fmc_dio_device dev, const char *fmt, ...);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/timex.h>
#include <sys/ioctl.h>
#include "fmc-dio-device.h"
#include "fmc-dio-device-private.h"
fmc_dio_device create_fmc_dio_device(char *name)
{
fmc_dio_device dev = calloc(1, sizeof(*dev));
if(!dev)
return BAD_FMC_DEVICE;
dev->dev_name = name;
return dev;
}
static int check_fmc_dio_device(fmc_dio_device dev)
{
if(dev != BAD_FMC_DEVICE) {
return 0;
}
else {
return 1;
}
}
int open_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
dev->fd = open(dev->dev_name, O_RDWR);
if(dev->fd < 0) {
free(dev);
return -ENODEV;
}
if(ioctl(dev->fd, PRIV_MEZZANINE_ID, (unsigned long) dev->dev_name) < 0 &&
errno != EAGAIN) {
free(dev);
return -EFAULT;
}
return 0;
}
void attach_log_devices_to_fmc_dio_device(fmc_dio_device dev,
log_device *log_devs,
unsigned int n_log_devs)
{
if(check_fmc_dio_device(dev) || !log_devs || n_log_devs == 0)
return;
dev->logs = log_devs;
dev->n_logs = n_log_devs;
}
int enable_log_for_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
dev->enabled_log = 1;
return 0;
}
int disable_log_for_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
dev->enabled_log = 0;
return 0;
}
void close_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return;
close(dev->fd);
free(dev);
}
int enable_fmc_dio_device_irq(fmc_dio_device dev, int ch)
{
int ret;
if(check_fmc_dio_device(dev)) {
return -EINVAL;
}
ret = enable_fmc_dio_device_hw_irq(dev, ch, 1);
return ret;
}
int enable_fmc_dio_device_all_irq(fmc_dio_device dev)
{
int ret = 0;
for(int i = 0 ; i <= FMC_DIO_N_CH ; i++) {
ret = enable_fmc_dio_device_irq(dev, i);
if(ret)
break;
}
return ret;
}
int disable_fmc_dio_device_irq(fmc_dio_device dev, int ch)
{
int ret;
if(check_fmc_dio_device(dev)) {
return -EINVAL;
}
ret = enable_fmc_dio_device_hw_irq(dev, ch, 0);
return ret;
}
int disable_fmc_dio_device_all_irq(fmc_dio_device dev)
{
int ret = 0;
for(int i = 0 ; i <= FMC_DIO_N_CH ; i++) {
ret = disable_fmc_dio_device_irq(dev, i);
if(ret)
break;
}
return ret;
}
static int enable_fmc_dio_device_hw_irq(fmc_dio_device dev,
int ch, int en)
{
if(ch < 0 || ch > FMC_DIO_N_CH) {
return -EINVAL;
}
struct wr_dio_cmd *c = &dev->cmd;
en = (en) ? 1 : 0;
c->command = WR_DIO_CMD_MASK_IRQ;
c->flags = WR_DIO_F_MASK;
c->channel = 1 << ch;
c->value = (en) ? WR_DIO_F_MASK_ENABLE_IRQ :
WR_DIO_F_MASK_DISABLE_IRQ;
if(ioctl(dev->fd, PRIV_MEZZANINE_CMD, c) < 0)
return -EFAULT;
return 0;
}
int setup_fmc_dio_device_irq(fmc_dio_device dev,
unsigned long period,
long count)
{
int ret;
if(check_fmc_dio_device(dev))
return -EINVAL;
ret = setup_fmc_dio_device_hw_irq(dev, period, count);
return ret;
}
static int setup_fmc_dio_device_hw_irq(fmc_dio_device dev,
unsigned long period,
long count)
{
struct wr_dio_cmd *c = &dev->cmd;
int ret;
c->command = WR_DIO_CMD_IRQ;
c->flags = 0x0;
c->flags |= WR_DIO_F_LOOP;
c->flags |= WR_DIO_F_NOW;
c->t[1].tv_nsec = period % NS_IN_A_SEC;
c->t[1].tv_sec = period / NS_IN_A_SEC;
c->value= count;
ret = ioctl(dev->fd, PRIV_MEZZANINE_CMD, c);
if(ret < 0) {
return -EFAULT;
}
return 0;
}
int get_tai_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
return get_hw_ts_from_fmc_dio_device(dev, ch, ts, nts);
}
int get_utc_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts)
{
int ret;
int tai;
ret = get_tai_ts_from_fmc_dio_device(dev, ch, ts, nts);
if(ret)
return ret;
tai = get_kernel_leaps_info(dev);
for(int i = 0 ; i < *nts ; i++)
(*ts)[i].tv_sec -= tai;
return ret;
}
static int get_hw_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts)
{
struct wr_dio_cmd *c = &dev->cmd;
int ret;
c->command = WR_DIO_CMD_STAMP;
c->flags = 0;
c->channel = ch;
ret = ioctl(dev->fd, PRIV_MEZZANINE_CMD, (unsigned long) c);
if(ret < 0) {
return -EFAULT;
}
if(c->nstamp <= 0) {
return -EAGAIN;
}
*nts = c->nstamp;
*ts = calloc(c->nstamp, sizeof(struct timespec));
if(!*ts)
return -ENOMEM;
for(int i = 0 ; i < c->nstamp ; i++) {
(*ts)[i] = c->t[i];
}
dev->total_n_ts += c->nstamp;
dev->partial_n_ts += c->nstamp;
return 0;
}
static int get_kernel_leaps_info(fmc_dio_device dev)
{
struct timex tx = {0};
if (adjtimex(&tx) < 0) {
return -EFAULT;
}
return tx.tai;
}
unsigned int get_total_n_timestamps(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return 0;
return dev->total_n_ts;
}
unsigned int get_partial_n_timestamps(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return 0;
return dev->partial_n_ts;
}
void reset_partial_n_timestamps(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return;
dev->partial_n_ts = 0;
}
static void log_msg(fmc_dio_device dev, const char *msg)
{
if(!dev->logs || dev->n_logs == 0)
return;
if(!dev->enabled_log)
return;
for(int i = 0 ; i < dev->n_logs ; i++)
send_to_log_device(dev->logs[i], msg);
}
static void LOG(fmc_dio_device dev, const char *fmt, ...)
{
va_list ap;
char buffer[MAX_TMP_BUF] = {0};
va_start(ap, fmt);
vsnprintf(buffer, MAX_TMP_BUF-1, fmt, ap);
va_end(ap);
log_msg(dev, buffer);
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FMC_DIO_DEVICE_H__
#define __FMC_DIO_DEVICE_H__
#include <time.h>
#include "log-device.h"
typedef struct fmc_dio_dev * fmc_dio_device;
fmc_dio_device create_fmc_dio_device(char *name);
int open_fmc_dio_device(fmc_dio_device dev);
void close_fmc_dio_device(fmc_dio_device dev);
void attach_log_devices_to_fmc_dio_device(fmc_dio_device dev,
log_device *log_devs,
unsigned int n_log_devs);
int enable_log_for_fmc_dio_device(fmc_dio_device dev);
int disable_log_for_fmc_dio_device(fmc_dio_device dev);
int enable_fmc_dio_device_irq(fmc_dio_device dev, int ch);
int enable_fmc_dio_device_all_irq(fmc_dio_device dev);
int disable_fmc_dio_device_irq(fmc_dio_device dev, int ch);
int disable_fmc_dio_device_all_irq(fmc_dio_device dev);
int setup_fmc_dio_device_irq(fmc_dio_device dev,
unsigned long period,
long count);
int get_tai_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts);
int get_utc_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts);
unsigned int get_total_n_timestamps(fmc_dio_device dev);
unsigned int get_partial_n_timestamps(fmc_dio_device dev);
void reset_partial_n_timestamps(fmc_dio_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __LOG_DEVICE_PRIVATE_H__
#define __LOG_DEVICE_PRIVATE_H__
static const log_device BAD_LOG_DEVICE = NULL;
static int check_log_device(log_device dev);
static int check_log_device_interface(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdlib.h>
#include "log-device.h"
#include "log-device-private.h"
log_device create_log_device(void *args, log_device_interface interface)
{
log_device dev = calloc(1, sizeof(struct log_dev));
if(dev != BAD_LOG_DEVICE && interface != NULL) {
dev->private = args;
dev->ops = interface;
if(dev->ops->init_log_device)
dev->ops->init_log_device(dev);
}
return dev;
}
void send_to_log_device(log_device dev, const char *msg)
{
if(check_log_device_interface(dev))
return;
dev->ops->send_to_log_device(dev, msg);
}
void clear_log_device(log_device dev)
{
if(check_log_device_interface(dev))
return;
if(dev->ops->clear_log_device)
dev->ops->clear_log_device(dev);
}
void destroy_log_device(log_device dev)
{
if(check_log_device_interface(dev))
return;
if(dev->ops->deinit_log_device)
dev->ops->deinit_log_device(dev);
free(dev);
}
static int check_log_device(log_device dev)
{
return (dev == BAD_LOG_DEVICE) ? 1 : 0;
}
static int check_log_device_interface(log_device dev)
{
if(check_log_device(dev))
return 1;
if(!dev->ops)
return 1;
else
return 0;
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __LOG_DEVICE_H__
#define __LOG_DEVICE_H__
typedef struct log_device_iface * log_device_interface;
struct log_dev {
log_device_interface ops;
void *private;
};
typedef struct log_dev * log_device;
struct log_device_iface {
void (*init_log_device)(log_device dev);
void (*send_to_log_device)(log_device dev, const char *msg);
void (*deinit_log_device)(log_device dev);
void (*clear_log_device)(log_device dev);
};
log_device create_log_device(void *args, log_device_interface interface);
void send_to_log_device(log_device dev, const char *msg);
void clear_log_device(log_device dev);
void destroy_log_device(log_device dev);
#endif