renamed to be consistent with digital input driver
r1203 | dcl | 2006-10-30 12:22:45 +1100 (Mon, 30 Oct 2006) | 2 lines
This commit is contained in:
@@ -1,683 +0,0 @@
|
||||
/*
|
||||
* Abstraction of the counter device.
|
||||
*
|
||||
*/
|
||||
#include "cntr.h"
|
||||
#include "params.h"
|
||||
#include "sock.h"
|
||||
#include "hctr.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define HCTR_TEST(functionCall) \
|
||||
if( hctr_failed(error=(functionCall)) ) \
|
||||
goto Error; \
|
||||
else
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
dbg_printf(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);
|
||||
dbg_printf(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)
|
||||
{
|
||||
dbg_printf(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** cpp, char* name)
|
||||
{
|
||||
int error = 0;
|
||||
char errBuff[2048]={'\0'};
|
||||
SAMPLE* sp = NULL;
|
||||
COUNTER* cp = (COUNTER*) malloc(sizeof(COUNTER));
|
||||
*cpp = cp;
|
||||
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(hctr_ctor(name, &cp->private_data));
|
||||
sp = cur_sample(cp);
|
||||
sp->timestamp = now;
|
||||
sp->counter_value = cp->current_count;
|
||||
sp->valid = true;
|
||||
cntr_sample(cp);
|
||||
return 0;
|
||||
Error:
|
||||
hctr_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;
|
||||
int value;
|
||||
SAMPLE* sp = NULL;
|
||||
SAMPLE* psp = NULL;
|
||||
PARAMETERS* pp = &cp->params;
|
||||
/* 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;
|
||||
dbg_printf(0, "Setting input line to %d\n", pp->source);
|
||||
HCTR_TEST(hctr_source(cp->private_data, pp->source));
|
||||
cp->source = pp->source;
|
||||
HCTR_TEST(hctr_read(cp->private_data, &cp->count64));
|
||||
sp = cur_sample(cp);
|
||||
sp->timestamp = cp->current_time;
|
||||
sp->counter_value = cp->current_count;
|
||||
psp = prv_sample(cp, 1);
|
||||
psp->timestamp = cp->current_time;
|
||||
psp->counter_value = cp->current_count;
|
||||
make_report(cp);
|
||||
if (pp->output_line == 1)
|
||||
value = 1;
|
||||
else if (pp->output_line == 2)
|
||||
value = 0;
|
||||
else
|
||||
value = -1;
|
||||
dbg_printf(0, "Setting output line to %d\n", value);
|
||||
HCTR_TEST(hctr_outp(cp->private_data, value));
|
||||
return error;
|
||||
Error:
|
||||
cntr_errmsg(errBuff, sizeof(errBuff));
|
||||
printf("DAQmx Error: %s\n", errBuff);
|
||||
return error;
|
||||
}
|
||||
|
||||
int cntr_stop(COUNTER *cp)
|
||||
{
|
||||
int error = 0;
|
||||
char errBuff[2048]={'\0'};
|
||||
PARAMETERS* pp = &cp->params;
|
||||
int value;
|
||||
cp->stop_time = cp->current_time;
|
||||
cp->state = counter_stopped;
|
||||
if (pp->output_line == 1)
|
||||
value = 0;
|
||||
else if (pp->output_line == 2)
|
||||
value = 1;
|
||||
else
|
||||
value = -1;
|
||||
dbg_printf(0, "Setting output line to %d\n", value);
|
||||
HCTR_TEST(hctr_outp(cp->private_data, value));
|
||||
dbg_printf(0, "Setting input line to %d\n", pp->source);
|
||||
HCTR_TEST(hctr_source(cp->private_data, pp->source));
|
||||
cp->source = pp->source;
|
||||
return error;
|
||||
Error:
|
||||
cntr_errmsg(errBuff, sizeof(errBuff));
|
||||
printf("DAQmx Error: %s\n", errBuff);
|
||||
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;
|
||||
}
|
||||
|
||||
int cntr_command(void* counter, const char* command)
|
||||
{
|
||||
COUNTER* cp = static_cast<COUNTER*>(counter);
|
||||
if (strncasecmp(command, "pause", 5) == 0)
|
||||
return cntr_pause(cp);
|
||||
else if (strncasecmp(command, "continue", 8) == 0)
|
||||
return cntr_resume(cp);
|
||||
else if (strncasecmp(command, "resume", 6) == 0)
|
||||
return cntr_resume(cp);
|
||||
else if (strncasecmp(command, "start", 6) == 0)
|
||||
return cntr_start(cp);
|
||||
else if (strncasecmp(command, "stop", 4) == 0)
|
||||
return cntr_stop(cp);
|
||||
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);
|
||||
dbg_printf(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
|
||||
*/
|
||||
// TODO FIXME improve wraparound handling
|
||||
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
|
||||
*/
|
||||
// TODO FIXME improve wraparound handling
|
||||
if (
|
||||
#if 1
|
||||
sp->counter_value >= pp->terminal_count
|
||||
#else
|
||||
(sp->counter_value >= pp->terminal_count &&
|
||||
psp->counter_value < pp->terminal_count) ||
|
||||
(sp->counter_value < psp->counter_value &&
|
||||
psp->counter_value > pp->terminal_count)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
cp->terminal_due = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pp->terminal_check_type == 2)
|
||||
{
|
||||
if ((uint64) 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)
|
||||
{
|
||||
PARAMETERS* pp = &cp->params;
|
||||
char errBuff[2048]={'\0'};
|
||||
unsigned long long current_count_local;
|
||||
int count_delta_local;
|
||||
int error=0;
|
||||
SAMPLE* sp = NULL;
|
||||
SAMPLE* psp = NULL;
|
||||
|
||||
/* read the value from the hardware counter to a temp */
|
||||
++cp->poll_counter;
|
||||
HCTR_TEST(hctr_read(cp->private_data, ¤t_count_local));
|
||||
dbg_printf(0, "cntr_poll = %llu @ %s\n",
|
||||
current_count_local,
|
||||
make_timestamp(&cp->current_time));
|
||||
|
||||
sp = cur_sample(cp);
|
||||
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);
|
||||
}
|
||||
|
||||
/* set the source line */
|
||||
if (cp->source != pp->source)
|
||||
{
|
||||
cp->source = pp->source;
|
||||
HCTR_TEST(hctr_source(cp->private_data, cp->source));
|
||||
}
|
||||
|
||||
/* drive the output line */
|
||||
if (cp->output_line != pp->output_line)
|
||||
{
|
||||
int value;
|
||||
cp->output_line = pp->output_line;
|
||||
if (pp->output_line == 1)
|
||||
{
|
||||
if (cp->state == counter_running || cp->state == counter_paused)
|
||||
value = 1;
|
||||
else
|
||||
value = 0;
|
||||
}
|
||||
else if (pp->output_line == 2)
|
||||
{
|
||||
if (cp->state == counter_running || cp->state == counter_paused)
|
||||
value = 0;
|
||||
else
|
||||
value = 1;
|
||||
}
|
||||
else
|
||||
value = -1;
|
||||
HCTR_TEST(hctr_outp(cp->private_data, value));
|
||||
}
|
||||
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)
|
||||
{
|
||||
hctr_dtor(&cp->private_data);
|
||||
cp->private_data = NULL;
|
||||
}
|
||||
cp->state = counter_idle;
|
||||
}
|
||||
|
||||
bool cntr_fatal(int error)
|
||||
{
|
||||
return hctr_failed(error);
|
||||
}
|
||||
|
||||
void cntr_errmsg(char* buff, int len)
|
||||
{
|
||||
hctr_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,120 +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 source */
|
||||
int source;
|
||||
/** active value of parameter output_line */
|
||||
int output_line;
|
||||
struct counter_private_t* private_data;
|
||||
} COUNTER, *pCOUNTER;
|
||||
|
||||
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** cpp, char* name);
|
||||
int cntr_start(COUNTER* cp);
|
||||
int cntr_stop(COUNTER* cp);
|
||||
int cntr_pause(COUNTER* cp);
|
||||
int cntr_resume(COUNTER* cp);
|
||||
int cntr_command(void* cp, const char* cmd);
|
||||
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,830 +0,0 @@
|
||||
/* vim: ts=8 sts=2 sw=2 cindent
|
||||
*/
|
||||
#include "hctr.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||
#define DAQmxFailed(e) ((e) != 0)
|
||||
#define DAQmxGetExtendedErrorInfo(b, l) snprintf(b, l, "BAD")
|
||||
#include <osiBus.h>
|
||||
#include <tTIO.h>
|
||||
typedef unsigned long uInt32;
|
||||
/**
|
||||
* This structure contains the data for the PCI-6602 card
|
||||
*/
|
||||
typedef struct card_t
|
||||
{
|
||||
iBus* bus;
|
||||
tAddressSpace Bar1;
|
||||
tAddressSpace Bar2;
|
||||
tTIO *tio_1;
|
||||
tTIO *tio_2;
|
||||
unsigned char dio_mask;
|
||||
unsigned char dev_mask;
|
||||
} CARD;
|
||||
#else
|
||||
#include <NIDAQmx.h>
|
||||
|
||||
#define DAQmxErrChk(functionCall) \
|
||||
do { if( DAQmxFailed(error=(functionCall)) ) \
|
||||
goto Error; } while(0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This structure encapsulates the data that is private to
|
||||
* the implementation of the NI DAQ counter interface
|
||||
*/
|
||||
typedef struct counter_private_t
|
||||
{
|
||||
/** extended 64-bit counter value */
|
||||
unsigned long long count64;
|
||||
/** NIDAQ device number of card */
|
||||
int device_number;
|
||||
/** NI counter number on card */
|
||||
int counter_number;
|
||||
/** true if using external sync else timer based sampling */
|
||||
bool sync;
|
||||
/** sync line number on the card */
|
||||
int sync_line_number;
|
||||
/** output line number on the card */
|
||||
int output_line_number;
|
||||
/** Actual physical counter value, as returned by read function */
|
||||
uInt32 count32;
|
||||
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||
CARD* card;
|
||||
#else
|
||||
/** NIDAQ opaque task handle */
|
||||
TaskHandle taskHandle;
|
||||
/** NIDAQ opaque task handle for digital output */
|
||||
TaskHandle taskHandle_dout;
|
||||
#endif
|
||||
} COUNTER_PRIVATE;
|
||||
|
||||
typedef struct mapping_t {
|
||||
int cntr_num;
|
||||
int sync_num;
|
||||
int outp_num;
|
||||
} MAPPING;
|
||||
|
||||
static MAPPING mapping[8] = {
|
||||
{ 0, 37, 36 },
|
||||
{ 1, 33, 32 },
|
||||
{ 2, 29, 28 },
|
||||
{ 3, 25, 24 },
|
||||
{ 4, 21, 20 },
|
||||
{ 5, 17, 16 },
|
||||
{ 6, 13, 12 },
|
||||
{ 7, 9, 8 }
|
||||
};
|
||||
|
||||
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||
static void initMite(iBus *bus);
|
||||
|
||||
static CARD* card[10];
|
||||
#else
|
||||
static int make_dout_task(pHCTR ptr);
|
||||
#endif
|
||||
|
||||
int hctr_ctor(const char* device_name, pHCTR* ptr)
|
||||
{
|
||||
pHCTR hctr = NULL;
|
||||
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||
CARD* pci = NULL;
|
||||
#endif
|
||||
int error = 0;
|
||||
bool flag = false;
|
||||
char text_string[] = "dev1/ctr0";
|
||||
const char *name;
|
||||
const char *text;
|
||||
|
||||
hctr = (COUNTER_PRIVATE*) malloc(sizeof(COUNTER_PRIVATE));
|
||||
*ptr = hctr;
|
||||
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)
|
||||
{
|
||||
(*ptr)->counter_number = *name - '0';
|
||||
(*ptr)->sync_line_number = mapping[(*ptr)->counter_number].sync_num;
|
||||
(*ptr)->output_line_number = mapping[(*ptr)->counter_number].outp_num;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*ptr)->device_number = *name - '0';
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
else if (tolower(*name) != *text)
|
||||
{
|
||||
/* TODO error */
|
||||
printf("Device name error: %s (%d,%d)\n",
|
||||
device_name,
|
||||
(*ptr)->counter_number,
|
||||
(*ptr)->device_number);
|
||||
break;
|
||||
}
|
||||
++name;
|
||||
++text;
|
||||
}
|
||||
|
||||
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||
if (card[hctr->device_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, "0x1310"))
|
||||
{
|
||||
++count;
|
||||
name = strstr(line, "PXI");
|
||||
if (name && count == hctr->device_number)
|
||||
{
|
||||
found = true;
|
||||
strcpy(local_name, name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
// TODO error
|
||||
}
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
card[hctr->device_number] = (CARD*) malloc(sizeof(CARD));
|
||||
memset(card[hctr->device_number], 0, sizeof(CARD));
|
||||
pci = card[hctr->device_number];
|
||||
hctr->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->Bar2 = pci->bus->createAddressSpace(kPCI_BAR1);
|
||||
pci->tio_1 = new tTIO(pci->Bar1);
|
||||
pci->tio_2 = new tTIO(pci->Bar2);
|
||||
pci->tio_2->setAddressOffset(0x800);
|
||||
//
|
||||
//Set all counter outputs to 'input' so we don't accidentally double drive an IO pin
|
||||
pci->tio_1->IO_Pin_8_9_Configuration_Register.writeIO_Pin_8_Select(0); //0='input'
|
||||
pci->tio_1->IO_Pin_12_13_Configuration_Register.writeIO_Pin_12_Select(0); //0='input'
|
||||
pci->tio_1->IO_Pin_16_17_Configuration_Register.writeIO_Pin_16_Select(0); //0='input'
|
||||
pci->tio_1->IO_Pin_20_21_Configuration_Register.writeIO_Pin_20_Select(0); //0='input'
|
||||
pci->tio_1->IO_Pin_24_25_Configuration_Register.writeIO_Pin_24_Select(0); //0='input'
|
||||
pci->tio_1->IO_Pin_28_29_Configuration_Register.writeIO_Pin_28_Select(0); //0='input'
|
||||
pci->tio_1->IO_Pin_32_33_Configuration_Register.writeIO_Pin_32_Select(0); //0='input'
|
||||
pci->tio_1->IO_Pin_36_37_Configuration_Register.writeIO_Pin_36_Select(0); //0='input'
|
||||
|
||||
pci->tio_2->IO_Pin_8_9_Configuration_Register.writeIO_Pin_8_Select(0); //0='input'
|
||||
pci->tio_2->IO_Pin_12_13_Configuration_Register.writeIO_Pin_12_Select(0); //0='input'
|
||||
pci->tio_2->IO_Pin_16_17_Configuration_Register.writeIO_Pin_16_Select(0); //0='input'
|
||||
pci->tio_2->IO_Pin_20_21_Configuration_Register.writeIO_Pin_20_Select(0); //0='input'
|
||||
pci->tio_2->IO_Pin_24_25_Configuration_Register.writeIO_Pin_24_Select(0); //0='input'
|
||||
pci->tio_2->IO_Pin_28_29_Configuration_Register.writeIO_Pin_28_Select(0); //0='input'
|
||||
pci->tio_2->IO_Pin_32_33_Configuration_Register.writeIO_Pin_32_Select(0); //0='input'
|
||||
pci->tio_2->IO_Pin_36_37_Configuration_Register.writeIO_Pin_36_Select(0); //0='input'
|
||||
|
||||
//Bind the first TIO to counters 0-3 on the IO connector, and
|
||||
//bind the second TIO to counters 4-7
|
||||
pci->tio_1->Clock_Configuration_Register.writeCntr_Swap(0);
|
||||
pci->tio_2->Clock_Configuration_Register.writeCntr_Swap(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pci = card[hctr->device_number];
|
||||
hctr->card = pci;
|
||||
}
|
||||
|
||||
// Mark the counter on this card as in-use
|
||||
if (pci->dev_mask & (1 << hctr->counter_number))
|
||||
{
|
||||
// TODO error
|
||||
}
|
||||
pci->dev_mask |= 1 << hctr->counter_number;
|
||||
|
||||
/*
|
||||
* Set up the counter object
|
||||
*/
|
||||
switch (hctr->counter_number)
|
||||
{
|
||||
case 0:
|
||||
//Disarm
|
||||
pci->tio_1->G0_Command_Register.writeG0_Disarm(1);
|
||||
//load initial value of zero
|
||||
pci->tio_1->G0_Load_A_Registers.writeG0_Load_A(0x00000000);
|
||||
pci->tio_1->G0_Command_Register.writeG0_Load(1);
|
||||
//set source to external default source pin
|
||||
pci->tio_1->G0_Input_Select_Register.writeG0_Source_Select(1);
|
||||
//set gate to no gate
|
||||
pci->tio_1->G0_Input_Select_Register.writeG0_Gate_Select(30);
|
||||
pci->tio_1->G0_Mode_Register.writeG0_Gate_Polarity(1);
|
||||
pci->tio_1->G0_Mode_Register.writeG0_Trigger_Mode_For_Edge_Gate(3);
|
||||
//set counting direction to up
|
||||
pci->tio_1->G0_Command_Register.writeG0_Up_Down(1);
|
||||
//arm counter
|
||||
pci->tio_1->G0_Command_Register.writeG0_Arm(1);
|
||||
break;
|
||||
case 1:
|
||||
//Disarm
|
||||
pci->tio_1->G1_Command_Register.writeG1_Disarm(1);
|
||||
//load initial value of zero
|
||||
pci->tio_1->G1_Load_A_Registers.writeG1_Load_A(0x00000000);
|
||||
pci->tio_1->G1_Command_Register.writeG1_Load(1);
|
||||
//set source to external default source pin
|
||||
pci->tio_1->G1_Input_Select_Register.writeG1_Source_Select(1);
|
||||
//set gate to no gate
|
||||
pci->tio_1->G1_Input_Select_Register.writeG1_Gate_Select(30);
|
||||
pci->tio_1->G1_Mode_Register.writeG1_Gate_Polarity(1);
|
||||
pci->tio_1->G1_Mode_Register.writeG1_Trigger_Mode_For_Edge_Gate(3);
|
||||
//set counting direction to up
|
||||
pci->tio_1->G1_Command_Register.writeG1_Up_Down(1);
|
||||
//arm counter
|
||||
pci->tio_1->G1_Command_Register.writeG1_Arm(1);
|
||||
break;
|
||||
case 2:
|
||||
//Disarm
|
||||
pci->tio_1->G2_Command_Register.writeG2_Disarm(1);
|
||||
//load initial value of zero
|
||||
pci->tio_1->G2_Load_A_Registers.writeG2_Load_A(0x00000000);
|
||||
pci->tio_1->G2_Command_Register.writeG2_Load(1);
|
||||
//set source to external default source pin
|
||||
pci->tio_1->G2_Input_Select_Register.writeG2_Source_Select(1);
|
||||
//set gate to no gate
|
||||
pci->tio_1->G2_Input_Select_Register.writeG2_Gate_Select(30);
|
||||
pci->tio_1->G2_Mode_Register.writeG2_Gate_Polarity(1);
|
||||
pci->tio_1->G2_Mode_Register.writeG2_Trigger_Mode_For_Edge_Gate(3);
|
||||
//set counting direction to up
|
||||
pci->tio_1->G2_Command_Register.writeG2_Up_Down(1);
|
||||
//arm counter
|
||||
pci->tio_1->G2_Command_Register.writeG2_Arm(1);
|
||||
break;
|
||||
case 3:
|
||||
//Disarm
|
||||
pci->tio_1->G3_Command_Register.writeG3_Disarm(1);
|
||||
//load initial value of zero
|
||||
pci->tio_1->G3_Load_A_Registers.writeG3_Load_A(0x00000000);
|
||||
pci->tio_1->G3_Command_Register.writeG3_Load(1);
|
||||
//set source to external default source pin
|
||||
pci->tio_1->G3_Input_Select_Register.writeG3_Source_Select(1);
|
||||
//set gate to no gate
|
||||
pci->tio_1->G3_Input_Select_Register.writeG3_Gate_Select(30);
|
||||
pci->tio_1->G3_Mode_Register.writeG3_Gate_Polarity(1);
|
||||
pci->tio_1->G3_Mode_Register.writeG3_Trigger_Mode_For_Edge_Gate(3);
|
||||
//set counting direction to up
|
||||
pci->tio_1->G3_Command_Register.writeG3_Up_Down(1);
|
||||
//arm counter
|
||||
pci->tio_1->G3_Command_Register.writeG3_Arm(1);
|
||||
break;
|
||||
case 4:
|
||||
//Disarm
|
||||
pci->tio_2->G0_Command_Register.writeG0_Disarm(1);
|
||||
//load initial value of zero
|
||||
pci->tio_2->G0_Load_A_Registers.writeG0_Load_A(0x00000000);
|
||||
pci->tio_2->G0_Command_Register.writeG0_Load(1);
|
||||
//set source to external default source pin
|
||||
pci->tio_2->G0_Input_Select_Register.writeG0_Source_Select(1);
|
||||
//set gate to no gate
|
||||
pci->tio_2->G0_Input_Select_Register.writeG0_Gate_Select(30);
|
||||
pci->tio_2->G0_Mode_Register.writeG0_Gate_Polarity(1);
|
||||
pci->tio_2->G0_Mode_Register.writeG0_Trigger_Mode_For_Edge_Gate(3);
|
||||
//set counting direction to up
|
||||
pci->tio_2->G0_Command_Register.writeG0_Up_Down(1);
|
||||
//arm counter
|
||||
pci->tio_2->G0_Command_Register.writeG0_Arm(1);
|
||||
break;
|
||||
case 5:
|
||||
//Disarm
|
||||
pci->tio_2->G1_Command_Register.writeG1_Disarm(1);
|
||||
//load initial value of zero
|
||||
pci->tio_2->G1_Load_A_Registers.writeG1_Load_A(0x00000000);
|
||||
pci->tio_2->G1_Command_Register.writeG1_Load(1);
|
||||
//set source to external default source pin
|
||||
pci->tio_2->G1_Input_Select_Register.writeG1_Source_Select(1);
|
||||
//set gate to no gate
|
||||
pci->tio_2->G1_Input_Select_Register.writeG1_Gate_Select(30);
|
||||
pci->tio_2->G1_Mode_Register.writeG1_Gate_Polarity(1);
|
||||
pci->tio_2->G1_Mode_Register.writeG1_Trigger_Mode_For_Edge_Gate(3);
|
||||
//set counting direction to up
|
||||
pci->tio_2->G1_Command_Register.writeG1_Up_Down(1);
|
||||
//arm counter
|
||||
pci->tio_2->G1_Command_Register.writeG1_Arm(1);
|
||||
break;
|
||||
case 6:
|
||||
//Disarm
|
||||
pci->tio_2->G2_Command_Register.writeG2_Disarm(1);
|
||||
//load initial value of zero
|
||||
pci->tio_2->G2_Load_A_Registers.writeG2_Load_A(0x00000000);
|
||||
pci->tio_2->G2_Command_Register.writeG2_Load(1);
|
||||
//set source to external default source pin
|
||||
pci->tio_2->G2_Input_Select_Register.writeG2_Source_Select(1);
|
||||
//set gate to no gate
|
||||
pci->tio_2->G2_Input_Select_Register.writeG2_Gate_Select(30);
|
||||
pci->tio_2->G2_Mode_Register.writeG2_Gate_Polarity(1);
|
||||
pci->tio_2->G2_Mode_Register.writeG2_Trigger_Mode_For_Edge_Gate(3);
|
||||
//set counting direction to up
|
||||
pci->tio_2->G2_Command_Register.writeG2_Up_Down(1);
|
||||
//arm counter
|
||||
pci->tio_2->G2_Command_Register.writeG2_Arm(1);
|
||||
break;
|
||||
case 7:
|
||||
//Disarm
|
||||
pci->tio_2->G3_Command_Register.writeG3_Disarm(1);
|
||||
//load initial value of zero
|
||||
pci->tio_2->G3_Load_A_Registers.writeG3_Load_A(0x00000000);
|
||||
pci->tio_2->G3_Command_Register.writeG3_Load(1);
|
||||
//set source to external default source pin
|
||||
pci->tio_2->G3_Input_Select_Register.writeG3_Source_Select(1);
|
||||
//set gate to no gate
|
||||
pci->tio_2->G3_Input_Select_Register.writeG3_Gate_Select(30);
|
||||
pci->tio_2->G3_Mode_Register.writeG3_Gate_Polarity(1);
|
||||
pci->tio_2->G3_Mode_Register.writeG3_Trigger_Mode_For_Edge_Gate(3);
|
||||
//set counting direction to up
|
||||
pci->tio_2->G3_Command_Register.writeG3_Up_Down(1);
|
||||
//arm counter
|
||||
pci->tio_2->G3_Command_Register.writeG3_Arm(1);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
/*********************************************/
|
||||
// Create a DAQmx task to hold the counter
|
||||
/*********************************************/
|
||||
DAQmxErrChk (DAQmxCreateTask("",&(*ptr)->taskHandle));
|
||||
|
||||
/*********************************************/
|
||||
// Create a DAQmx counter within the task
|
||||
/*********************************************/
|
||||
DAQmxErrChk (
|
||||
DAQmxCreateCICountEdgesChan((*ptr)->taskHandle,
|
||||
device_name,
|
||||
"",
|
||||
DAQmx_Val_Rising,
|
||||
(*ptr)->count32,
|
||||
DAQmx_Val_CountUp));
|
||||
|
||||
/*********************************************/
|
||||
// Start the DAQmx task
|
||||
/*********************************************/
|
||||
DAQmxErrChk (DAQmxStartTask((*ptr)->taskHandle));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
Error:
|
||||
free(*ptr);
|
||||
*ptr = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
int hctr_read(pHCTR hctr, unsigned long long* value)
|
||||
{
|
||||
int error = 0;
|
||||
*value = 0;
|
||||
uInt32 counterValue1;
|
||||
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||
uInt32 counterValue2;
|
||||
CARD* pci = hctr->card;
|
||||
|
||||
//read counter value
|
||||
//Use this method to read the value of an armed counter
|
||||
//during non-buffered counting. Since the value of the counter may
|
||||
//change during the read, we make sure that the value is stable.
|
||||
switch (hctr->counter_number)
|
||||
{
|
||||
case 0:
|
||||
counterValue1 = pci->tio_1->G0_Save_Registers.readRegister();
|
||||
counterValue2 = pci->tio_1->G0_Save_Registers.readRegister();
|
||||
if (counterValue1 != counterValue2)
|
||||
counterValue1 = pci->tio_1->G0_Save_Registers.readRegister();
|
||||
break;
|
||||
case 1:
|
||||
counterValue1 = pci->tio_1->G1_Save_Registers.readRegister();
|
||||
counterValue2 = pci->tio_1->G1_Save_Registers.readRegister();
|
||||
if (counterValue1 != counterValue2)
|
||||
counterValue1 = pci->tio_1->G1_Save_Registers.readRegister();
|
||||
break;
|
||||
case 2:
|
||||
counterValue1 = pci->tio_1->G2_Save_Registers.readRegister();
|
||||
counterValue2 = pci->tio_1->G2_Save_Registers.readRegister();
|
||||
if (counterValue1 != counterValue2)
|
||||
counterValue1 = pci->tio_1->G2_Save_Registers.readRegister();
|
||||
break;
|
||||
case 3:
|
||||
counterValue1 = pci->tio_1->G3_Save_Registers.readRegister();
|
||||
counterValue2 = pci->tio_1->G3_Save_Registers.readRegister();
|
||||
if (counterValue1 != counterValue2)
|
||||
counterValue1 = pci->tio_1->G3_Save_Registers.readRegister();
|
||||
break;
|
||||
case 4:
|
||||
counterValue1 = pci->tio_2->G0_Save_Registers.readRegister();
|
||||
counterValue2 = pci->tio_2->G0_Save_Registers.readRegister();
|
||||
if (counterValue1 != counterValue2)
|
||||
counterValue1 = pci->tio_2->G0_Save_Registers.readRegister();
|
||||
break;
|
||||
case 5:
|
||||
counterValue1 = pci->tio_2->G1_Save_Registers.readRegister();
|
||||
counterValue2 = pci->tio_2->G1_Save_Registers.readRegister();
|
||||
if (counterValue1 != counterValue2)
|
||||
counterValue1 = pci->tio_2->G1_Save_Registers.readRegister();
|
||||
break;
|
||||
case 6:
|
||||
counterValue1 = pci->tio_2->G2_Save_Registers.readRegister();
|
||||
counterValue2 = pci->tio_2->G2_Save_Registers.readRegister();
|
||||
if (counterValue1 != counterValue2)
|
||||
counterValue1 = pci->tio_2->G2_Save_Registers.readRegister();
|
||||
break;
|
||||
case 7:
|
||||
counterValue1 = pci->tio_2->G3_Save_Registers.readRegister();
|
||||
counterValue2 = pci->tio_2->G3_Save_Registers.readRegister();
|
||||
if (counterValue1 != counterValue2)
|
||||
counterValue1 = pci->tio_2->G3_Save_Registers.readRegister();
|
||||
break;
|
||||
}
|
||||
#else
|
||||
DAQmxErrChk (DAQmxReadCounterScalarU32(hctr->taskHandle,
|
||||
1.0,
|
||||
&counterValue1,
|
||||
NULL));
|
||||
Error:
|
||||
if (error)
|
||||
counterValue1 = hctr->count32;
|
||||
#endif
|
||||
hctr->count64 += counterValue1 - hctr->count32;
|
||||
hctr->count32 = counterValue1;
|
||||
*value = hctr->count64;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the source
|
||||
*/
|
||||
int hctr_source(pHCTR hctr, int value)
|
||||
{
|
||||
int error = 0;
|
||||
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||
CARD* pci = hctr->card;
|
||||
int src = 1;
|
||||
if (value == 3)
|
||||
//set source to internal time base 3, the 80Mhz internal clock
|
||||
src = 30;
|
||||
else if (value == 2)
|
||||
//set source to internal time base 2, the l00Khz internal clock
|
||||
src = 18;
|
||||
else if (value == 1)
|
||||
//set source to internal time base 1, the 20Mhz internal clock
|
||||
src = 0;
|
||||
else
|
||||
//set source to external default source pin
|
||||
src = 1;
|
||||
switch (hctr->counter_number)
|
||||
{
|
||||
case 0:
|
||||
pci->tio_1->G0_Input_Select_Register.writeG0_Source_Select(src);
|
||||
break;
|
||||
case 1:
|
||||
pci->tio_1->G1_Input_Select_Register.writeG1_Source_Select(src);
|
||||
break;
|
||||
case 2:
|
||||
pci->tio_1->G2_Input_Select_Register.writeG2_Source_Select(src);
|
||||
break;
|
||||
case 3:
|
||||
pci->tio_1->G3_Input_Select_Register.writeG3_Source_Select(src);
|
||||
break;
|
||||
case 4:
|
||||
pci->tio_2->G0_Input_Select_Register.writeG0_Source_Select(src);
|
||||
break;
|
||||
case 5:
|
||||
pci->tio_2->G1_Input_Select_Register.writeG1_Source_Select(src);
|
||||
break;
|
||||
case 6:
|
||||
pci->tio_2->G2_Input_Select_Register.writeG2_Source_Select(src);
|
||||
break;
|
||||
case 7:
|
||||
pci->tio_2->G3_Input_Select_Register.writeG3_Source_Select(src);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// TODO
|
||||
// DAQmxGetDevCIPhysicalChans
|
||||
// DAQmxSetCICountEdgesTerm
|
||||
//Error:
|
||||
#endif
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the output line corresponding to the counter
|
||||
*/
|
||||
int hctr_outp(pHCTR hctr, int value)
|
||||
{
|
||||
int error = 0;
|
||||
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||
CARD* pci = hctr->card;
|
||||
u16 data;
|
||||
if (value < 0)
|
||||
{
|
||||
// set the disabled line to input
|
||||
value = 0;
|
||||
pci->dio_mask &= ~(1 << hctr->counter_number);
|
||||
pci->tio_1->DIO_Control_Register.writeDIO_Pins_Dir(pci->dio_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
pci->dio_mask |= 1 << hctr->counter_number;
|
||||
pci->tio_1->DIO_Control_Register.writeDIO_Pins_Dir(pci->dio_mask);
|
||||
data = pci->tio_1->DIO_Output_Register.readDIO_Parallel_Data_Out();
|
||||
printf("data %04x", data);
|
||||
if (value > 0)
|
||||
data |= 1 << hctr->counter_number;
|
||||
else
|
||||
data &= ~(1 << hctr->counter_number);
|
||||
pci->tio_1->DIO_Output_Register.writeDIO_Parallel_Data_Out(data);
|
||||
printf(" => %04x", data);
|
||||
data = pci->tio_1->DIO_Output_Register.readDIO_Parallel_Data_Out();
|
||||
printf(" => %04x\n", data);
|
||||
}
|
||||
#else
|
||||
uInt8 data;
|
||||
if (value < 0)
|
||||
{
|
||||
// set the disabled line to logic low
|
||||
if (hctr->taskHandle_dout != 0) {
|
||||
data = 0;
|
||||
DAQmxWriteDigitalLines(hctr->taskHandle_dout,
|
||||
1,
|
||||
1,
|
||||
10.0,
|
||||
DAQmx_Val_GroupByChannel,
|
||||
&data,
|
||||
NULL,
|
||||
NULL);
|
||||
/*********************************************/
|
||||
// DAQmx Stop Code
|
||||
/*********************************************/
|
||||
DAQmxStopTask(hctr->taskHandle_dout);
|
||||
DAQmxClearTask(hctr->taskHandle_dout);
|
||||
hctr->taskHandle_dout = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hctr->taskHandle_dout == 0)
|
||||
DAQmxErrChk (make_dout_task(hctr));
|
||||
if (value > 0)
|
||||
data = 1;
|
||||
else
|
||||
data = 0;
|
||||
DAQmxErrChk (
|
||||
DAQmxWriteDigitalScalarU32(hctr->taskHandle_dout,
|
||||
1,
|
||||
10.0,
|
||||
data,
|
||||
NULL));
|
||||
}
|
||||
Error:
|
||||
#endif
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up to read the counter synchronized to an external signal
|
||||
*/
|
||||
void hctr_sync(pHCTR hctr, bool external)
|
||||
{
|
||||
#if REGISTER_LEVEL_PROGRAMMING
|
||||
CARD* pci = hctr->card;
|
||||
// TODO
|
||||
#else
|
||||
int error = 0;
|
||||
char device_name[40];
|
||||
if (hctr->sync != external)
|
||||
{
|
||||
hctr->sync = external;
|
||||
/*********************************************/
|
||||
// DAQmx Stop Code
|
||||
/*********************************************/
|
||||
DAQmxStopTask(hctr->taskHandle);
|
||||
DAQmxClearTask(hctr->taskHandle);
|
||||
/*********************************************/
|
||||
// Create a DAQmx task to hold the counter
|
||||
/*********************************************/
|
||||
DAQmxErrChk (DAQmxCreateTask("",&hctr->taskHandle));
|
||||
|
||||
/*********************************************/
|
||||
// Create a DAQmx counter within the task
|
||||
/*********************************************/
|
||||
hctr->count32 = 0;
|
||||
snprintf(device_name, sizeof(device_name), "dev%d/ctr%d",
|
||||
hctr->device_number, hctr->counter_number);
|
||||
DAQmxErrChk (
|
||||
DAQmxCreateCICountEdgesChan(hctr->taskHandle,
|
||||
device_name,
|
||||
"",
|
||||
DAQmx_Val_Rising,
|
||||
hctr->count32,
|
||||
DAQmx_Val_CountUp));
|
||||
|
||||
if (external)
|
||||
{
|
||||
char str[40];
|
||||
snprintf(str, sizeof(str), "dev%d/PFI%d",
|
||||
hctr->device_number, hctr->sync_line_number);
|
||||
DAQmxErrChk (
|
||||
DAQmxCfgSampClkTiming(hctr->taskHandle,
|
||||
str,
|
||||
10000,
|
||||
DAQmx_Val_Rising,
|
||||
DAQmx_Val_ContSamps,
|
||||
10000));
|
||||
}
|
||||
/*********************************************/
|
||||
// Start the DAQmx task
|
||||
/*********************************************/
|
||||
DAQmxErrChk (DAQmxStartTask(hctr->taskHandle));
|
||||
|
||||
}
|
||||
Error:
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shut down the counter
|
||||
*/
|
||||
int hctr_dtor(pHCTR* hctr)
|
||||
{
|
||||
if (hctr && *hctr)
|
||||
{
|
||||
#ifdef REGISTER_LEVEL_PROGRAMMING
|
||||
CARD* pci = (*hctr)->card;
|
||||
switch ((*hctr)->counter_number)
|
||||
{
|
||||
case 0:
|
||||
pci->tio_1->G0_Command_Register.writeG0_Disarm(1);
|
||||
break;
|
||||
case 1:
|
||||
pci->tio_1->G1_Command_Register.writeG1_Disarm(1);
|
||||
break;
|
||||
case 2:
|
||||
pci->tio_1->G2_Command_Register.writeG2_Disarm(1);
|
||||
break;
|
||||
case 3:
|
||||
pci->tio_1->G3_Command_Register.writeG3_Disarm(1);
|
||||
break;
|
||||
case 4:
|
||||
pci->tio_2->G0_Command_Register.writeG0_Disarm(1);
|
||||
break;
|
||||
case 5:
|
||||
pci->tio_2->G1_Command_Register.writeG1_Disarm(1);
|
||||
break;
|
||||
case 6:
|
||||
pci->tio_2->G2_Command_Register.writeG2_Disarm(1);
|
||||
break;
|
||||
case 7:
|
||||
pci->tio_2->G3_Command_Register.writeG3_Disarm(1);
|
||||
break;
|
||||
}
|
||||
|
||||
pci->dev_mask &= ~(1 << (*hctr)->counter_number);
|
||||
if (pci->dev_mask == 0)
|
||||
{
|
||||
delete pci->tio_1;
|
||||
delete pci->tio_2;
|
||||
pci->bus->destroyAddressSpace(pci->Bar1);
|
||||
pci->bus->destroyAddressSpace(pci->Bar2);
|
||||
|
||||
releaseBoard(pci->bus);
|
||||
card[(*hctr)->device_number] = NULL;
|
||||
free(pci);
|
||||
}
|
||||
#else
|
||||
if ((*hctr)->taskHandle!=0)
|
||||
{
|
||||
/*********************************************/
|
||||
// DAQmx Stop Code
|
||||
/*********************************************/
|
||||
DAQmxStopTask((*hctr)->taskHandle);
|
||||
DAQmxClearTask((*hctr)->taskHandle);
|
||||
(*hctr)->taskHandle = 0;
|
||||
}
|
||||
if ((*hctr)->taskHandle_dout!=0)
|
||||
{
|
||||
/*********************************************/
|
||||
// DAQmx Stop Code
|
||||
/*********************************************/
|
||||
DAQmxStopTask((*hctr)->taskHandle_dout);
|
||||
DAQmxClearTask((*hctr)->taskHandle_dout);
|
||||
(*hctr)->taskHandle_dout = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* release the storage */
|
||||
free(*hctr);
|
||||
*hctr = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hctr_failed(int error)
|
||||
{
|
||||
if (DAQmxFailed(error))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void hctr_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);
|
||||
|
||||
// ***** 6602/6608 specific MITE initialization *****
|
||||
// Hit the IO Window Base/Size Register 1 (IOWBSR1) in the MITE. We set the
|
||||
// address, enable the window and set the size of the window:
|
||||
Bar0.write32(0xC4, (physicalBar1 & 0xffffff00L) | 0x8C);
|
||||
|
||||
// Write to the IO Window Control Register 1 (IOWCR1) to make the IO window
|
||||
// go to RAM memory space instead of the config space
|
||||
Bar0.write32(0xF4, 0);
|
||||
|
||||
// ***** End of 6602/6608 specific code *****
|
||||
|
||||
bus->destroyAddressSpace(Bar0);
|
||||
}
|
||||
#else
|
||||
int make_dout_task(pHCTR ptr)
|
||||
{
|
||||
int error = 0;
|
||||
char port_range[40];
|
||||
/*********************************************/
|
||||
// Create a DAQmx task to hold the counter
|
||||
/*********************************************/
|
||||
DAQmxErrChk (DAQmxCreateTask("",&ptr->taskHandle_dout));
|
||||
|
||||
/*********************************************/
|
||||
// Create the digital channel within the task
|
||||
/*********************************************/
|
||||
snprintf(port_range, sizeof(port_range), "DEV%d/LINE%d",
|
||||
ptr->device_number, ptr->counter_number);
|
||||
DAQmxErrChk (DAQmxCreateDOChan(ptr->taskHandle_dout,
|
||||
port_range,
|
||||
"",
|
||||
DAQmx_Val_ChanPerLine));
|
||||
|
||||
/*********************************************/
|
||||
// Start the DAQmx task
|
||||
/*********************************************/
|
||||
DAQmxErrChk (DAQmxStartTask(ptr->taskHandle_dout));
|
||||
return error;
|
||||
|
||||
Error:
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
@@ -1,105 +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 _HCTR_H_
|
||||
#define _HCTR_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
struct counter_private_t;
|
||||
typedef struct counter_private_t* pHCTR;
|
||||
|
||||
/**
|
||||
* 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 hctr_ctor(const char* device_name, pHCTR* ptr);
|
||||
|
||||
/**
|
||||
* Read the value of the 64-bit counter
|
||||
*
|
||||
* \param hctr pointer to opaque private data structure
|
||||
* \param value address of unsigned 64-bit value to receive the output
|
||||
*
|
||||
* \return
|
||||
* 0 OK
|
||||
* !0 Error
|
||||
*/
|
||||
int hctr_read(pHCTR hctr, unsigned long long* value);
|
||||
|
||||
/**
|
||||
* Select the source
|
||||
*
|
||||
* \param value source selector
|
||||
* 3 Timebase 3 (80Mhz on PCI-6602)
|
||||
* 2 Timebase 2 (100Khz on PCI-6602)
|
||||
* 1 Timebase 1 (20Mhz on PCI-6602)
|
||||
* else default external pin
|
||||
*/
|
||||
int hctr_source(pHCTR hctr, int value);
|
||||
|
||||
/**
|
||||
* Enables external output on designated DIO line
|
||||
*
|
||||
* \param hctr pointer to opaque private data structure
|
||||
* \param value to be written to the associated line
|
||||
* < 0 disconnect
|
||||
* = 0 logic low
|
||||
* > 0 logic high
|
||||
*/
|
||||
int hctr_outp(pHCTR hctr, int value);
|
||||
|
||||
/**
|
||||
* Enables external sync on designated (up/down) line
|
||||
*
|
||||
* \param hctr pointer to opaque private data structure
|
||||
* \param external true for external sync, false for internal
|
||||
*/
|
||||
void hctr_sync(pHCTR hctr, bool external);
|
||||
|
||||
/**
|
||||
* Destroy the 64-bit counter
|
||||
*
|
||||
* \param ptr address of pointer to opaque private data structure
|
||||
*
|
||||
* \return
|
||||
* 0 OK
|
||||
* !0 Error
|
||||
*/
|
||||
int hctr_dtor(pHCTR* hctr);
|
||||
|
||||
/**
|
||||
* Tests returned error value to see if it represents failure
|
||||
*
|
||||
* \param error a value returned from another hctr function
|
||||
*
|
||||
* \return
|
||||
* true the error was a failure
|
||||
* false the error was not a failure (warning)
|
||||
*/
|
||||
bool hctr_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 hctr_errmsg(char* buff, int len);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user