Commit 38edf888 authored by Jorge Machado's avatar Jorge Machado

Add irq-demo to the sw directory of the fmc repo

parent 21a37068
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
/*
* 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 __PRINTF_LOG_PRIVATE_H__
#define __PRINTF_LOG_PRIVATE_H__
static void send_to_printf_log_device(log_device dev, const char *msg);
static void clear_printf_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 <stddef.h>
#include <stdio.h>
#include "log-device.h"
#include "printf-log-private.h"
static struct log_device_iface _printf_log_iface =
{
.init_log_device = NULL,
.send_to_log_device = send_to_printf_log_device,
.deinit_log_device = NULL,
.clear_log_device = clear_printf_log_device,
};
static const log_device_interface printf_log_iface = &_printf_log_iface;
static void send_to_printf_log_device(log_device dev, const char *msg)
{
printf("%s\n", msg);
}
static void clear_printf_log_device(log_device dev)
{
printf("\e[1;1H\e[2J");
}
log_device create_printf_log_device(void)
{
return create_log_device(NULL, printf_log_iface);
}
/*
* 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 __PRINTF_LOG_H__
#define __PRINTF_LOG_H__
#include "log-device.h"
log_device create_printf_log_device(void);
void clear_screen(log_device device);
#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 __STATS_ENGINE_PRIVATE_H__
#define __STATS_ENGINE_PRIVATE_H__
#define MAX_TS 1000
#define NS_IN_A_SEC 1000000000
#define MAX_TMP_BUF 1024
struct ts_stats {
double mean;
double std;
unsigned int ts_per_second;
unsigned int ts_total;
};
struct _stats_engine {
struct timespec usr_ts[MAX_TS];
struct timespec sys_ts[MAX_TS];
double diff_ts[MAX_TS];
struct ts_stats stats;
unsigned int n_ts;
unsigned int current_ts;
unsigned int next_ts;
log_device *logs;
unsigned int n_logs;
int enabled_log;
};
const stats_engine BAD_STATS_ENGINE = NULL;
static void update_n_ts_stats_engine(stats_engine engine);
static void update_index_stats_engine(unsigned int *index);
static void log_stats_engine(stats_engine engine, int verbose);
static int check_log_configuration(stats_engine engine);
static void log_msg(stats_engine engine,
const char *msg);
static void log_clear(stats_engine engine);
static void LOG(stats_engine engine, const char *fmt, ...);
static int timespec_subtract(struct timespec *result,
struct timespec *x,
struct timespec *y);
static double compute_mean(const double *values,
const unsigned int n_values);
static double compute_stdev(const double *values,
const unsigned int n_values,
const double mean);
static int compute_ts_per_second(const int sec,
const struct timespec *ts,
const unsigned int n_ts);
#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 <stdio.h>
#include <math.h>
#include <stdarg.h>
#include <errno.h>
#include "stats-engine.h"
#include "stats-engine-private.h"
stats_engine create_stats_engine(void)
{
stats_engine engine = calloc(1, sizeof(*engine));
return engine;
}
int check_stats_engine(stats_engine engine)
{
if(engine != BAD_STATS_ENGINE)
return 0;
else
return 1;
}
void attach_log_devices_to_stats_engine(stats_engine engine,
log_device *log_devs,
unsigned int n_log_devs)
{
if(check_stats_engine(engine) || !log_devs || n_log_devs == 0)
return;
engine->logs = log_devs;
engine->n_logs = n_log_devs;
}
int enable_log_for_stats_engine(stats_engine engine)
{
if(check_stats_engine(engine))
return -EINVAL;
engine->enabled_log = 1;
return 0;
}
int disable_log_for_stats_engine(stats_engine engine)
{
if(check_stats_engine(engine))
return -EINVAL;
return 0;
}
int add_usr_timestamp_to_stats_engine(stats_engine engine, struct timespec *ts)
{
struct timespec system_ts;
if(check_stats_engine(engine))
return -EINVAL;
clock_gettime(CLOCK_REALTIME, &system_ts);
engine->sys_ts[engine->next_ts] = system_ts;
engine->usr_ts[engine->next_ts] = *ts;
update_index_stats_engine(&engine->next_ts);
update_n_ts_stats_engine(engine);
return 0;
}
int run_stats_engine(stats_engine engine)
{
struct timespec ts;
int neg;
int count_ts;
if(check_stats_engine(engine))
return -EINVAL;
neg = timespec_subtract(&ts, &engine->sys_ts[engine->current_ts],
&engine->usr_ts[engine->current_ts]);
engine->diff_ts[engine->current_ts] = ((neg) ? -1.0 : 1.0)*(ts.tv_sec + ((double) ts.tv_nsec / NS_IN_A_SEC));
engine->stats.mean = compute_mean(engine->diff_ts, engine->n_ts);
engine->stats.std = compute_stdev(engine->diff_ts, engine->n_ts, engine->stats.mean);
count_ts = compute_ts_per_second(engine->usr_ts[engine->current_ts].tv_sec,
engine->usr_ts, engine->n_ts);
if(count_ts != -1)
engine->stats.ts_per_second = count_ts;
engine->stats.ts_total++;
log_stats_engine(engine, 0);
update_index_stats_engine(&engine->current_ts);
return 0;
}
void destroy_stats_engine(stats_engine engine)
{
if(check_stats_engine(engine))
return;
free(engine);
}
static void update_n_ts_stats_engine(stats_engine engine)
{
if(engine->n_ts < MAX_TS)
engine->n_ts++;
}
static void update_index_stats_engine(unsigned int *index)
{
if(*index == MAX_TS-1)
*index = 0;
else
(*index)++;
}
static void log_stats_engine(stats_engine engine, int verbose)
{
LOG(engine, "\n===================== STATS ENGINE LOG =====================\n");
if(verbose) {
LOG(engine, "n_ts: %d", engine->n_ts);
LOG(engine, "next_ts: %d\n", engine->next_ts);
for(int i = 0 ; i < engine->n_ts ; i++) {
LOG(engine, "\tsys_ts[%d]: sec %ld, nsec %ld",
i, engine->sys_ts[i].tv_sec,
engine->sys_ts[i].tv_nsec);
LOG(engine, "\twr_ts[%d]: sec %ld, nsec %ld",
i, engine->usr_ts[i].tv_sec,
engine->usr_ts[i].tv_nsec);
LOG(engine, "\tdiff[%d]: diff %f",
i, engine->diff_ts[i]);
}
}
LOG(engine, "\nMetrics => nts: %d, nts_per_sec: %d\nmean: %f, stdev: %f",
engine->stats.ts_total, engine->stats.ts_per_second, engine->stats.mean, engine->stats.std);
LOG(engine, "\n============================================================\n");
log_clear(engine);
}
static int check_log_configuration(stats_engine engine)
{
if(!engine->logs || engine->n_logs == 0)
return 1;
if(!engine->enabled_log)
return 1;
return 0;
}
static void log_msg(stats_engine engine, const char *msg)
{
if(check_log_configuration(engine))
return;
for(int i = 0 ; i < engine->n_logs ; i++)
send_to_log_device(engine->logs[i], msg);
}
static void log_clear(stats_engine engine)
{
if(check_log_configuration(engine))
return;
for(int i = 0 ; i < engine->n_logs ; i++)
clear_log_device(engine->logs[i]);
}
static void LOG(stats_engine engine, 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(engine, buffer);
}
static int timespec_subtract(struct timespec *result,
struct timespec *x,
struct timespec *y)
{
struct timespec xx = *x;
struct timespec yy = *y;
x = &xx; y = &yy;
if (x->tv_nsec > NS_IN_A_SEC-1)
{
x->tv_sec += x->tv_nsec / NS_IN_A_SEC;
x->tv_nsec %= NS_IN_A_SEC;
}
if (y->tv_nsec > NS_IN_A_SEC-1)
{
y->tv_sec += y->tv_nsec / NS_IN_A_SEC;
y->tv_nsec %= NS_IN_A_SEC;
}
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_nsec = x->tv_nsec - y->tv_nsec;
if(result->tv_sec>0 && result->tv_nsec < 0)
{
result->tv_nsec += NS_IN_A_SEC;
result->tv_sec--;
}
else if(result->tv_sec<0 && result->tv_nsec > 0)
{
result->tv_nsec -= NS_IN_A_SEC;
result->tv_sec++;
}
return (result->tv_sec < 0) || (result->tv_nsec<0);
}
static double compute_mean(const double *values,
const unsigned int n_values)
{
double mean = 0.0;
for(int i = 0 ; i < n_values ; i++) {
mean += values[i];
}
mean /= n_values;
return mean;
}
static double compute_stdev(const double *values,
const unsigned int n_values,
const double mean)
{
double stdev = 0.0;
double aux = 0.0;
for(int i = 0 ; i < n_values ; i++) {
aux += pow((values[i]-mean),2);
}
stdev = sqrt((aux/n_values));
return stdev;
}
static int compute_ts_per_second(const int sec,
const struct timespec *ts,
const unsigned int n_ts)
{
static int prev_sec = -1;
int count = -1;
if(prev_sec == -1) {
prev_sec = sec;
}
else {
if(prev_sec != sec) {
count = 0;
for(int i = 0 ; i < n_ts ; i++) {
if(ts[i].tv_sec == prev_sec)
count++;
}
prev_sec = sec;
}
}
return count;
}
/*
* 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 __STATS_ENGINE_H__
#define __STATS_ENGINE_H__
#include <time.h>
#include "log-device.h"
typedef struct _stats_engine *stats_engine;
stats_engine create_stats_engine(void);
int check_stats_engine(stats_engine engine);
void attach_log_devices_to_stats_engine(stats_engine engine,
log_device *log_devs,
unsigned int n_log_devs);
int enable_log_for_stats_engine(stats_engine engine);
int disable_log_for_stats_engine(stats_engine engine);
int add_usr_timestamp_to_stats_engine(stats_engine engine,
struct timespec *ts);
int run_stats_engine(stats_engine engine);
void destroy_stats_engine(stats_engine engine);
#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 __DEMO_IRQ_PRIVATE_H__
#define __DEMO_IRQ_PRIVATE_H__
#define PROG_NAME "irq-demo"
#define TEST_FMC_DIO_CH 5
#define TEST_FMC_DIO_COUNT -1
#define TEST_FMC_DIO_PERIOD 100000000
#define STATS_LOG_PATH "./.irq-demo.log"
#define PROCESS_SLEEP_US 100000
struct _user_args {
char *fmc_dev_path;
unsigned int irq_period;
};
typedef struct _user_args * user_args;
static void demo_irq_process_loop(fmc_dio_device fmc_dev, stats_engine engine);
static void process_timestamps_to_engine(stats_engine engine, struct timespec *ts,
unsigned int nts);
static user_args create_user_arguments(void);
static int parse_user_arguments(int argc, char *argv[], user_args parsed_args);
static void destroy_user_arguments(user_args args);
static void show_help(void);
static unsigned int check_user_stop(void);
#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 <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include "stats-engine.h"
#include "fmc-dio-device.h"
#include "printf-log.h"
#include "file-log.h"
#include "irq-demo-private.h"
int main(int argc, char *argv[])
{
fmc_dio_device dev;
log_device gen_log;
log_device stats_log;
user_args user_arguments;
log_device logs[2];
unsigned int n_logs = 2;
unsigned int user_stop = 0;
stats_engine sengine;
int ret = 0;
gen_log = create_printf_log_device();
stats_log = create_file_log_device(STATS_LOG_PATH);
logs[0] = gen_log;
logs[1] = stats_log;
user_arguments = create_user_arguments();
if(parse_user_arguments(argc, argv, user_arguments)) {
show_help();
ret = 1;
goto out_log;
}
sengine = create_stats_engine();
if(check_stats_engine(sengine)) {
ret = 1;
goto out_user_args;
}
attach_log_devices_to_stats_engine(sengine, logs, n_logs);
enable_log_for_stats_engine(sengine);
dev = create_fmc_dio_device(user_arguments->fmc_dev_path);
if(open_fmc_dio_device(dev)) {
ret = 1;
goto out_stats_engine;
}
attach_log_devices_to_fmc_dio_device(dev, logs, n_logs);
enable_log_for_fmc_dio_device(dev);
disable_fmc_dio_device_all_irq(dev);
enable_fmc_dio_device_irq(dev, TEST_FMC_DIO_CH);
setup_fmc_dio_device_irq(dev, user_arguments->irq_period, TEST_FMC_DIO_COUNT);
while(!user_stop) {
demo_irq_process_loop(dev, sengine);
user_stop = check_user_stop();
}
disable_fmc_dio_device_all_irq(dev);
out_fmc_dio_device:
close_fmc_dio_device(dev);
out_stats_engine:
destroy_stats_engine(sengine);
out_user_args:
destroy_user_arguments(user_arguments);
out_log:
destroy_log_device(stats_log);
destroy_log_device(gen_log);
return ret;
}
static void demo_irq_process_loop(fmc_dio_device fmc_dev, stats_engine engine)
{
struct timespec *ts;
unsigned int nts;
while(!get_utc_ts_from_fmc_dio_device(fmc_dev, TEST_FMC_DIO_CH, &ts, &nts)) {
process_timestamps_to_engine(engine, ts, nts);
usleep(PROCESS_SLEEP_US);
}
}
static void process_timestamps_to_engine(stats_engine engine, struct timespec *ts,
unsigned int nts)
{
for(int i = 0 ; i < nts ; i++) {
add_usr_timestamp_to_stats_engine(engine, &ts[i]);
run_stats_engine(engine);
}
free(ts);
}
static user_args create_user_arguments(void)
{
user_args arguments;
arguments = calloc(1, sizeof(*arguments));
return arguments;
}
static int parse_user_arguments(int argc, char *argv[], user_args parsed_args)
{
if(argc != 2 && argc != 3)
return 1;
parsed_args->fmc_dev_path = argv[1];
if(argc == 3)
sscanf(argv[2], "%d", &parsed_args->irq_period);
else
parsed_args->irq_period = TEST_FMC_DIO_PERIOD;
return 0;
}
static void destroy_user_arguments(user_args args)
{
if(args) {
free(args);
}
}
static void show_help(void)
{
printf("usage: %s <FMC device path> [<irq period (ns)>]\n", PROG_NAME);
}
static unsigned int check_user_stop(void)
{
int ret = 0;
char c;
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
tv.tv_sec = 0;
tv.tv_usec = 1;
if(select(STDIN_FILENO+1, &fds, NULL, NULL, &tv) == 1) {
c = getchar();
if(c == 'q')
ret = 1;
}
return ret;
}
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