Rename files and make more consistent with Beam Monitor code
dio.* => device.* hdio.* => hware.* Digital.* => Monitor.* r1265 | dcl | 2006-11-09 12:25:16 +1100 (Thu, 09 Nov 2006) | 5 lines
This commit is contained in:
@@ -1,143 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
*
|
|
||||||
* ANSI C program:
|
|
||||||
* Digital.c
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This program reads digital lines on a NI-6509 Digital I/O card.
|
|
||||||
* Direction, and are all configurable.
|
|
||||||
*
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#define CNTR_CHK(func) if (cntr_fatal(error=(func))) goto Error; else
|
|
||||||
|
|
||||||
#include "Digital.h"
|
|
||||||
#include "utility.h"
|
|
||||||
#include "params.h"
|
|
||||||
#include "sock.h"
|
|
||||||
#include "dio.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <libiberty.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
int usage(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
fprintf(stderr, "usage: %s <DEVn/CTRn> <PORT>\n",
|
|
||||||
argv[0]);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
int error=0;
|
|
||||||
char errBuff[2048]={'\0'};
|
|
||||||
struct timeval now;
|
|
||||||
uint64 last_poll;
|
|
||||||
char* device;
|
|
||||||
int port;
|
|
||||||
int idx = 1;
|
|
||||||
|
|
||||||
if (idx >= argc)
|
|
||||||
return usage(argc, argv);
|
|
||||||
if (argv[idx][0] == '-')
|
|
||||||
{
|
|
||||||
if (tolower(argv[idx][1]) == 'd')
|
|
||||||
{
|
|
||||||
if (isdigit(argv[idx][2]))
|
|
||||||
set_debug_level(argv[idx][2] - '0');
|
|
||||||
else
|
|
||||||
set_debug_level(0);
|
|
||||||
}
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx >= argc)
|
|
||||||
return usage(argc, argv);
|
|
||||||
if (tolower(argv[idx][0]) == 'd' &&
|
|
||||||
tolower(argv[idx][1]) == 'e' &&
|
|
||||||
tolower(argv[idx][2]) == 'v' &&
|
|
||||||
isdigit(argv[idx][3]))
|
|
||||||
{
|
|
||||||
device = argv[idx];
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return usage(argc, argv);
|
|
||||||
|
|
||||||
if (idx >= argc)
|
|
||||||
return usage(argc, argv);
|
|
||||||
if (isdigit(argv[idx][0]))
|
|
||||||
{
|
|
||||||
port = atoi(argv[idx]);
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return usage(argc, argv);
|
|
||||||
|
|
||||||
memset(&counter, 0, sizeof(counter));
|
|
||||||
|
|
||||||
CNTR_CHK(cntr_init(&counter, device));
|
|
||||||
// CNTR_CHK(cntr_start(&counter));
|
|
||||||
sock_init(port);
|
|
||||||
|
|
||||||
printf("Continuously polling. Press Ctrl+C to interrupt\n");
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
last_poll = 1000 * (uint64) now.tv_sec + now.tv_usec / 1000;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
COUNTER* cp = &counter;
|
|
||||||
PARAMETERS* pp = &cp->params;
|
|
||||||
uint64 timeofday;
|
|
||||||
int timeout = 0;
|
|
||||||
do {
|
|
||||||
sock_check(timeout);
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
timeofday = 1000 * (uint64) now.tv_sec + now.tv_usec / 1000;
|
|
||||||
if (timeofday / pp->poll_period > last_poll / pp->poll_period)
|
|
||||||
timeout = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
timeout = pp->poll_period - timeofday % pp->poll_period;
|
|
||||||
if (timeout < 0)
|
|
||||||
{
|
|
||||||
if (timeout < 0)
|
|
||||||
dprintf(0, "Poll timeout < 0 at %d\n", timeout);
|
|
||||||
timeout = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//dprintf(0, "Poll timeout = %d\n", timeout);
|
|
||||||
} while (timeout > 0);
|
|
||||||
cp->current_time = now;
|
|
||||||
#if 1
|
|
||||||
dprintf(0, "-%s %s %.3f %s %.3f %4d\n",
|
|
||||||
make_timestamp(&cp->current_time),
|
|
||||||
make_timestamp(&cp->sample_timer),
|
|
||||||
cntr_time_to_next_sample(cp),
|
|
||||||
make_timestamp(&cp->report_timer),
|
|
||||||
cntr_time_to_next_report(cp),
|
|
||||||
cp->sample_index);
|
|
||||||
#endif
|
|
||||||
CNTR_CHK(cntr_poll(cp));
|
|
||||||
last_poll = timeofday;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error:
|
|
||||||
puts("");
|
|
||||||
if (cntr_fatal(error))
|
|
||||||
{
|
|
||||||
cntr_errmsg(errBuff, sizeof(errBuff));
|
|
||||||
printf("DAQmx Error: %s\n", errBuff);
|
|
||||||
}
|
|
||||||
cntr_term(&counter);
|
|
||||||
printf("End of program\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
164
site_ansto/hardsup/Digital/Monitor.c
Normal file
164
site_ansto/hardsup/Digital/Monitor.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* ANSI C program:
|
||||||
|
* Monitor.c
|
||||||
|
*
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#define DEVICE_CHK(func) if (device_fatal(error=(func))) goto Error; else
|
||||||
|
|
||||||
|
#include "Monitor.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "sock.h"
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libiberty.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
int usage(int argc, char* argv[], const char* reason)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fprintf(stderr, "%s", argv[0]);
|
||||||
|
for (i = 1; i < argc; ++i)
|
||||||
|
fprintf(stderr, " %s", argv[i]);
|
||||||
|
fprintf(stderr, "\n%s\n", reason);
|
||||||
|
fprintf(stderr, "usage: %s <DEVn/CTRn> <PORT>\n",
|
||||||
|
argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int error=0;
|
||||||
|
char errBuff[2048]={'\0'};
|
||||||
|
struct timeval now;
|
||||||
|
uint64 last_poll;
|
||||||
|
char* device = DEFAULT_DEVICE;
|
||||||
|
uint dev_no;
|
||||||
|
int port = DEFAULT_LISTEN_PORT;
|
||||||
|
int idx = 1;
|
||||||
|
DEVICE* devices[MAX_DEVICES];
|
||||||
|
|
||||||
|
if (idx >= argc)
|
||||||
|
return usage(argc, argv, "no args");
|
||||||
|
if (argv[idx][0] == '-')
|
||||||
|
{
|
||||||
|
if (tolower(argv[idx][1]) == 'd')
|
||||||
|
{
|
||||||
|
if (isdigit(argv[idx][2]))
|
||||||
|
set_debug_level(argv[idx][2] - '0');
|
||||||
|
else
|
||||||
|
set_debug_level(0);
|
||||||
|
}
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx >= argc)
|
||||||
|
return usage(argc, argv, "no device");
|
||||||
|
if (tolower(argv[idx][0]) == 'd' &&
|
||||||
|
tolower(argv[idx][1]) == 'e' &&
|
||||||
|
tolower(argv[idx][2]) == 'v' &&
|
||||||
|
isdigit(argv[idx][3]))
|
||||||
|
{
|
||||||
|
device = argv[idx];
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
else if (tolower(argv[idx][0]) == 'p' &&
|
||||||
|
tolower(argv[idx][1]) == 'x' &&
|
||||||
|
tolower(argv[idx][2]) == 'i' &&
|
||||||
|
isdigit(argv[idx][3]))
|
||||||
|
{
|
||||||
|
device = argv[idx];
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return usage(argc, argv, "bad device");
|
||||||
|
|
||||||
|
if (idx >= argc)
|
||||||
|
return usage(argc, argv, "no port");
|
||||||
|
if (isdigit(argv[idx][0]))
|
||||||
|
{
|
||||||
|
port = atoi(argv[idx]);
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return usage(argc, argv, "bad port");
|
||||||
|
|
||||||
|
dev_no = atoi(&device[3]);
|
||||||
|
sock_init();
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
for (idx = 0; idx < MAX_DEVICES; ++idx)
|
||||||
|
{
|
||||||
|
sprintf(device, "dev%d/port%d", dev_no, idx);
|
||||||
|
DEVICE_CHK(device_init(&devices[idx], device));
|
||||||
|
sock_listen(port + idx, device_command, devices[idx]);
|
||||||
|
devices[idx]->current_time = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Continuously polling. Press Ctrl+C to interrupt\n");
|
||||||
|
last_poll = 1000 * (uint64) now.tv_sec + now.tv_usec / 1000;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
uint64 timeofday;
|
||||||
|
int timeout = 0;
|
||||||
|
int next_timeout = 0;
|
||||||
|
do {
|
||||||
|
next_timeout = 1000;
|
||||||
|
sock_check(timeout);
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
timeofday = 1000 * (uint64) now.tv_sec + now.tv_usec / 1000;
|
||||||
|
for (idx = 0; idx < MAX_DEVICES; ++idx)
|
||||||
|
{
|
||||||
|
DEVICE* device = devices[idx];
|
||||||
|
PARAMETERS* pp = &device->params;
|
||||||
|
last_poll = 1000 * (uint64) device->current_time.tv_sec
|
||||||
|
+ device->current_time.tv_usec / 1000;
|
||||||
|
if (timeofday / pp->poll_period > last_poll / pp->poll_period)
|
||||||
|
timeout = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timeout = pp->poll_period - timeofday % pp->poll_period;
|
||||||
|
if (timeout < 0)
|
||||||
|
{
|
||||||
|
if (timeout < 0)
|
||||||
|
dbg_printf(0, "Poll timeout < 0 at %d\n", timeout);
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (timeout < next_timeout)
|
||||||
|
next_timeout = timeout;
|
||||||
|
if (timeout == 0)
|
||||||
|
{
|
||||||
|
device->current_time = now;
|
||||||
|
DEVICE_CHK(device_poll(device));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (next_timeout > 999)
|
||||||
|
next_timeout = 1;
|
||||||
|
timeout = next_timeout;
|
||||||
|
//dbg_printf(0, "Poll timeout = %d\n", timeout);
|
||||||
|
} while (timeout > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error:
|
||||||
|
puts("");
|
||||||
|
if (device_fatal(error))
|
||||||
|
{
|
||||||
|
device_errmsg(errBuff, sizeof(errBuff));
|
||||||
|
printf("DAQmx Error: %s\n", errBuff);
|
||||||
|
}
|
||||||
|
for (idx = 0; idx < MAX_DEVICES; ++idx)
|
||||||
|
device_term(devices[idx]);
|
||||||
|
printf("End of program\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#ifndef _MONITOR_H_
|
#ifndef _MONITOR_H_
|
||||||
#define _MONITOR_H_
|
#define _MONITOR_H_
|
||||||
|
|
||||||
#define DEFAULT_COUNTER_DEVICE "DEV1/CTR0"
|
#define DEFAULT_DEVICE "DEV1"
|
||||||
#define DEFAULT_LISTEN_PORT 3000
|
#define DEFAULT_LISTEN_PORT 3000
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
215
site_ansto/hardsup/Digital/device.c
Normal file
215
site_ansto/hardsup/Digital/device.c
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Abstraction of the counter device.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "device.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "sock.h"
|
||||||
|
#include "hware.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define HWARE_TEST(functionCall) \
|
||||||
|
if( hware_failed(error=(functionCall)) ) \
|
||||||
|
goto Error; \
|
||||||
|
else
|
||||||
|
|
||||||
|
void device_send(DEVICE* device, int n)
|
||||||
|
{
|
||||||
|
BUFFER buffer;
|
||||||
|
buffer.length = 0;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"Time: %s, Value: 0x%06X\r\n",
|
||||||
|
make_timestamp(NULL),
|
||||||
|
device->value);
|
||||||
|
buffer.length = strlen(buffer.body);
|
||||||
|
sock_send(n, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_read(DEVICE* device, int n)
|
||||||
|
{
|
||||||
|
BUFFER buffer;
|
||||||
|
buffer.length = 0;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"READ 0x%06X\r\n",
|
||||||
|
device->value);
|
||||||
|
buffer.length = strlen(buffer.body);
|
||||||
|
sock_send(n, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_write(DEVICE *device, int n, const char* tp)
|
||||||
|
{
|
||||||
|
unsigned long value;
|
||||||
|
|
||||||
|
value = strtol(tp, NULL, 16);
|
||||||
|
hware_write(device->private_data, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_print(DEVICE* device, FILE* fd)
|
||||||
|
{
|
||||||
|
fprintf(fd, "Time: %s, Value: 0x%06X\r\n",
|
||||||
|
make_timestamp(NULL),
|
||||||
|
device->value);
|
||||||
|
fflush(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_report(DEVICE* device)
|
||||||
|
{
|
||||||
|
dbg_printf(0, "device_report\n");
|
||||||
|
/*
|
||||||
|
* Set the time for this report
|
||||||
|
*/
|
||||||
|
device->report_timer = device->current_time;
|
||||||
|
BUFFER buffer;
|
||||||
|
char* str = make_timestamp(&device->current_time);
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"%s 0x%06X\r\n",
|
||||||
|
str,
|
||||||
|
device->value);
|
||||||
|
buffer.length = strlen(buffer.body);
|
||||||
|
sock_report(&buffer, 1, device);
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"REPORT %s 0x%06X\r\n",
|
||||||
|
str,
|
||||||
|
device->value);
|
||||||
|
buffer.length = strlen(buffer.body);
|
||||||
|
sock_report(&buffer, 2, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the counter
|
||||||
|
*
|
||||||
|
* Initialise all of the control data associated with the logical counter.
|
||||||
|
*
|
||||||
|
* Create a 64-bit physical counter and start it.
|
||||||
|
*/
|
||||||
|
int device_init(DEVICE** cpp, char* name)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
char errBuff[2048]={'\0'};
|
||||||
|
DEVICE* device = (DEVICE*) malloc(sizeof(DEVICE));
|
||||||
|
*cpp = device;
|
||||||
|
memset(device, 0, sizeof(DEVICE));
|
||||||
|
strncpy(device->name, name, sizeof(device->name));
|
||||||
|
device->params.poll_period = 1000; /* milliseconds between polls */
|
||||||
|
device->params.sample_period = 10; /* polls between sample calcs */
|
||||||
|
device->params.report_period = 3; /* samples between reports */
|
||||||
|
device->state = device_stopped;
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
device->current_time = now;
|
||||||
|
device->previous_time = now;
|
||||||
|
device->report_timer = now;
|
||||||
|
HWARE_TEST(hware_ctor(name, &device->private_data));
|
||||||
|
return 0;
|
||||||
|
Error:
|
||||||
|
hware_errmsg(errBuff, sizeof(errBuff));
|
||||||
|
printf("DAQmx Error: %s\n", errBuff);
|
||||||
|
return error;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_command(void* dev, const char* command)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// DEVICE* device = (DEVICE*)(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void device_event(DEVICE *device, char* event)
|
||||||
|
{
|
||||||
|
BUFFER buffer;
|
||||||
|
sprintf(buffer.body, "EVENT %s %s\r\n",
|
||||||
|
make_timestamp(&device->current_time),
|
||||||
|
event);
|
||||||
|
buffer.length = strlen(buffer.body);
|
||||||
|
dbg_printf(0, "%s", buffer.body);
|
||||||
|
sock_report(&buffer, 1, device);
|
||||||
|
sock_report(&buffer, 2, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* poll the physical counter
|
||||||
|
*/
|
||||||
|
int device_poll(DEVICE* device)
|
||||||
|
{
|
||||||
|
char errBuff[2048]={'\0'};
|
||||||
|
HWARE_VALUE current_local_value;
|
||||||
|
int error=0;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
dbg_printf(0, "%s:-%s %s %4d\n",
|
||||||
|
device->name,
|
||||||
|
make_timestamp(&device->current_time),
|
||||||
|
make_timestamp(&device->report_timer),
|
||||||
|
device_time_to_next_report(device));
|
||||||
|
#endif
|
||||||
|
/* read the value from the hardware to a temp */
|
||||||
|
++device->poll_counter;
|
||||||
|
HWARE_TEST(hware_read(device->private_data, ¤t_local_value));
|
||||||
|
dbg_printf(0, "device_poll = 0x%06X @ %s\n",
|
||||||
|
current_local_value,
|
||||||
|
make_timestamp(&device->current_time));
|
||||||
|
if (current_local_value != device->value)
|
||||||
|
{
|
||||||
|
char str[100];
|
||||||
|
snprintf(str, sizeof(str), "changed 0x%06X 0x%06X",
|
||||||
|
current_local_value,
|
||||||
|
device->value);
|
||||||
|
device_event(device, str);
|
||||||
|
}
|
||||||
|
device->value = current_local_value;
|
||||||
|
/* check if it is time to roll the report */
|
||||||
|
if (device_time_to_next_report(device) <= 0)
|
||||||
|
{
|
||||||
|
device_report(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
Error:
|
||||||
|
device_errmsg(errBuff, sizeof(errBuff));
|
||||||
|
printf("DAQmx Error: %s\n", errBuff);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_term(DEVICE* device)
|
||||||
|
{
|
||||||
|
if (device->private_data)
|
||||||
|
{
|
||||||
|
hware_dtor(&device->private_data);
|
||||||
|
device->private_data = NULL;
|
||||||
|
}
|
||||||
|
device->state = device_idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool device_fatal(int error)
|
||||||
|
{
|
||||||
|
return hware_failed(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_errmsg(char* buff, int len)
|
||||||
|
{
|
||||||
|
hware_errmsg(buff, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
double device_time_to_next_report(DEVICE* device)
|
||||||
|
{
|
||||||
|
uint64 last_report;
|
||||||
|
uint64 timeofday;
|
||||||
|
int timeout;
|
||||||
|
struct timeval now;
|
||||||
|
now = device->current_time;
|
||||||
|
last_report = 1000 * (uint64) device->report_timer.tv_sec;
|
||||||
|
last_report += (uint64) device->report_timer.tv_usec / 1000;
|
||||||
|
timeofday = 1000 * (uint64) now.tv_sec;
|
||||||
|
timeofday += (uint64) now.tv_usec / 1000;
|
||||||
|
timeout = device->params.poll_period *
|
||||||
|
device->params.sample_period *
|
||||||
|
device->params.report_period;
|
||||||
|
if ((last_report / timeout) != (timeofday / timeout))
|
||||||
|
return 0.0;
|
||||||
|
timeout = timeout - timeofday % timeout;
|
||||||
|
return 0.001 * timeout;
|
||||||
|
}
|
||||||
62
site_ansto/hardsup/Digital/device.h
Normal file
62
site_ansto/hardsup/Digital/device.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#ifndef _DEVICE_H_
|
||||||
|
#define _DEVICE_H_
|
||||||
|
|
||||||
|
#define MAX_DEVICES 3
|
||||||
|
|
||||||
|
#define SAMPLE_ARRAY_SZ 1000
|
||||||
|
|
||||||
|
#include "utility.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
|
typedef enum device_state_t
|
||||||
|
{
|
||||||
|
/** The counter has not yet been created or has been destroyed */
|
||||||
|
device_idle = 0,
|
||||||
|
/** The counter has not yet been started or has been stopped */
|
||||||
|
device_stopped,
|
||||||
|
/** The counter is counting */
|
||||||
|
device_running,
|
||||||
|
/** the counter has been paused */
|
||||||
|
device_paused
|
||||||
|
} DEVICE_STATE;
|
||||||
|
|
||||||
|
typedef struct device_t
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
DEVICE_STATE state;
|
||||||
|
/** time of this read */
|
||||||
|
struct timeval current_time;
|
||||||
|
/** time of last read */
|
||||||
|
struct timeval previous_time;
|
||||||
|
/** time of next report generation */
|
||||||
|
struct timeval report_timer;
|
||||||
|
/** number of polls */
|
||||||
|
int poll_counter;
|
||||||
|
/** physical device value */
|
||||||
|
unsigned int value;
|
||||||
|
/** Control parameters */
|
||||||
|
PARAMETERS params;
|
||||||
|
struct device_private_t* private_data;
|
||||||
|
} DEVICE, *pDEVICE;
|
||||||
|
|
||||||
|
void make_report(DEVICE* device);
|
||||||
|
void device_sample(DEVICE* device);
|
||||||
|
void device_send(DEVICE* device, int n);
|
||||||
|
void device_read(DEVICE* device, int n);
|
||||||
|
void device_write(DEVICE* device, int n, const char *tp);
|
||||||
|
void device_print(DEVICE* device, FILE* fd);
|
||||||
|
void device_report(DEVICE* device);
|
||||||
|
int device_init(DEVICE** cpp, char* name);
|
||||||
|
int device_start(DEVICE* device);
|
||||||
|
int device_stop(DEVICE* device);
|
||||||
|
int device_pause(DEVICE* device);
|
||||||
|
int device_resume(DEVICE* device);
|
||||||
|
int device_command(void* device, const char* cmd);
|
||||||
|
int device_poll(DEVICE* device);
|
||||||
|
void device_term(DEVICE* device);
|
||||||
|
bool device_fatal(int error);
|
||||||
|
void device_errmsg(char* buff, int len);
|
||||||
|
double device_time_to_next_sample(DEVICE* device);
|
||||||
|
double device_time_to_next_report(DEVICE* device);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,586 +0,0 @@
|
|||||||
/*
|
|
||||||
* Abstraction of the counter device.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include "dio.h"
|
|
||||||
#include "params.h"
|
|
||||||
#include "sock.h"
|
|
||||||
#include "hdio.h"
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define HCTR_TEST(functionCall) \
|
|
||||||
if( hdio_failed(error=(functionCall)) ) \
|
|
||||||
goto Error; \
|
|
||||||
else
|
|
||||||
|
|
||||||
COUNTER counter;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get a pointer to the current sample
|
|
||||||
*/
|
|
||||||
static SAMPLE* cur_sample(COUNTER* cp)
|
|
||||||
{
|
|
||||||
return &cp->sample_array[cp->sample_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get a pointer to the num'th previous sample
|
|
||||||
*/
|
|
||||||
static SAMPLE* prv_sample(COUNTER* cp, int num)
|
|
||||||
{
|
|
||||||
int idx = (cp->sample_index + SAMPLE_ARRAY_SZ - num) % SAMPLE_ARRAY_SZ;
|
|
||||||
return &cp->sample_array[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
void make_report(COUNTER* cp)
|
|
||||||
{
|
|
||||||
dprintf(0, "make_report\n");
|
|
||||||
int i;
|
|
||||||
SAMPLE* sp = cur_sample(cp);
|
|
||||||
cp->report = *sp;
|
|
||||||
cp->report.average_rate = cp->report.counter_rate;
|
|
||||||
cp->report.minimum_rate = cp->report.counter_rate;
|
|
||||||
cp->report.maximum_rate = cp->report.counter_rate;
|
|
||||||
for (i = 1; i <= cp->params.report_period; ++i)
|
|
||||||
{
|
|
||||||
SAMPLE* psp;
|
|
||||||
psp = prv_sample(cp, i);
|
|
||||||
if (psp->valid)
|
|
||||||
{
|
|
||||||
cp->report.time_delta = time_diff(&sp->timestamp, &psp->timestamp);
|
|
||||||
cp->report.count_delta = sp->count64 - psp->count64;
|
|
||||||
if (cp->report.time_delta > 0.0)
|
|
||||||
cp->report.average_rate = cp->report.count_delta
|
|
||||||
/ cp->report.time_delta;
|
|
||||||
if (i < cp->params.report_period)
|
|
||||||
{
|
|
||||||
cp->report.num_polls += psp->num_polls;
|
|
||||||
if (psp->counter_rate < cp->report.minimum_rate)
|
|
||||||
cp->report.minimum_rate = psp->counter_rate;
|
|
||||||
if (psp->counter_rate > cp->report.maximum_rate)
|
|
||||||
cp->report.maximum_rate = psp->counter_rate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sp = &cp->report;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* given two samples, compute the count-rate
|
|
||||||
*/
|
|
||||||
static double compute_rate(COUNTER* cp, SAMPLE* cur, SAMPLE* prv)
|
|
||||||
{
|
|
||||||
double result = 0.0;
|
|
||||||
uInt32 delta_counter;
|
|
||||||
if (cp->params.direction == COUNT_DOWN)
|
|
||||||
delta_counter = prv->counter_value - cur->counter_value;
|
|
||||||
else
|
|
||||||
delta_counter = cur->counter_value - prv->counter_value;
|
|
||||||
double delta_timer = time_diff(&cur->timestamp, &prv->timestamp);
|
|
||||||
result = 1.0 * delta_counter / delta_timer;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* given two samples, compute the average rate
|
|
||||||
*/
|
|
||||||
static double compute_average(COUNTER* cp, SAMPLE* cur, SAMPLE* prv)
|
|
||||||
{
|
|
||||||
double result = 0.0;
|
|
||||||
if (cur == prv)
|
|
||||||
result = cur->counter_rate;
|
|
||||||
else
|
|
||||||
result = compute_rate(cp, cur, prv);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void cntr_send(COUNTER* cp, int n)
|
|
||||||
{
|
|
||||||
SAMPLE* sp = cur_sample(cp);
|
|
||||||
BUFFER buffer;
|
|
||||||
buffer.length = 0;
|
|
||||||
snprintf(buffer.body, sizeof(buffer.body),
|
|
||||||
"Time: %s, Count: %10llu, Delta: %6d, Time: %8.6f, Rate: %8.2f, Ave: %8.2f\r\n",
|
|
||||||
make_timestamp(&sp->timestamp),
|
|
||||||
sp->counter_value,
|
|
||||||
sp->count_delta,
|
|
||||||
sp->time_delta,
|
|
||||||
sp->counter_rate,
|
|
||||||
sp->average_rate);
|
|
||||||
buffer.length = strlen(buffer.body);
|
|
||||||
sock_send(n, &buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cntr_read(COUNTER* cp, int n)
|
|
||||||
{
|
|
||||||
SAMPLE* sp = cur_sample(cp);
|
|
||||||
BUFFER buffer;
|
|
||||||
buffer.length = 0;
|
|
||||||
snprintf(buffer.body, sizeof(buffer.body),
|
|
||||||
"READ %c%c%c%c %s %.6f %10llu %8.2f\r\n",
|
|
||||||
cp->state == counter_idle ? 'I' :
|
|
||||||
cp->state == counter_stopped ? 'S' :
|
|
||||||
cp->state == counter_running ? 'R' :
|
|
||||||
cp->state == counter_paused ? 'P' : '?',
|
|
||||||
cp->terminal_due ? 'T' : ' ',
|
|
||||||
cp->range_error == 0 ? ' ' : 'R',
|
|
||||||
cp->range_gated ? 'G' : ' ',
|
|
||||||
make_timestamp(&sp->timestamp),
|
|
||||||
cp->accumulated.tv_sec + .000001 * cp->accumulated.tv_usec,
|
|
||||||
sp->counter_value,
|
|
||||||
sp->counter_rate);
|
|
||||||
buffer.length = strlen(buffer.body);
|
|
||||||
sock_send(n, &buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cntr_print(COUNTER* cp, FILE* fd)
|
|
||||||
{
|
|
||||||
SAMPLE* sp = cur_sample(cp);
|
|
||||||
fprintf(fd, "Time: %s, Count: %10llu, Delta: %6d, Time: %8.6f, Rate: %8.2f, Ave: %8.2f\r\n",
|
|
||||||
make_timestamp(&sp->timestamp),
|
|
||||||
sp->counter_value,
|
|
||||||
sp->count_delta,
|
|
||||||
sp->time_delta,
|
|
||||||
sp->counter_rate,
|
|
||||||
sp->average_rate);
|
|
||||||
fflush(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Finalise the current sample and move on to the next
|
|
||||||
*/
|
|
||||||
void cntr_sample(COUNTER* cp)
|
|
||||||
{
|
|
||||||
SAMPLE* psp = cur_sample(cp);
|
|
||||||
dprintf(0, "cntr_sample: %4d\r\n"
|
|
||||||
" polls: %4d\r\n"
|
|
||||||
" time: %4s\r\n"
|
|
||||||
" counter: %10llu\r\n"
|
|
||||||
" count64: %10llu\r\n"
|
|
||||||
" c_delta: %d\r\n"
|
|
||||||
" t_delta: %6.3f\r\n"
|
|
||||||
" rate: %10g\n",
|
|
||||||
cp->sample_index,
|
|
||||||
psp->num_polls,
|
|
||||||
make_timestamp(&psp->timestamp),
|
|
||||||
psp->counter_value,
|
|
||||||
psp->count64,
|
|
||||||
psp->count_delta,
|
|
||||||
psp->time_delta,
|
|
||||||
psp->counter_rate);
|
|
||||||
cp->sample_timer = cp->current_time;
|
|
||||||
++cp->sample_counter;
|
|
||||||
|
|
||||||
if (++cp->sample_index >= SAMPLE_ARRAY_SZ)
|
|
||||||
cp->sample_index = 0;
|
|
||||||
SAMPLE* sp = cur_sample(cp);
|
|
||||||
*sp = *psp;
|
|
||||||
sp->valid = true;
|
|
||||||
sp->num_polls = 0;
|
|
||||||
sp->sample_counter = cp->sample_counter;
|
|
||||||
sp->poll_counter = cp->poll_counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cntr_report(COUNTER* cp)
|
|
||||||
{
|
|
||||||
dprintf(0, "cntr_report\n");
|
|
||||||
/*
|
|
||||||
* Set the time for this report
|
|
||||||
*/
|
|
||||||
cp->report_timer = cp->current_time;
|
|
||||||
BUFFER buffer;
|
|
||||||
SAMPLE* sp;
|
|
||||||
sp = &cp->report;
|
|
||||||
char* str = make_timestamp(&sp->timestamp);
|
|
||||||
snprintf(buffer.body, sizeof(buffer.body),
|
|
||||||
"%s (%6.3f), %10llu (%8d), %8.2f (%8.2f,%8.2f,%8.2f)\r\n",
|
|
||||||
str,
|
|
||||||
sp->time_delta,
|
|
||||||
sp->counter_value,
|
|
||||||
sp->count_delta,
|
|
||||||
sp->counter_rate,
|
|
||||||
sp->minimum_rate,
|
|
||||||
sp->average_rate,
|
|
||||||
sp->maximum_rate);
|
|
||||||
buffer.length = strlen(buffer.body);
|
|
||||||
//fputs(buffer.body, stdout);
|
|
||||||
sock_report(&buffer, 1);
|
|
||||||
snprintf(buffer.body, sizeof(buffer.body),
|
|
||||||
"REPORT %s %10llu %8.2f (%8.2f,%8.2f,%8.2f)\r\n",
|
|
||||||
str,
|
|
||||||
sp->counter_value,
|
|
||||||
sp->counter_rate,
|
|
||||||
sp->minimum_rate,
|
|
||||||
sp->average_rate,
|
|
||||||
sp->maximum_rate);
|
|
||||||
buffer.length = strlen(buffer.body);
|
|
||||||
//fputs(buffer.body, stdout);
|
|
||||||
sock_report(&buffer, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise the counter
|
|
||||||
*
|
|
||||||
* Initialise all of the control data associated with the logical counter.
|
|
||||||
*
|
|
||||||
* Create a 64-bit physical counter and start it.
|
|
||||||
*/
|
|
||||||
int cntr_init(COUNTER* cp, char* name)
|
|
||||||
{
|
|
||||||
int error = 0;
|
|
||||||
char errBuff[2048]={'\0'};
|
|
||||||
memset(cp, 0, sizeof(COUNTER));
|
|
||||||
strncpy(cp->name, name, sizeof(cp->name));
|
|
||||||
cp->params.poll_period = 1000; /* milliseconds between polls */
|
|
||||||
cp->params.sample_period = 10; /* polls between sample calcs */
|
|
||||||
cp->params.report_period = 3; /* samples between reports */
|
|
||||||
cp->state = counter_stopped;
|
|
||||||
struct timeval now;
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
cp->current_time = now;
|
|
||||||
cp->previous_time = now;
|
|
||||||
cp->sample_timer = now;
|
|
||||||
cp->report_timer = now;
|
|
||||||
HCTR_TEST(hdio_ctor(name, &cp->private_data));
|
|
||||||
SAMPLE* sp = cur_sample(cp);
|
|
||||||
sp->timestamp = now;
|
|
||||||
sp->counter_value = cp->current_count;
|
|
||||||
sp->valid = true;
|
|
||||||
cntr_sample(cp);
|
|
||||||
return 0;
|
|
||||||
Error:
|
|
||||||
hdio_errmsg(errBuff, sizeof(errBuff));
|
|
||||||
printf("DAQmx Error: %s\n", errBuff);
|
|
||||||
return error;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the logical counter
|
|
||||||
*
|
|
||||||
* Read the value of the physical counter and set the state to running
|
|
||||||
*/
|
|
||||||
int cntr_start(COUNTER *cp)
|
|
||||||
{
|
|
||||||
int error = 0;
|
|
||||||
char errBuff[2048]={'\0'};
|
|
||||||
struct timeval now;
|
|
||||||
/* start the counter object */
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
cp->current_time = now;
|
|
||||||
cp->start_time = cp->current_time;
|
|
||||||
cp->current_count = cp->params.initial_count;
|
|
||||||
cp->accumulated.tv_sec = 0;
|
|
||||||
cp->accumulated.tv_usec = 0;
|
|
||||||
cp->poll_counter = 0;
|
|
||||||
cp->sample_counter = 0;
|
|
||||||
cp->terminal_due = false;
|
|
||||||
cp->state = counter_running;
|
|
||||||
cp->previous_time = cp->current_time;
|
|
||||||
HCTR_TEST(hdio_read(cp->private_data, &cp->count64));
|
|
||||||
make_report(cp);
|
|
||||||
return error;
|
|
||||||
Error:
|
|
||||||
cntr_errmsg(errBuff, sizeof(errBuff));
|
|
||||||
printf("DAQmx Error: %s\n", errBuff);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cntr_stop(COUNTER *cp)
|
|
||||||
{
|
|
||||||
int error = 0;
|
|
||||||
cp->stop_time = cp->current_time;
|
|
||||||
cp->state = counter_stopped;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cntr_pause(COUNTER *cp)
|
|
||||||
{
|
|
||||||
if (cp->state == counter_running)
|
|
||||||
cp->state = counter_paused;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cntr_resume(COUNTER *cp)
|
|
||||||
{
|
|
||||||
if (cp->state == counter_paused)
|
|
||||||
cp->state = counter_running;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cntr_event(COUNTER *cp, char* event)
|
|
||||||
{
|
|
||||||
BUFFER buffer;
|
|
||||||
sprintf(buffer.body, "EVENT %s %s\r\n",
|
|
||||||
event,
|
|
||||||
make_timestamp(&cp->current_time));
|
|
||||||
buffer.length = strlen(buffer.body);
|
|
||||||
dprintf(0, "%s", buffer.body);
|
|
||||||
//sock_report(&buffer, 0);
|
|
||||||
sock_report(&buffer, 1);
|
|
||||||
sock_report(&buffer, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cntr_range_check(COUNTER* cp, int mode)
|
|
||||||
{
|
|
||||||
PARAMETERS* pp = &cp->params;
|
|
||||||
if (pp->range_check_enable)
|
|
||||||
{
|
|
||||||
if (pp->range_mode == mode)
|
|
||||||
{
|
|
||||||
double test;
|
|
||||||
SAMPLE* sp = cur_sample(cp);
|
|
||||||
if (mode == 1)
|
|
||||||
test = sp->counter_rate;
|
|
||||||
else if (mode == 2)
|
|
||||||
test = sp->counter_rate;
|
|
||||||
else
|
|
||||||
test = cp->report.average_rate;
|
|
||||||
if (pp->range_low > 0 && pp->range_low > test)
|
|
||||||
{
|
|
||||||
if (cp->range_error != 1)
|
|
||||||
cntr_event(cp, "RANGE OUT LOW");
|
|
||||||
cp->range_error = 1;
|
|
||||||
if (pp->range_gate_enable)
|
|
||||||
cp->range_gated = true;
|
|
||||||
else
|
|
||||||
cp->range_gated = false;
|
|
||||||
}
|
|
||||||
else if (pp->range_high > 0 && pp->range_high < test)
|
|
||||||
{
|
|
||||||
if (cp->range_error != 2)
|
|
||||||
cntr_event(cp, "RANGE OUT HIGH");
|
|
||||||
cp->range_error = 2;
|
|
||||||
if (pp->range_gate_enable)
|
|
||||||
cp->range_gated = true;
|
|
||||||
else
|
|
||||||
cp->range_gated = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (cp->range_error != 0)
|
|
||||||
cntr_event(cp, "RANGE IN");
|
|
||||||
cp->range_error = 0;
|
|
||||||
cp->range_gated = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* If range check has been disabled while in error - reset */
|
|
||||||
if (cp->range_error != 0)
|
|
||||||
cntr_event(cp, "RANGE IN");
|
|
||||||
cp->range_error = 0;
|
|
||||||
cp->range_gated = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cntr_test_term(COUNTER* cp)
|
|
||||||
{
|
|
||||||
PARAMETERS* pp = &cp->params;
|
|
||||||
SAMPLE* sp = cur_sample(cp);
|
|
||||||
SAMPLE* psp = prv_sample(cp, 1);
|
|
||||||
|
|
||||||
if (!cp->terminal_due)
|
|
||||||
{
|
|
||||||
if (pp->terminal_check_type == 1)
|
|
||||||
{
|
|
||||||
if (pp->direction == COUNT_DOWN)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* decremented to or through terminal
|
|
||||||
*/
|
|
||||||
if ((sp->counter_value <= pp->terminal_count &&
|
|
||||||
psp->counter_value > pp->terminal_count) ||
|
|
||||||
(sp->counter_value > psp->counter_value &&
|
|
||||||
psp->counter_value > pp->terminal_count))
|
|
||||||
{
|
|
||||||
cp->terminal_due = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* incremented to or through terminal
|
|
||||||
*/
|
|
||||||
if ((sp->counter_value >= pp->terminal_count &&
|
|
||||||
psp->counter_value < pp->terminal_count) ||
|
|
||||||
(sp->counter_value < psp->counter_value &&
|
|
||||||
psp->counter_value > pp->terminal_count))
|
|
||||||
{
|
|
||||||
cp->terminal_due = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pp->terminal_check_type == 2)
|
|
||||||
{
|
|
||||||
if (cp->accumulated.tv_sec >= pp->terminal_count)
|
|
||||||
cp->terminal_due = true;
|
|
||||||
}
|
|
||||||
if (cp->terminal_due)
|
|
||||||
{
|
|
||||||
cntr_event(cp, "TERMINAL");
|
|
||||||
make_report(cp);
|
|
||||||
cntr_stop(cp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* poll the physical counter
|
|
||||||
*/
|
|
||||||
int cntr_poll(COUNTER* cp)
|
|
||||||
{
|
|
||||||
char errBuff[2048]={'\0'};
|
|
||||||
unsigned long long current_count_local;
|
|
||||||
int count_delta_local;
|
|
||||||
int error=0;
|
|
||||||
|
|
||||||
/* read the value from the hardware counter to a temp */
|
|
||||||
++cp->poll_counter;
|
|
||||||
HCTR_TEST(hdio_read(cp->private_data, ¤t_count_local));
|
|
||||||
dprintf(0, "cntr_poll = %llu @ %s\n",
|
|
||||||
current_count_local,
|
|
||||||
make_timestamp(&cp->current_time));
|
|
||||||
|
|
||||||
SAMPLE* sp = cur_sample(cp);
|
|
||||||
SAMPLE* psp = prv_sample(cp, 1);
|
|
||||||
|
|
||||||
/* calculate the number since last time and save new value */
|
|
||||||
count_delta_local = current_count_local - cp->count64;
|
|
||||||
cp->count64 = current_count_local;
|
|
||||||
sp->num_polls += 1;
|
|
||||||
/*
|
|
||||||
* If the counter is running and not gated increment the count and runtime
|
|
||||||
*/
|
|
||||||
if (cp->state == counter_running &&
|
|
||||||
!(cp->params.range_gate_enable && cp->range_gated))
|
|
||||||
{
|
|
||||||
if (cp->params.direction == COUNT_DOWN)
|
|
||||||
{
|
|
||||||
cp->current_count -= count_delta_local;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cp->current_count += count_delta_local;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Add the time difference to the accumulated time
|
|
||||||
*/
|
|
||||||
cp->accumulated.tv_sec += cp->current_time.tv_sec - sp->timestamp.tv_sec;
|
|
||||||
/* prevent negative tv_usec by borrowing one second in microseconds */
|
|
||||||
cp->accumulated.tv_usec += 1000000;
|
|
||||||
cp->accumulated.tv_usec += cp->current_time.tv_usec;
|
|
||||||
cp->accumulated.tv_usec -= sp->timestamp.tv_usec;
|
|
||||||
if (cp->accumulated.tv_usec >= 1000000)
|
|
||||||
{
|
|
||||||
/* carry the seconds */
|
|
||||||
cp->accumulated.tv_sec += cp->accumulated.tv_usec / 1000000;
|
|
||||||
cp->accumulated.tv_usec %= 1000000;
|
|
||||||
}
|
|
||||||
/* pay back the borrowed second */
|
|
||||||
cp->accumulated.tv_sec -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate and check the count-rate between polls */
|
|
||||||
sp->count_delta = cp->count64 - sp->count64;
|
|
||||||
sp->time_delta = time_diff(&cp->current_time, &sp->timestamp);
|
|
||||||
sp->counter_rate = (double) sp->count_delta / sp->time_delta;
|
|
||||||
cntr_range_check(cp, 2); /* poll range check */
|
|
||||||
|
|
||||||
cp->previous_time = cp->current_time;
|
|
||||||
|
|
||||||
/* save counter values in the sample */
|
|
||||||
sp->counter_value = cp->current_count;
|
|
||||||
sp->count64 = cp->count64;
|
|
||||||
sp->timestamp = cp->current_time;
|
|
||||||
|
|
||||||
/* calculate the count-rate for this sample so far */
|
|
||||||
sp->count_delta = sp->count64 - psp->count64;
|
|
||||||
sp->time_delta = time_diff(&sp->timestamp, &psp->timestamp);
|
|
||||||
sp->counter_rate = (double) sp->count_delta / sp->time_delta;
|
|
||||||
|
|
||||||
/* test for the occurrence of a terminal event */
|
|
||||||
cntr_test_term(cp);
|
|
||||||
|
|
||||||
/* check if it is time to roll the sample */
|
|
||||||
if (cntr_time_to_next_sample(cp) <= 0)
|
|
||||||
{
|
|
||||||
/* check if it is time to roll the report */
|
|
||||||
if (cntr_time_to_next_report(cp) <= 0)
|
|
||||||
{
|
|
||||||
make_report(cp);
|
|
||||||
cntr_range_check(cp, 0); /* report range check */
|
|
||||||
cntr_report(cp);
|
|
||||||
}
|
|
||||||
cntr_range_check(cp, 1); /* sample range check */
|
|
||||||
cntr_sample(cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
Error:
|
|
||||||
cntr_errmsg(errBuff, sizeof(errBuff));
|
|
||||||
printf("DAQmx Error: %s\n", errBuff);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cntr_term(COUNTER* cp)
|
|
||||||
{
|
|
||||||
if (cp->private_data)
|
|
||||||
{
|
|
||||||
hdio_dtor(&cp->private_data);
|
|
||||||
cp->private_data = NULL;
|
|
||||||
}
|
|
||||||
cp->state = counter_idle;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cntr_fatal(int error)
|
|
||||||
{
|
|
||||||
return hdio_failed(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cntr_errmsg(char* buff, int len)
|
|
||||||
{
|
|
||||||
hdio_errmsg(buff, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
double cntr_time_to_next_report(COUNTER* cp)
|
|
||||||
{
|
|
||||||
uint64 last_report;
|
|
||||||
uint64 timeofday;
|
|
||||||
int timeout;
|
|
||||||
struct timeval now;
|
|
||||||
now = cp->current_time;
|
|
||||||
last_report = 1000 * (uint64) cp->report_timer.tv_sec;
|
|
||||||
last_report += (uint64) cp->report_timer.tv_usec / 1000;
|
|
||||||
timeofday = 1000 * (uint64) now.tv_sec;
|
|
||||||
timeofday += (uint64) now.tv_usec / 1000;
|
|
||||||
timeout = cp->params.poll_period * cp->params.sample_period *
|
|
||||||
cp->params.report_period;
|
|
||||||
if ((last_report / timeout) != (timeofday / timeout))
|
|
||||||
return 0.0;
|
|
||||||
timeout = timeout - timeofday % timeout;
|
|
||||||
return 0.001 * timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
double cntr_time_to_next_sample(COUNTER* cp)
|
|
||||||
{
|
|
||||||
uint64 last_sample;
|
|
||||||
uint64 timeofday;
|
|
||||||
int timeout;
|
|
||||||
struct timeval now;
|
|
||||||
now = cp->current_time;
|
|
||||||
last_sample = 1000 * (uint64) cp->sample_timer.tv_sec;
|
|
||||||
last_sample += (uint64) cp->sample_timer.tv_usec / 1000;
|
|
||||||
timeofday = 1000 * (uint64) now.tv_sec;
|
|
||||||
timeofday += (uint64) now.tv_usec / 1000;
|
|
||||||
timeout = cp->params.poll_period * cp->params.sample_period;
|
|
||||||
if ((last_sample / timeout) != (timeofday / timeout))
|
|
||||||
return 0.0;
|
|
||||||
timeout = timeout - timeofday % timeout;
|
|
||||||
return 0.001 * timeout;
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
#ifndef _COUNTER_H_
|
|
||||||
#define _COUNTER_H_
|
|
||||||
|
|
||||||
#define SAMPLE_ARRAY_SZ 1000
|
|
||||||
|
|
||||||
#include "utility.h"
|
|
||||||
#include "params.h"
|
|
||||||
|
|
||||||
typedef enum counter_state_t
|
|
||||||
{
|
|
||||||
/** The counter has not yet been created or has been destroyed */
|
|
||||||
counter_idle = 0,
|
|
||||||
/** The counter has not yet been started or has been stopped */
|
|
||||||
counter_stopped,
|
|
||||||
/** The counter is counting */
|
|
||||||
counter_running,
|
|
||||||
/** the counter has been paused */
|
|
||||||
counter_paused
|
|
||||||
} COUNTER_STATE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logical counter sample
|
|
||||||
*/
|
|
||||||
typedef struct sample_t
|
|
||||||
{
|
|
||||||
/** sample number */
|
|
||||||
int sample_counter;
|
|
||||||
/** poll number */
|
|
||||||
int poll_counter;
|
|
||||||
/** time of last read */
|
|
||||||
struct timeval timestamp;
|
|
||||||
/** logical counter value */
|
|
||||||
uint64 counter_value;
|
|
||||||
/** extended physical counter value */
|
|
||||||
uint64 count64;
|
|
||||||
/** counts between current and previous */
|
|
||||||
int count_delta;
|
|
||||||
/** number of polls */
|
|
||||||
int num_polls;
|
|
||||||
/** this data is valid */
|
|
||||||
bool valid;
|
|
||||||
/** time between current and previous */
|
|
||||||
double time_delta;
|
|
||||||
/** computed */
|
|
||||||
double counter_rate;
|
|
||||||
/** computed */
|
|
||||||
double average_rate;
|
|
||||||
/** computed */
|
|
||||||
double minimum_rate;
|
|
||||||
/** computed */
|
|
||||||
double maximum_rate;
|
|
||||||
} SAMPLE, *pSAMPLE;
|
|
||||||
|
|
||||||
typedef struct counter_t
|
|
||||||
{
|
|
||||||
char name[64];
|
|
||||||
COUNTER_STATE state;
|
|
||||||
/** time of last start */
|
|
||||||
struct timeval start_time;
|
|
||||||
/** time of last stop */
|
|
||||||
struct timeval stop_time;
|
|
||||||
/** time of this read */
|
|
||||||
struct timeval current_time;
|
|
||||||
/** time of last read */
|
|
||||||
struct timeval previous_time;
|
|
||||||
/** time of next sample closure */
|
|
||||||
struct timeval sample_timer;
|
|
||||||
/** time of next report generation */
|
|
||||||
struct timeval report_timer;
|
|
||||||
/** accumulated runtime */
|
|
||||||
struct timeval accumulated;
|
|
||||||
/** Current value of logical 64-bit counter */
|
|
||||||
uint64 current_count;
|
|
||||||
/** an array of samples to be used for reporting */
|
|
||||||
SAMPLE sample_array[SAMPLE_ARRAY_SZ];
|
|
||||||
/** calculated values for reporting */
|
|
||||||
SAMPLE report;
|
|
||||||
/** index into the sample array of the current sample */
|
|
||||||
int sample_index;
|
|
||||||
/** number of polls */
|
|
||||||
int poll_counter;
|
|
||||||
/** number of samples */
|
|
||||||
int sample_counter;
|
|
||||||
/** is a terminal count exception due */
|
|
||||||
bool terminal_due;
|
|
||||||
/** error: 0:none, 1:low, 2:high */
|
|
||||||
int range_error;
|
|
||||||
/** is a range exception gate active */
|
|
||||||
bool range_gated;
|
|
||||||
/** Extended physical counter value */
|
|
||||||
uint64 count64;
|
|
||||||
/** Control parameters */
|
|
||||||
PARAMETERS params;
|
|
||||||
/** active value of parameter output_line */
|
|
||||||
int output_line;
|
|
||||||
struct counter_private_t* private_data;
|
|
||||||
} COUNTER, *pCOUNTER;
|
|
||||||
|
|
||||||
extern COUNTER counter;
|
|
||||||
|
|
||||||
void make_report(COUNTER* cp);
|
|
||||||
void cntr_sample(COUNTER* cp);
|
|
||||||
void cntr_send(COUNTER* cp, int n);
|
|
||||||
void cntr_read(COUNTER* cp, int n);
|
|
||||||
void cntr_print(COUNTER* cp, FILE* fd);
|
|
||||||
void cntr_report(COUNTER* cp);
|
|
||||||
int cntr_init(COUNTER* cp, char* name);
|
|
||||||
int cntr_start(COUNTER *cp);
|
|
||||||
int cntr_stop(COUNTER *cp);
|
|
||||||
int cntr_pause(COUNTER *cp);
|
|
||||||
int cntr_resume(COUNTER *cp);
|
|
||||||
int cntr_poll(COUNTER* cp);
|
|
||||||
void cntr_term(COUNTER* cp);
|
|
||||||
bool cntr_fatal(int error);
|
|
||||||
void cntr_errmsg(char* buff, int len);
|
|
||||||
double cntr_time_to_next_sample(COUNTER* cp);
|
|
||||||
double cntr_time_to_next_report(COUNTER* cp);
|
|
||||||
#endif
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
#include "hdio.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <NIDAQmx.h>
|
|
||||||
|
|
||||||
#define SAMPLE_COUNT 1
|
|
||||||
#define BUFFER_SIZE 96
|
|
||||||
#define PORT_RANGE "Dev2/line0:95"
|
|
||||||
#define READ_TIMEOUT 2.0
|
|
||||||
|
|
||||||
#define DAQmxErrChk(functionCall) \
|
|
||||||
do { if( DAQmxFailed(error=(functionCall)) ) \
|
|
||||||
goto Error; } while(0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This structure encapsulates the data that is private to
|
|
||||||
* the implementation of the NI DAQ counter interface
|
|
||||||
*/
|
|
||||||
typedef struct counter_private_t
|
|
||||||
{
|
|
||||||
/** NIDAQ opaque task handle */
|
|
||||||
TaskHandle taskHandle;
|
|
||||||
/** Actual physical data value, as returned by NIDAQ read function */
|
|
||||||
uInt8 data[BUFFER_SIZE];
|
|
||||||
/** previous physical data value */
|
|
||||||
uInt8 old_data[BUFFER_SIZE];
|
|
||||||
/** NIDAQ device number of card */
|
|
||||||
int device_number;
|
|
||||||
/** number of samples read */
|
|
||||||
int32 numRead;
|
|
||||||
/** number of bytes per sample */
|
|
||||||
int32 bytesPerSamp;
|
|
||||||
} COUNTER_PRIVATE;
|
|
||||||
|
|
||||||
|
|
||||||
int hdio_ctor(const char* device_name, pHDIO* ptr)
|
|
||||||
{
|
|
||||||
int error = 0;
|
|
||||||
bool flag = false;
|
|
||||||
char text_string[] = "dev1/line0:7";
|
|
||||||
const char *name;
|
|
||||||
const char *text;
|
|
||||||
|
|
||||||
*ptr = (COUNTER_PRIVATE*) malloc(sizeof(COUNTER_PRIVATE));
|
|
||||||
memset(*ptr, 0, sizeof(COUNTER_PRIVATE));
|
|
||||||
|
|
||||||
name = device_name;
|
|
||||||
text = text_string;
|
|
||||||
while (name && *name)
|
|
||||||
{
|
|
||||||
if (isspace(*name))
|
|
||||||
++name;
|
|
||||||
else if (*name >= '0' && *name <= '7')
|
|
||||||
{
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
(*ptr)->device_number = *name - '0';
|
|
||||||
flag = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (tolower(*name) != *text)
|
|
||||||
{
|
|
||||||
/* TODO error */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++name;
|
|
||||||
++text;
|
|
||||||
}
|
|
||||||
/*********************************************/
|
|
||||||
// Create a DAQmx task
|
|
||||||
/*********************************************/
|
|
||||||
DAQmxErrChk (DAQmxCreateTask("",&(*ptr)->taskHandle));
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
// Create a DAQmx port within the task
|
|
||||||
/*********************************************/
|
|
||||||
DAQmxErrChk (DAQmxCreateDIChan((*ptr)->taskHandle,
|
|
||||||
PORT_RANGE,
|
|
||||||
"",
|
|
||||||
DAQmx_Val_ChanPerLine));
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
// Start the DAQmx task
|
|
||||||
/*********************************************/
|
|
||||||
DAQmxErrChk (DAQmxStartTask((*ptr)->taskHandle));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
Error:
|
|
||||||
free(*ptr);
|
|
||||||
*ptr = NULL;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hdio_read(pHDIO hdio, unsigned long long* value)
|
|
||||||
{
|
|
||||||
int error = 0;
|
|
||||||
error = 0;
|
|
||||||
hdio->numRead = 0;
|
|
||||||
hdio->bytesPerSamp = 0;
|
|
||||||
/*********************************************/
|
|
||||||
// DAQmx Read Code
|
|
||||||
/*********************************************/
|
|
||||||
error = DAQmxReadDigitalLines (hdio->taskHandle,
|
|
||||||
SAMPLE_COUNT,
|
|
||||||
READ_TIMEOUT,
|
|
||||||
DAQmx_Val_GroupByScanNumber,
|
|
||||||
hdio->data,
|
|
||||||
BUFFER_SIZE,
|
|
||||||
&hdio->numRead,
|
|
||||||
&hdio->bytesPerSamp,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (error == DAQmxErrorSamplesNotYetAvailable)
|
|
||||||
{
|
|
||||||
printf("Timeout, reading raw data\n");
|
|
||||||
error = 0;
|
|
||||||
}
|
|
||||||
else if (hdio_failed(error))
|
|
||||||
goto Error;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO copy the data
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
Error:
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hdio_dtor(pHDIO* hdio)
|
|
||||||
{
|
|
||||||
if( hdio && *hdio && (*hdio)->taskHandle!=0 )
|
|
||||||
{
|
|
||||||
/*********************************************/
|
|
||||||
// DAQmx Stop Code
|
|
||||||
/*********************************************/
|
|
||||||
DAQmxStopTask((*hdio)->taskHandle);
|
|
||||||
DAQmxClearTask((*hdio)->taskHandle);
|
|
||||||
}
|
|
||||||
(*hdio)->taskHandle = 0;
|
|
||||||
free (*hdio);
|
|
||||||
*hdio = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hdio_failed(int error)
|
|
||||||
{
|
|
||||||
if (DAQmxFailed(error))
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hdio_errmsg(char* buff, int len)
|
|
||||||
{
|
|
||||||
*buff = '\0';
|
|
||||||
DAQmxGetExtendedErrorInfo(buff, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* This is an encapsulation of a National Instruments counter.
|
|
||||||
*
|
|
||||||
* It presents a simple 64-bit counter abstraction. When the counter is
|
|
||||||
* created, it commences counting at zero until it is destroyed.
|
|
||||||
*
|
|
||||||
* The counter can be read and returns a 64-bit unsigned value.
|
|
||||||
*/
|
|
||||||
#ifndef _HDIO_H_
|
|
||||||
#define _HDIO_H_
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
struct counter_private_t;
|
|
||||||
typedef struct counter_private_t* pHDIO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a 64-bit counter and start it counting
|
|
||||||
*
|
|
||||||
* \param device_name the name of the device (e.g. "dev1/ctr0")
|
|
||||||
* \param ptr address of pointer to opaque private data structure
|
|
||||||
*
|
|
||||||
* \return
|
|
||||||
* 0 OK
|
|
||||||
* !0 Error
|
|
||||||
*/
|
|
||||||
int hdio_ctor(const char* device_name, pHDIO* ptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the value of the 64-bit counter
|
|
||||||
*
|
|
||||||
* \param hdio pointer to opaque private data structure
|
|
||||||
* \param value address of unsigned 64-bit value to receive the output
|
|
||||||
*
|
|
||||||
* \return
|
|
||||||
* 0 OK
|
|
||||||
* !0 Error
|
|
||||||
*/
|
|
||||||
int hdio_read(pHDIO hdio, unsigned long long* value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables external sync on designated (up/down) line
|
|
||||||
*
|
|
||||||
* \param hdio pointer to opaque private data structure
|
|
||||||
* \param value to be written to the associated line
|
|
||||||
* < 0 disconnect
|
|
||||||
* = 0 logic low
|
|
||||||
* > 0 logic high
|
|
||||||
*/
|
|
||||||
int hdio_outp(pHDIO hdio, int value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables external sync on designated (up/down) line
|
|
||||||
*
|
|
||||||
* \param hdio pointer to opaque private data structure
|
|
||||||
* \param external true for external sync, false for internal
|
|
||||||
*/
|
|
||||||
void hdio_sync(pHDIO hdio, bool external);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy the 64-bit counter
|
|
||||||
*
|
|
||||||
* \param ptr address of pointer to opaque private data structure
|
|
||||||
*
|
|
||||||
* \return
|
|
||||||
* 0 OK
|
|
||||||
* !0 Error
|
|
||||||
*/
|
|
||||||
int hdio_dtor(pHDIO* hdio);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests returned error value to see if it represents failure
|
|
||||||
*
|
|
||||||
* \param error a value returned from another hdio function
|
|
||||||
*
|
|
||||||
* \return
|
|
||||||
* true the error was a failure
|
|
||||||
* false the error was not a failure (warning)
|
|
||||||
*/
|
|
||||||
bool hdio_failed(int error);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a textual representation of the most recent error
|
|
||||||
*
|
|
||||||
* \param buff a pointer to the buffer to receive the text
|
|
||||||
* \param len the length of the provided buffer
|
|
||||||
*/
|
|
||||||
void hdio_errmsg(char* buff, int len);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
501
site_ansto/hardsup/Digital/hware.c
Normal file
501
site_ansto/hardsup/Digital/hware.c
Normal file
@@ -0,0 +1,501 @@
|
|||||||
|
/* vim: ts=8 sts=2 sw=2 cindent
|
||||||
|
*/
|
||||||
|
#include "hware.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#define DEFAULT_DEVICE "dev2/port0"
|
||||||
|
|
||||||
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||||
|
#define DEVICE_ID_NUMBER "0x7085"
|
||||||
|
#define DAQmxFailed(e) ((e) != 0)
|
||||||
|
#define DAQmxGetExtendedErrorInfo(b, l) snprintf(b, l, "BAD")
|
||||||
|
#include <osiBus.h>
|
||||||
|
#include <tstaticDIO.h>
|
||||||
|
typedef unsigned long uInt32;
|
||||||
|
/**
|
||||||
|
* This structure contains the data for the PCI-6602 card
|
||||||
|
*/
|
||||||
|
typedef struct card_t
|
||||||
|
{
|
||||||
|
iBus* bus;
|
||||||
|
tAddressSpace Bar1;
|
||||||
|
tstaticDIO *board;
|
||||||
|
unsigned char dev_mask;
|
||||||
|
} CARD;
|
||||||
|
#else
|
||||||
|
#include <NIDAQmx.h>
|
||||||
|
|
||||||
|
#define SAMPLE_COUNT 1
|
||||||
|
#define PORT_RANGE "Dev2/port0"
|
||||||
|
#define READ_TIMEOUT 2.0
|
||||||
|
#define WRITE_TIMEOUT 2.0
|
||||||
|
|
||||||
|
#define DAQmxErrChk(functionCall) \
|
||||||
|
do { if( DAQmxFailed(error=(functionCall)) ) \
|
||||||
|
goto Error; } while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 96
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This structure encapsulates the data that is private to
|
||||||
|
* the implementation of the device
|
||||||
|
*/
|
||||||
|
typedef struct device_private_t
|
||||||
|
{
|
||||||
|
/** NIDAQ device number of card */
|
||||||
|
int card_number;
|
||||||
|
/** NI channel number on card */
|
||||||
|
int channel_number;
|
||||||
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||||
|
HWARE_VALUE value;
|
||||||
|
CARD* card;
|
||||||
|
#else
|
||||||
|
/** NIDAQ opaque task handle */
|
||||||
|
TaskHandle taskHandle;
|
||||||
|
/** NIDAQ opaque task handle for digital output */
|
||||||
|
TaskHandle taskHandle_dout;
|
||||||
|
/** Actual physical data value, as returned by NIDAQ read function */
|
||||||
|
uInt8 data[BUFFER_SIZE];
|
||||||
|
/** previous physical data value */
|
||||||
|
uInt8 old_data[BUFFER_SIZE];
|
||||||
|
/** number of samples read */
|
||||||
|
int32 numRead;
|
||||||
|
/** number of bytes per sample */
|
||||||
|
int32 bytesPerSamp;
|
||||||
|
#endif
|
||||||
|
} DEVICE_PRIVATE;
|
||||||
|
|
||||||
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||||
|
static void initMite(iBus *bus);
|
||||||
|
|
||||||
|
static CARD* card[10];
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int hware_ctor(const char* device_name, pHWARE* ptr)
|
||||||
|
{
|
||||||
|
pHWARE hware = NULL;
|
||||||
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||||
|
CARD* pci = NULL;
|
||||||
|
#endif
|
||||||
|
int error = 0;
|
||||||
|
bool flag = false;
|
||||||
|
char text_string[] = DEFAULT_DEVICE;
|
||||||
|
const char *name;
|
||||||
|
const char *text;
|
||||||
|
|
||||||
|
hware = (DEVICE_PRIVATE*) malloc(sizeof(DEVICE_PRIVATE));
|
||||||
|
*ptr = hware;
|
||||||
|
memset(hware, 0, sizeof(DEVICE_PRIVATE));
|
||||||
|
|
||||||
|
name = device_name;
|
||||||
|
text = text_string;
|
||||||
|
while (name && *name)
|
||||||
|
{
|
||||||
|
if (isspace(*name))
|
||||||
|
++name;
|
||||||
|
else if (*name >= '0' && *name <= '9')
|
||||||
|
{
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
hware->channel_number = *name - '0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hware->card_number = *name - '0';
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tolower(*name) != *text)
|
||||||
|
{
|
||||||
|
/* TODO error */
|
||||||
|
printf("Device name error: %s (%d,%d)\n",
|
||||||
|
device_name,
|
||||||
|
hware->channel_number,
|
||||||
|
hware->card_number);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++name;
|
||||||
|
++text;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||||
|
if (card[hware->card_number] == NULL)
|
||||||
|
{
|
||||||
|
char local_name[40] = "PXI6::1::INSTR";
|
||||||
|
FILE* fd = fopen("/proc/nirlpk/lsdaq", "r");
|
||||||
|
if (fd)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
int count = 0;
|
||||||
|
char line[100];
|
||||||
|
while (fgets(line, 100, fd))
|
||||||
|
{
|
||||||
|
if (strstr(line, DEVICE_ID_NUMBER))
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
name = strstr(line, "PXI");
|
||||||
|
if (name && count == hware->card_number)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
strcpy(local_name, name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
// TODO error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
card[hware->card_number] = (CARD*) malloc(sizeof(CARD));
|
||||||
|
memset(card[hware->card_number], 0, sizeof(CARD));
|
||||||
|
pci = card[hware->card_number];
|
||||||
|
hware->card = pci;
|
||||||
|
|
||||||
|
pci->bus = acquireBoard((tChar*) local_name /* "PXI6::1::INSTR" */);
|
||||||
|
|
||||||
|
if(pci->bus == NULL)
|
||||||
|
{
|
||||||
|
printf("Error accessing the PCI device \"%s\". Exiting.\n",
|
||||||
|
local_name);
|
||||||
|
error = 1;
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Intitialise Mite Chip.
|
||||||
|
|
||||||
|
initMite(pci->bus);
|
||||||
|
|
||||||
|
pci->Bar1 = pci->bus->createAddressSpace(kPCI_BAR1);
|
||||||
|
pci->board = new tstaticDIO(pci->Bar1);
|
||||||
|
//
|
||||||
|
//Configure All Digital lines as Input or Output
|
||||||
|
pci->board->IOSelect0.writeDirection(pci->board->IOSelect0.kDirectionInput);
|
||||||
|
pci->board->IOSelect1.writeDirection(pci->board->IOSelect1.kDirectionInput);
|
||||||
|
pci->board->IOSelect2.writeDirection(pci->board->IOSelect2.kDirectionInput);
|
||||||
|
pci->board->IOSelect3.writeDirection(pci->board->IOSelect3.kDirectionOutput);
|
||||||
|
|
||||||
|
pci->board->IOSelect4.writeDirection(pci->board->IOSelect4.kDirectionInput);
|
||||||
|
pci->board->IOSelect5.writeDirection(pci->board->IOSelect5.kDirectionInput);
|
||||||
|
pci->board->IOSelect6.writeDirection(pci->board->IOSelect6.kDirectionInput);
|
||||||
|
pci->board->IOSelect7.writeDirection(pci->board->IOSelect7.kDirectionOutput);
|
||||||
|
|
||||||
|
pci->board->IOSelect8.writeDirection(pci->board->IOSelect8.kDirectionInput);
|
||||||
|
pci->board->IOSelect9.writeDirection(pci->board->IOSelect9.kDirectionInput);
|
||||||
|
pci->board->IOSelect10.writeDirection(pci->board->IOSelect10.kDirectionInput);
|
||||||
|
pci->board->IOSelect11.writeDirection(pci->board->IOSelect11.kDirectionOutput);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pci = card[hware->card_number];
|
||||||
|
hware->card = pci;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the counter on this card as in-use
|
||||||
|
if (pci->dev_mask & (1 << hware->channel_number))
|
||||||
|
{
|
||||||
|
// TODO error
|
||||||
|
}
|
||||||
|
pci->dev_mask |= 1 << hware->channel_number;
|
||||||
|
|
||||||
|
#else
|
||||||
|
char local_name[40] = "dev2/port0";
|
||||||
|
/*********************************************/
|
||||||
|
// Create a DAQmx task
|
||||||
|
/*********************************************/
|
||||||
|
DAQmxErrChk (DAQmxCreateTask("",&hware->taskHandle));
|
||||||
|
DAQmxErrChk (DAQmxCreateTask("",&hware->taskHandle_dout));
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
// Create a DAQmx device within the task
|
||||||
|
/*********************************************/
|
||||||
|
snprintf(local_name, sizeof(local_name), "dev%d/line%d:%d",
|
||||||
|
hware->card_number,
|
||||||
|
hware->channel_number * 32,
|
||||||
|
hware->channel_number * 32 + 23);
|
||||||
|
DAQmxErrChk (
|
||||||
|
DAQmxCreateDIChan(hware->taskHandle,
|
||||||
|
local_name,
|
||||||
|
"",
|
||||||
|
DAQmx_Val_ChanForAllLines));
|
||||||
|
fprintf(stderr, "Input %s\n", local_name);
|
||||||
|
snprintf(local_name, sizeof(local_name), "dev%d/line%d:%d",
|
||||||
|
hware->card_number,
|
||||||
|
hware->channel_number * 32 + 24,
|
||||||
|
hware->channel_number * 32 + 31);
|
||||||
|
DAQmxErrChk (
|
||||||
|
DAQmxCreateDOChan(hware->taskHandle_dout,
|
||||||
|
local_name,
|
||||||
|
"",
|
||||||
|
DAQmx_Val_ChanForAllLines));
|
||||||
|
fprintf(stderr, "Output %s\n", local_name);
|
||||||
|
/*********************************************/
|
||||||
|
// Start the DAQmx task
|
||||||
|
/*********************************************/
|
||||||
|
DAQmxErrChk (DAQmxStartTask(hware->taskHandle));
|
||||||
|
DAQmxErrChk (DAQmxStartTask(hware->taskHandle_dout));
|
||||||
|
#endif
|
||||||
|
hware_write(hware, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
Error:
|
||||||
|
free(hware);
|
||||||
|
*ptr = NULL;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hware_read(pHWARE hware, HWARE_VALUE* value)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
*value = 0;
|
||||||
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||||
|
CARD* pci = hware->card;
|
||||||
|
HWARE_VALUE uPattern;
|
||||||
|
switch (hware->channel_number)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
uPattern = pci->board->IOPort0Data.readRegister();
|
||||||
|
uPattern |= pci->board->IOPort1Data.readRegister() << 8;
|
||||||
|
uPattern |= pci->board->IOPort2Data.readRegister() << 16;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
uPattern = pci->board->IOPort4Data.readRegister();
|
||||||
|
uPattern |= pci->board->IOPort5Data.readRegister() << 8;
|
||||||
|
uPattern |= pci->board->IOPort6Data.readRegister() << 16;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
uPattern = pci->board->IOPort8Data.readRegister();
|
||||||
|
uPattern |= pci->board->IOPort9Data.readRegister() << 8;
|
||||||
|
uPattern |= pci->board->IOPort10Data.readRegister() << 16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*value = uPattern;
|
||||||
|
#else
|
||||||
|
/*********************************************/
|
||||||
|
// DAQmx Read Code
|
||||||
|
/*********************************************/
|
||||||
|
hware->numRead = 0;
|
||||||
|
hware->bytesPerSamp = 0;
|
||||||
|
error = DAQmxReadDigitalLines (hware->taskHandle,
|
||||||
|
SAMPLE_COUNT,
|
||||||
|
READ_TIMEOUT,
|
||||||
|
DAQmx_Val_GroupByScanNumber,
|
||||||
|
hware->data,
|
||||||
|
BUFFER_SIZE,
|
||||||
|
&hware->numRead,
|
||||||
|
&hware->bytesPerSamp,
|
||||||
|
NULL);
|
||||||
|
#if 0
|
||||||
|
if (hware->channel_number == 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fprintf(stderr, "dev:%d.%d, numRead:%d, bytesPerSamp:%d",
|
||||||
|
hware->channel_number,
|
||||||
|
hware->channel_number,
|
||||||
|
(int) hware->numRead,
|
||||||
|
(int) hware->bytesPerSamp);
|
||||||
|
for (i = 0; i < hware->bytesPerSamp; ++i)
|
||||||
|
fprintf(stderr, ", %02x", hware->data[i]);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (error == DAQmxErrorSamplesNotYetAvailable)
|
||||||
|
{
|
||||||
|
printf("Timeout, reading raw data\n");
|
||||||
|
error = 0;
|
||||||
|
}
|
||||||
|
else if (hware_failed(error))
|
||||||
|
goto Error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
HWARE_VALUE uPattern;
|
||||||
|
uPattern = 0;
|
||||||
|
for (i = 0; i < hware->bytesPerSamp; ++i)
|
||||||
|
if (hware->data[i])
|
||||||
|
uPattern |= 1 << i;
|
||||||
|
*value = uPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
Error:
|
||||||
|
#endif
|
||||||
|
return error;
|
||||||
|
} /* hware_read */
|
||||||
|
|
||||||
|
int hware_write(pHWARE hware, HWARE_VALUE value)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||||
|
CARD* pci = hware->card;
|
||||||
|
switch (hware->channel_number)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
pci->board->IOPort3Data.writeRegister(value & 0xFF);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pci->board->IOPort7Data.writeRegister(value & 0xFF);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pci->board->IOPort11Data.writeRegister(value & 0xFF);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/*********************************************/
|
||||||
|
// DAQmx Write Code
|
||||||
|
/*********************************************/
|
||||||
|
hware->bytesPerSamp = 8;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
// copy the data
|
||||||
|
for (i = 0; i < hware->bytesPerSamp; ++i)
|
||||||
|
hware->data[i] = (value >> i) & 1;
|
||||||
|
}
|
||||||
|
error = DAQmxWriteDigitalLines(hware->taskHandle_dout,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
WRITE_TIMEOUT,
|
||||||
|
DAQmx_Val_GroupByChannel,
|
||||||
|
hware->data,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
#if 1
|
||||||
|
if (hware->channel_number == 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fprintf(stderr, "dev:%d.%d, Write: %d",
|
||||||
|
hware->card_number,
|
||||||
|
hware->channel_number,
|
||||||
|
(int) hware->bytesPerSamp);
|
||||||
|
for (i = 0; i < hware->bytesPerSamp; ++i)
|
||||||
|
fprintf(stderr, ", %02x", hware->data[i]);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (hware_failed(error))
|
||||||
|
goto Error;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
Error:
|
||||||
|
#endif
|
||||||
|
return error;
|
||||||
|
} /* hware_write */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select the source
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shut down the channel
|
||||||
|
*/
|
||||||
|
int hware_dtor(pHWARE* ptr)
|
||||||
|
{
|
||||||
|
if (ptr && *ptr)
|
||||||
|
{
|
||||||
|
pHWARE hware = *ptr;
|
||||||
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||||
|
CARD* pci = hware->card;
|
||||||
|
switch (hware->channel_number)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci->dev_mask &= ~(1 << hware->channel_number);
|
||||||
|
if (pci->dev_mask == 0)
|
||||||
|
{
|
||||||
|
delete pci->board;
|
||||||
|
pci->bus->destroyAddressSpace(pci->Bar1);
|
||||||
|
|
||||||
|
releaseBoard(pci->bus);
|
||||||
|
card[hware->card_number] = NULL;
|
||||||
|
free(pci);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (hware->taskHandle != 0)
|
||||||
|
{
|
||||||
|
/*********************************************/
|
||||||
|
// DAQmx Stop Code
|
||||||
|
/*********************************************/
|
||||||
|
DAQmxStopTask(hware->taskHandle);
|
||||||
|
DAQmxClearTask(hware->taskHandle);
|
||||||
|
hware->taskHandle = 0;
|
||||||
|
}
|
||||||
|
if (hware->taskHandle_dout != 0)
|
||||||
|
{
|
||||||
|
/*********************************************/
|
||||||
|
// DAQmx Stop Code
|
||||||
|
/*********************************************/
|
||||||
|
DAQmxStopTask(hware->taskHandle_dout);
|
||||||
|
DAQmxClearTask(hware->taskHandle_dout);
|
||||||
|
hware->taskHandle_dout = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* release the storage */
|
||||||
|
free(hware);
|
||||||
|
*ptr = NULL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hware_failed(int error)
|
||||||
|
{
|
||||||
|
if (DAQmxFailed(error))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hware_errmsg(char* buff, int len)
|
||||||
|
{
|
||||||
|
*buff = '\0';
|
||||||
|
DAQmxGetExtendedErrorInfo(buff, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||||
|
//
|
||||||
|
//Tell the MITE to link the BAR1 address to the DAQ Board
|
||||||
|
//You must initialize the MITE before you write to the rest of the PCI board
|
||||||
|
void initMite(iBus *bus)
|
||||||
|
{
|
||||||
|
tAddressSpace Bar0;
|
||||||
|
u32 physicalBar1;
|
||||||
|
|
||||||
|
//Skip MITE initialization for PCMCIA boards
|
||||||
|
//(which do not have a MITE DMA controller)
|
||||||
|
if(!bus->get(kIsPciPxiBus,0)) return;
|
||||||
|
|
||||||
|
Bar0 = bus->createAddressSpace(kPCI_BAR0);
|
||||||
|
|
||||||
|
//Get the physical address of the DAQ board
|
||||||
|
physicalBar1 = bus->get(kBusAddressPhysical,kPCI_BAR1);
|
||||||
|
//Tell the MITE to enable BAR1, where the rest of the board's registers are
|
||||||
|
Bar0.write32(0xC0, (physicalBar1 & 0xffffff00L) | 0x80);
|
||||||
|
|
||||||
|
bus->destroyAddressSpace(Bar0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
87
site_ansto/hardsup/Digital/hware.h
Normal file
87
site_ansto/hardsup/Digital/hware.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* This is an encapsulation of a National Instruments DIO port.
|
||||||
|
*
|
||||||
|
* It presents a simple device abstraction.
|
||||||
|
*
|
||||||
|
* The device can be read and returns a 32-bit unsigned value.
|
||||||
|
*/
|
||||||
|
#ifndef _HWARE_H_
|
||||||
|
#define _HWARE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#else
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct device_private_t;
|
||||||
|
typedef struct device_private_t* pHWARE;
|
||||||
|
typedef unsigned int HWARE_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a device
|
||||||
|
*
|
||||||
|
* \param card_name the name of the device (e.g. "dev1/port0")
|
||||||
|
* \param ptr address of pointer to opaque private data structure
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* 0 OK
|
||||||
|
* !0 Error
|
||||||
|
*/
|
||||||
|
int hware_ctor(const char* card_name, pHWARE* ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the value of the device
|
||||||
|
*
|
||||||
|
* \param hware pointer to opaque private data structure
|
||||||
|
* \param value address of value to receive the output
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* 0 OK
|
||||||
|
* !0 Error
|
||||||
|
*/
|
||||||
|
int hware_read(pHWARE hware, HWARE_VALUE* value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the value of the device
|
||||||
|
*
|
||||||
|
* \param hware pointer to opaque private data structure
|
||||||
|
* \param value to be written to the device
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* 0 OK
|
||||||
|
* !0 Error
|
||||||
|
*/
|
||||||
|
int hware_write(pHWARE hware, HWARE_VALUE value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the device
|
||||||
|
*
|
||||||
|
* \param ptr address of pointer to opaque private data structure
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* 0 OK
|
||||||
|
* !0 Error
|
||||||
|
*/
|
||||||
|
int hware_dtor(pHWARE* hware);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests returned error value to see if it represents failure
|
||||||
|
*
|
||||||
|
* \param error a value returned from another hware function
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* true the error was a failure
|
||||||
|
* false the error was not a failure (warning)
|
||||||
|
*/
|
||||||
|
bool hware_failed(int error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a textual representation of the most recent error
|
||||||
|
*
|
||||||
|
* \param buff a pointer to the buffer to receive the text
|
||||||
|
* \param len the length of the provided buffer
|
||||||
|
*/
|
||||||
|
void hware_errmsg(char* buff, int len);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Reference in New Issue
Block a user