Initial load of driver
r1083 | dcl | 2006-08-25 14:46:51 +1000 (Fri, 25 Aug 2006) | 2 lines
This commit is contained in:
34
site_ansto/hardsup/Monitor/Makefile
Normal file
34
site_ansto/hardsup/Monitor/Makefile
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
SHELL = /bin/sh
|
||||||
|
|
||||||
|
LIBS = nidaqmx
|
||||||
|
LIBFLAGS = -l$(LIBS)
|
||||||
|
TARGET = Monitor
|
||||||
|
|
||||||
|
OBJS = $(TARGET).o params.o utility.o sock.o display.o cntr.o hctr.o
|
||||||
|
|
||||||
|
CDEBUG = -ggdb3 -Wall
|
||||||
|
LDFLAGS += -g
|
||||||
|
|
||||||
|
CFLAGS += $(CDEBUG)
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) $(TARGET) core
|
||||||
|
|
||||||
|
$(TARGET) : $(OBJS)
|
||||||
|
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBFLAGS) -ggdb3
|
||||||
|
|
||||||
|
$(TARGET).o: $(TARGET).c Monitor.h params.h utility.h sock.h cntr.h
|
||||||
|
|
||||||
|
cntr.o: cntr.c Monitor.h cntr.h params.h sock.h
|
||||||
|
|
||||||
|
display.o: display.c Monitor.h display.h utility.h params.h sock.h cntr.h
|
||||||
|
|
||||||
|
hctr.o: hctr.c hctr.h
|
||||||
|
|
||||||
|
params.o: params.c Monitor.h params.h sock.h
|
||||||
|
|
||||||
|
sock.o: sock.c Monitor.h sock.h utility.h display.h cntr.h
|
||||||
|
|
||||||
|
utility.o: utility.c Monitor.h utility.h
|
||||||
168
site_ansto/hardsup/Monitor/Monitor.c
Normal file
168
site_ansto/hardsup/Monitor/Monitor.c
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* ANSI C program:
|
||||||
|
* Monitor.c
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This program counts digital events on a NI-6602
|
||||||
|
* Counter Input Channel. The Device, Counter Channel, Initial Count, Count
|
||||||
|
* Direction, and are all configurable.
|
||||||
|
*
|
||||||
|
* Edges are counted on the counter's default input terminal (refer
|
||||||
|
* to the I/O Connections Overview section below for more
|
||||||
|
* information), but could easily be modified to count edges on a
|
||||||
|
* PFI or RTSI line.
|
||||||
|
*
|
||||||
|
* Instructions for Running:
|
||||||
|
* 1. Select the Device and Channel which corresponds to the counter
|
||||||
|
* you want to count on.
|
||||||
|
* 2. Select the TCP/IP port number you want to listen on.
|
||||||
|
* 3. Enter the Initial Count, Count Direction, to specify how you want
|
||||||
|
* the counter to count.
|
||||||
|
*
|
||||||
|
* Steps:
|
||||||
|
* 1. Create a task.
|
||||||
|
* 2. Create a Counter Input channel to Count Events. The Edge
|
||||||
|
* parameter is used to determine if the counter will increment
|
||||||
|
* on rising or falling edges.
|
||||||
|
* 3. Call the Start function to arm the counter and begin
|
||||||
|
* counting. The counter will be preloaded with the Initial
|
||||||
|
* Count.
|
||||||
|
* 4. The counter will be continually polled.
|
||||||
|
* 5. Call the Clear Task function to clear the Task.
|
||||||
|
* 6. Display an error if any.
|
||||||
|
*
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#define CNTR_CHK(func) if (cntr_fatal(error=(func))) goto Error; else
|
||||||
|
|
||||||
|
#include "Monitor.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "sock.h"
|
||||||
|
#include "cntr.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 = DEFAULT_COUNTER_DEVICE;
|
||||||
|
int port = DEFAULT_LISTEN_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;
|
||||||
|
}
|
||||||
11
site_ansto/hardsup/Monitor/Monitor.h
Normal file
11
site_ansto/hardsup/Monitor/Monitor.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Monitor.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef _MONITOR_H_
|
||||||
|
#define _MONITOR_H_
|
||||||
|
|
||||||
|
#define DEFAULT_COUNTER_DEVICE "DEV1/CTR0"
|
||||||
|
#define DEFAULT_LISTEN_PORT 3000
|
||||||
|
|
||||||
|
#endif
|
||||||
584
site_ansto/hardsup/Monitor/cntr.c
Normal file
584
site_ansto/hardsup/Monitor/cntr.c
Normal file
@@ -0,0 +1,584 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
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(hctr_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:
|
||||||
|
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;
|
||||||
|
/* 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(hctr_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)
|
||||||
|
{
|
||||||
|
cp->stop_time = cp->current_time;
|
||||||
|
cp->state = counter_stopped;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(hctr_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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
116
site_ansto/hardsup/Monitor/cntr.h
Normal file
116
site_ansto/hardsup/Monitor/cntr.h
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#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;
|
||||||
|
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
|
||||||
696
site_ansto/hardsup/Monitor/display.c
Normal file
696
site_ansto/hardsup/Monitor/display.c
Normal file
@@ -0,0 +1,696 @@
|
|||||||
|
#include "display.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "sock.h"
|
||||||
|
#include "cntr.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#define MIN_REFRESH 5
|
||||||
|
#define MAX_REFRESH 30
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a drop down selection box in a two-column table row
|
||||||
|
*
|
||||||
|
* \param buffer where the output is appended
|
||||||
|
* \param title text to go in column one
|
||||||
|
* \param name name of the selection object
|
||||||
|
*
|
||||||
|
* The browser will return name=value for the selection, using the name from
|
||||||
|
* the selection box and the value from the option selected.
|
||||||
|
*/
|
||||||
|
static void add_select_begin(BUFFER* buffer, char* title, char* name)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"<tr><td>%s</td>\r\n"
|
||||||
|
"<td><select name=\"%s\">\r\n",
|
||||||
|
title,
|
||||||
|
name);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an option line to a drop down selection box
|
||||||
|
*
|
||||||
|
* \param buffer where the output is appended
|
||||||
|
* \param name text displayed in the box
|
||||||
|
* \param value text returned in the form
|
||||||
|
* \param selected if this is the default selection to be displayed
|
||||||
|
*
|
||||||
|
* The browser will return name=value for the selection, using the name from
|
||||||
|
* the selection box and the value from the option selected.
|
||||||
|
*/
|
||||||
|
static void add_option(BUFFER* buffer, char* name, char* value, bool selected)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"<option value=\"%s\"%s>%s</option>\r\n", value,
|
||||||
|
selected ? " selected=\"selected\"" : "",
|
||||||
|
name);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close out the selection, column and row of a drop down box
|
||||||
|
*
|
||||||
|
* \param buffer where the output is appended
|
||||||
|
*/
|
||||||
|
static void add_select_end(BUFFER* buffer)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"</select></td></tr>\r\n");
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add arbitrary text to a buffer and adjust the length
|
||||||
|
*
|
||||||
|
* \param buffer where the text is appended
|
||||||
|
*/
|
||||||
|
static void add_text(BUFFER* buffer, char* text)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length, "%s", text);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a two-column row for an integer
|
||||||
|
*
|
||||||
|
* \param buffer where the text is appended
|
||||||
|
* \param title is displayed in column one
|
||||||
|
* \param name is returned by the browser
|
||||||
|
* \param value is displayed in column two and returned by the browser
|
||||||
|
*
|
||||||
|
* The title is displayed in column one and the integer in column two. The
|
||||||
|
* name=value is returned by the browser.
|
||||||
|
*/
|
||||||
|
static void add_int(BUFFER* buffer, char* title, char* name, int value)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"<tr><td>%s</td>"
|
||||||
|
"<td><input type=\"text\" name=\"%s\" size=12 value=\"%d\"></td>"
|
||||||
|
"</tr>\r\n",
|
||||||
|
title,
|
||||||
|
name,
|
||||||
|
value);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a two-column row for a double floating point
|
||||||
|
*
|
||||||
|
* \param buffer where the text is appended
|
||||||
|
* \param title is displayed in column one
|
||||||
|
* \param name is returned by the browser
|
||||||
|
* \param value is displayed in column two and returned by the browser
|
||||||
|
*
|
||||||
|
* The title is displayed in column one and the double in column two. The
|
||||||
|
* name=value is returned by the browser.
|
||||||
|
*/
|
||||||
|
static void add_double(BUFFER* buffer, char* title, char* name, double value)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"<tr><td>%s</td>"
|
||||||
|
"<td><input type=\"text\" name=\"%s\" size=12 value=\"%.12g\"></td>"
|
||||||
|
"</tr>\r\n",
|
||||||
|
title,
|
||||||
|
name,
|
||||||
|
value);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a two-column row for a counter value
|
||||||
|
*
|
||||||
|
* \param buffer where the text is appended
|
||||||
|
* \param title is displayed in column one
|
||||||
|
* \param name is returned by the browser
|
||||||
|
* \param value is displayed in column two and returned by the browser
|
||||||
|
*
|
||||||
|
* The title is displayed in column one and the counter value in column two.
|
||||||
|
* The name=value is returned by the browser.
|
||||||
|
*/
|
||||||
|
static void add_counter(BUFFER* buffer, char* title, char* name, uint64 value)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"<tr><td>%s</td>"
|
||||||
|
"<td><input type=\"text\" name=\"%s\" size=12 value=\"%llu\"></td>"
|
||||||
|
"</tr>\r\n",
|
||||||
|
title,
|
||||||
|
name,
|
||||||
|
value);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the counter control form on socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*
|
||||||
|
* The counter control form has fields to display and change counter control
|
||||||
|
* parameters. It contains buttons to update the counter parameters or reset
|
||||||
|
* them to the last displayed values.
|
||||||
|
*/
|
||||||
|
void put_form(int n)
|
||||||
|
{
|
||||||
|
dprintf(0, "put_form\n");
|
||||||
|
BUFFER html;
|
||||||
|
BUFFER buffer;
|
||||||
|
PARAMETERS* pp = &counter.params;
|
||||||
|
char *bp;
|
||||||
|
buffer.length = 0;
|
||||||
|
bp = &buffer.body[buffer.length];
|
||||||
|
snprintf(bp, sizeof(buffer.body) - buffer.length,
|
||||||
|
"<html><head><title>Counter Form</title></head>\r\n"
|
||||||
|
"<body>\r\n"
|
||||||
|
"<form method=\"post\" action=\"/form\">\r\n"
|
||||||
|
"<table align=\"center\" border=\"0\">\r\n"
|
||||||
|
"<tr><th align=\"right\">Field</th>\r\n"
|
||||||
|
"<th align=\"left\">Value</th></tr>\r\n");
|
||||||
|
buffer.length += strlen(bp);
|
||||||
|
add_select_begin(&buffer, "Direction", "direction");
|
||||||
|
add_option(&buffer, "Up", "up", pp->direction == COUNT_UP);
|
||||||
|
add_option(&buffer, "Down", "down", !pp->direction == COUNT_UP);
|
||||||
|
add_select_end(&buffer);
|
||||||
|
add_int(&buffer, "Scan", "scan", pp->poll_period);
|
||||||
|
add_int(&buffer, "Sample", "sample", pp->sample_period);
|
||||||
|
add_int(&buffer, "Report", "report", pp->report_period);
|
||||||
|
add_counter(&buffer, "Initial", "initial", pp->initial_count);
|
||||||
|
add_counter(&buffer, "Terminal", "terminal", pp->terminal_count);
|
||||||
|
add_select_begin(&buffer, "Terminal Event", "te_check");
|
||||||
|
add_option(&buffer, "None", "none", pp->terminal_check_type == 0);
|
||||||
|
add_option(&buffer, "Counter", "counter", pp->terminal_check_type == 1);
|
||||||
|
add_option(&buffer, "Timer", "timer", pp->terminal_check_type == 2);
|
||||||
|
add_select_end(&buffer);
|
||||||
|
add_double(&buffer, "Range Low", "range_low", pp->range_low);
|
||||||
|
add_double(&buffer, "Range High", "range_high", pp->range_high);
|
||||||
|
add_select_begin(&buffer, "Range Event", "re_check");
|
||||||
|
add_option(&buffer, "Enabled", "enabled", pp->range_check_enable == true);
|
||||||
|
add_option(&buffer, "Disabled", "Disabled", pp->range_check_enable == false);
|
||||||
|
add_select_end(&buffer);
|
||||||
|
add_select_begin(&buffer, "Range Gate", "range_gate");
|
||||||
|
add_option(&buffer, "Enabled", "enabled", pp->range_gate_enable == true);
|
||||||
|
add_option(&buffer, "Disabled", "Disabled", pp->range_gate_enable == false);
|
||||||
|
add_select_end(&buffer);
|
||||||
|
add_select_begin(&buffer, "Range Mode", "range_mode");
|
||||||
|
add_option(&buffer, "Report", "0", pp->range_mode == 0);
|
||||||
|
add_option(&buffer, "Sample", "1", pp->range_mode == 1);
|
||||||
|
add_option(&buffer, "Poll", "2", pp->range_mode == 2);
|
||||||
|
add_select_end(&buffer);
|
||||||
|
bp = &buffer.body[buffer.length];
|
||||||
|
snprintf(bp, sizeof(buffer.body) - buffer.length,
|
||||||
|
"<tr><td>\r\n"
|
||||||
|
"<input type=\"submit\" name=\"Send\" size=9 value=\"Update\">\r\n"
|
||||||
|
"</td><td>"
|
||||||
|
"<input type=\"reset\" name=\"Reset\" size=9 value=\"Reset\">\r\n"
|
||||||
|
"</td></tr></table>\r\n"
|
||||||
|
"</form>\r\n"
|
||||||
|
"</body>\r\n"
|
||||||
|
"</html>\r\n" );
|
||||||
|
buffer.length += strlen(bp);
|
||||||
|
bp = &buffer.body[buffer.length];
|
||||||
|
html.length = 0;
|
||||||
|
bp = &html.body[html.length];
|
||||||
|
snprintf(bp, sizeof(html.body) - html.length,
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"\r\n",
|
||||||
|
buffer.length);
|
||||||
|
strcat(html.body, buffer.body);
|
||||||
|
html.length = strlen(html.body);
|
||||||
|
sock_send(n, &html);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_text(BUFFER* buffer, char* title, char* value)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"<tr><td>%s</td>"
|
||||||
|
"<td>%s</td>"
|
||||||
|
"</tr>\r\n",
|
||||||
|
title,
|
||||||
|
value);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_int(BUFFER* buffer, char* title, int value)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"<tr><td>%s</td>"
|
||||||
|
"<td>%d</td>"
|
||||||
|
"</tr>\r\n",
|
||||||
|
title,
|
||||||
|
value);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_real(BUFFER* buffer, char* title, double value)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"<tr><td>%s</td>"
|
||||||
|
"<td>%.2f</td>"
|
||||||
|
"</tr>\r\n",
|
||||||
|
title,
|
||||||
|
value);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_counter(BUFFER* buffer, char* title, unsigned long long value)
|
||||||
|
{
|
||||||
|
char* bp = &buffer->body[buffer->length];
|
||||||
|
snprintf(bp, sizeof(buffer->body) - buffer->length,
|
||||||
|
"<tr><td>%s</td>"
|
||||||
|
"<td>%llu</td>"
|
||||||
|
"</tr>\r\n",
|
||||||
|
title,
|
||||||
|
value);
|
||||||
|
buffer->length += strlen(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_time(BUFFER* buffer,
|
||||||
|
char* title,
|
||||||
|
struct timeval* value,
|
||||||
|
bool days_flag)
|
||||||
|
{
|
||||||
|
char time_str[40];
|
||||||
|
time_str[0] = '\0';
|
||||||
|
if (days_flag)
|
||||||
|
{
|
||||||
|
snprintf(time_str, sizeof(time_str),
|
||||||
|
"%ld ",
|
||||||
|
value->tv_sec / (24 * 3600));
|
||||||
|
}
|
||||||
|
strcat(time_str, make_timestamp(value));
|
||||||
|
show_text(buffer, title, time_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the counter display page on socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*
|
||||||
|
* The counter display page shows the state of the counter and contains
|
||||||
|
* buttons which allow commands to be issued to the counter. It will be
|
||||||
|
* periodically refreshed.
|
||||||
|
*/
|
||||||
|
void put_page(int n)
|
||||||
|
{
|
||||||
|
dprintf(0, "put_page\n");
|
||||||
|
BUFFER html;
|
||||||
|
BUFFER buffer;
|
||||||
|
COUNTER* cp = &counter;
|
||||||
|
PARAMETERS* pp = &counter.params;
|
||||||
|
SAMPLE* sp;
|
||||||
|
char *bp;
|
||||||
|
int refresh;
|
||||||
|
#if 1
|
||||||
|
{
|
||||||
|
refresh = cntr_time_to_next_report(cp) + 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
make_report(cp);
|
||||||
|
refresh = (pp->poll_period * pp->sample_period * pp->report_period + 500) / 1000;
|
||||||
|
#endif
|
||||||
|
if (refresh < MIN_REFRESH)
|
||||||
|
refresh = MIN_REFRESH;
|
||||||
|
if (refresh > MAX_REFRESH)
|
||||||
|
refresh = MAX_REFRESH;
|
||||||
|
sp = &cp->report;
|
||||||
|
buffer.length = 0;
|
||||||
|
bp = &buffer.body[buffer.length];
|
||||||
|
snprintf(bp, sizeof(buffer.body) - buffer.length,
|
||||||
|
"<html><head><title>Counter Page</title></head>\r\n"
|
||||||
|
"<body>\r\n"
|
||||||
|
"<table align=\"center\" border=\"0\"><tr><td>\r\n"
|
||||||
|
"<table align=\"center\" border=\"0\">\r\n"
|
||||||
|
"<tr><th align=\"right\">Field</th>\r\n"
|
||||||
|
"<th align=\"left\">Value</th></tr>\r\n");
|
||||||
|
buffer.length += strlen(bp);
|
||||||
|
show_text(&buffer, "State", cp->state == counter_stopped ? "STOPPED" :
|
||||||
|
cp->state == counter_running ? "RUNNING" :
|
||||||
|
cp->state == counter_paused ? "PAUSED" : "IDLE");
|
||||||
|
show_text(&buffer, "Direction", pp->direction == COUNT_UP ? "UP" : "DOWN");
|
||||||
|
show_int(&buffer, "Scan", pp->poll_period);
|
||||||
|
show_int(&buffer, "Sample", pp->sample_period);
|
||||||
|
show_int(&buffer, "Report", pp->report_period);
|
||||||
|
show_time(&buffer, "Start Time", &cp->start_time, false);
|
||||||
|
show_time(&buffer, "Current Time", &cp->current_time, false);
|
||||||
|
{
|
||||||
|
struct timeval tv = cp->stop_time;
|
||||||
|
if (cp->state == counter_running || cp->state == counter_paused)
|
||||||
|
{
|
||||||
|
tv = cp->current_time;
|
||||||
|
}
|
||||||
|
time_sub(&tv, &cp->start_time);
|
||||||
|
show_time(&buffer, "Elapsed", &tv, true);
|
||||||
|
}
|
||||||
|
show_time(&buffer, "Runtime", &cp->accumulated, true);
|
||||||
|
show_time(&buffer, "Report Time", &sp->timestamp, false);
|
||||||
|
show_counter(&buffer, "Counter", sp->counter_value);
|
||||||
|
show_int(&buffer, "Num Polls", sp->num_polls);
|
||||||
|
show_int(&buffer, "Poll Number", sp->poll_counter);
|
||||||
|
show_int(&buffer, "Sample Number", sp->sample_counter);
|
||||||
|
show_real(&buffer, "Rate", sp->counter_rate);
|
||||||
|
show_real(&buffer, "Min", sp->minimum_rate);
|
||||||
|
show_real(&buffer, "Ave", sp->average_rate);
|
||||||
|
show_real(&buffer, "Max", sp->maximum_rate);
|
||||||
|
if (pp->range_check_enable)
|
||||||
|
{
|
||||||
|
char* result;
|
||||||
|
if (cp->range_error == 1)
|
||||||
|
result = "<font color=\"BLUE\">LOW</font>";
|
||||||
|
else if (cp->range_error == 2)
|
||||||
|
result = "<font color=\"RED\">HIGH</font>";
|
||||||
|
else
|
||||||
|
result = "<font color=\"GREEN\">OK</font>";
|
||||||
|
show_text(&buffer, "Range Check", result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
show_text(&buffer, "Range Check", "Disabled");
|
||||||
|
add_text(&buffer, "</table></td><td valign=\"top\"><table>\r\n");
|
||||||
|
add_text(&buffer, "<tr><td><a href=\"/form\">\r\n"
|
||||||
|
"<button>Form</button>\r\n"
|
||||||
|
"</a></td></tr>\r\n");
|
||||||
|
add_text(&buffer, "<tr><td><a href=\"/cmd=start\">\r\n"
|
||||||
|
"<button>Start</button>\r\n"
|
||||||
|
"</a></td></tr>\r\n");
|
||||||
|
add_text(&buffer, "<tr><td><a href=\"/cmd=stop\">\r\n"
|
||||||
|
"<button>Stop</button>\r\n"
|
||||||
|
"</a></td></tr>\r\n");
|
||||||
|
add_text(&buffer, "<tr><td><a href=\"/cmd=pause\">\r\n"
|
||||||
|
"<button>Pause</button>\r\n"
|
||||||
|
"</a></td></tr>\r\n");
|
||||||
|
add_text(&buffer, "<tr><td><a href=\"/cmd=continue\">\r\n"
|
||||||
|
"<button>Continue</button>\r\n"
|
||||||
|
"</a></td></tr>\r\n");
|
||||||
|
add_text(&buffer, "</table></td></tr>\r\n");
|
||||||
|
add_text(&buffer, "</table>\r\n"
|
||||||
|
"</body>\r\n"
|
||||||
|
"</html>\r\n");
|
||||||
|
html.length = 0;
|
||||||
|
bp = &html.body[html.length];
|
||||||
|
snprintf(bp, sizeof(html.body) - html.length,
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"Refresh: %d\r\n"
|
||||||
|
"\r\n",
|
||||||
|
buffer.length,
|
||||||
|
refresh);
|
||||||
|
strcat(html.body, buffer.body);
|
||||||
|
html.length = strlen(html.body);
|
||||||
|
sock_send(n, &html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the control form in the buffer on the socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
* \param bp buffer containing form input
|
||||||
|
*
|
||||||
|
* The form is sent by a browser and contains name=value pairs which are used
|
||||||
|
* to set the counter parameters.
|
||||||
|
*/
|
||||||
|
void process_form(int n, BUFFER* bp)
|
||||||
|
{
|
||||||
|
dprintf(0, "process_form\n");
|
||||||
|
int i, j;
|
||||||
|
int state;
|
||||||
|
char name[80];
|
||||||
|
char value[80];
|
||||||
|
char hex_str[3];
|
||||||
|
unsigned int hex_val;
|
||||||
|
char* cp;
|
||||||
|
state = 0;
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; i < bp->length; ++i)
|
||||||
|
{
|
||||||
|
cp = &bp->body[i];
|
||||||
|
if (state == 0)
|
||||||
|
{
|
||||||
|
if (*cp == '=')
|
||||||
|
{
|
||||||
|
name[j++] = '\0';
|
||||||
|
j = 0;
|
||||||
|
state = 1;
|
||||||
|
}
|
||||||
|
else if (j < 80 - 1)
|
||||||
|
name[j++] = tolower(*cp);
|
||||||
|
}
|
||||||
|
else if (state == 1)
|
||||||
|
{
|
||||||
|
if (*cp == '&')
|
||||||
|
{
|
||||||
|
value[j++] = '\0';
|
||||||
|
j = 0;
|
||||||
|
state = 9;
|
||||||
|
}
|
||||||
|
else if (*cp == '%')
|
||||||
|
{
|
||||||
|
hex_str[0] = '\0';
|
||||||
|
state = 2;
|
||||||
|
}
|
||||||
|
else if (j < 80 - 1)
|
||||||
|
value[j++] = tolower(*cp);
|
||||||
|
}
|
||||||
|
else if (state == 2)
|
||||||
|
{
|
||||||
|
hex_str[0] = tolower(*cp);
|
||||||
|
state = 3;
|
||||||
|
}
|
||||||
|
else if (state == 3)
|
||||||
|
{
|
||||||
|
hex_str[1] = tolower(*cp);
|
||||||
|
hex_str[2] = '\0';
|
||||||
|
hex_val = strtoul(hex_str, NULL, 16);
|
||||||
|
if (hex_val < ' ' || hex_val > '~')
|
||||||
|
hex_val = '?';
|
||||||
|
if (j < 80 - 1)
|
||||||
|
value[j++] = tolower(hex_val);
|
||||||
|
state = 1;
|
||||||
|
}
|
||||||
|
if (state == 9)
|
||||||
|
{
|
||||||
|
dprintf(0, "name=\"%s\", value=\"%s\"\n", name, value);
|
||||||
|
if (param_set(&counter.params, name, value))
|
||||||
|
;
|
||||||
|
else if (strcmp(name, "xxx"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cause the browser to refresh the page
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*
|
||||||
|
* Used after a command button to redirect to the display page. Uses
|
||||||
|
* HTTP 303 REDIRECT to get the browser to display the page.
|
||||||
|
*/
|
||||||
|
void put_page_refresh(int n)
|
||||||
|
{
|
||||||
|
dprintf(0, "put_page_refresh\n");
|
||||||
|
BUFFER html;
|
||||||
|
BUFFER buffer;
|
||||||
|
char* bp;
|
||||||
|
COUNTER* cp = &counter;
|
||||||
|
|
||||||
|
int refresh;
|
||||||
|
#if 1
|
||||||
|
{
|
||||||
|
refresh = cntr_time_to_next_report(cp) + 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
PARAMETERS* pp = &counter.params;
|
||||||
|
make_report(cp);
|
||||||
|
refresh = (pp->poll_period * pp->sample_period * pp->report_period + 500) / 1000;
|
||||||
|
#endif
|
||||||
|
if (refresh < MIN_REFRESH)
|
||||||
|
refresh = MIN_REFRESH;
|
||||||
|
if (refresh > MAX_REFRESH)
|
||||||
|
refresh = MAX_REFRESH;
|
||||||
|
|
||||||
|
buffer.length = 0;
|
||||||
|
add_text(&buffer, "<html>\r\n"
|
||||||
|
"<head>\r\n"
|
||||||
|
"<title>Title</title>\r\n"
|
||||||
|
"</head>\r\n"
|
||||||
|
"<body>\r\n");
|
||||||
|
add_text(&buffer, "</body>\r\n"
|
||||||
|
"</html>\r\n");
|
||||||
|
html.length = 0;
|
||||||
|
bp = &html.body[html.length];
|
||||||
|
snprintf(bp, sizeof(html.body) - html.length,
|
||||||
|
"HTTP/1.1 303 REDIRECT\r\n"
|
||||||
|
"Location: page\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"\r\n",
|
||||||
|
buffer.length);
|
||||||
|
strcat(html.body, buffer.body);
|
||||||
|
html.length = strlen(html.body);
|
||||||
|
sock_send(n, &html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cause the browser to refresh the form
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*
|
||||||
|
* Used after a command button to redirect to the control form. Uses
|
||||||
|
* HTTP 303 REDIRECT to get the browser to display the form.
|
||||||
|
*/
|
||||||
|
void put_form_refresh(int n)
|
||||||
|
{
|
||||||
|
dprintf(0, "put_form_refresh\n");
|
||||||
|
BUFFER html;
|
||||||
|
BUFFER buffer;
|
||||||
|
char* bp;
|
||||||
|
COUNTER* cp = &counter;
|
||||||
|
|
||||||
|
int refresh;
|
||||||
|
#if 1
|
||||||
|
{
|
||||||
|
refresh = cntr_time_to_next_report(cp) + 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
PARAMETERS* pp = &counter.params;
|
||||||
|
make_report(cp);
|
||||||
|
refresh = (pp->poll_period * pp->sample_period * pp->report_period + 500) / 1000;
|
||||||
|
#endif
|
||||||
|
if (refresh < MIN_REFRESH)
|
||||||
|
refresh = MIN_REFRESH;
|
||||||
|
if (refresh > MAX_REFRESH)
|
||||||
|
refresh = MAX_REFRESH;
|
||||||
|
|
||||||
|
buffer.length = 0;
|
||||||
|
add_text(&buffer, "<html>\r\n"
|
||||||
|
"<head>\r\n"
|
||||||
|
"<title>Title</title>\r\n"
|
||||||
|
"</head>\r\n"
|
||||||
|
"<body>\r\n");
|
||||||
|
add_text(&buffer, "</body>\r\n"
|
||||||
|
"</html>\r\n");
|
||||||
|
html.length = 0;
|
||||||
|
bp = &html.body[html.length];
|
||||||
|
snprintf(bp, sizeof(html.body) - html.length,
|
||||||
|
"HTTP/1.1 303 REDIRECT\r\n"
|
||||||
|
"Location: form\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"\r\n",
|
||||||
|
buffer.length);
|
||||||
|
strcat(html.body, buffer.body);
|
||||||
|
html.length = strlen(html.body);
|
||||||
|
sock_send(n, &html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the command in the buffer on the socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
* \param bp buffer containing command
|
||||||
|
*
|
||||||
|
* Handles non-browser commands like SICS commands.
|
||||||
|
*/
|
||||||
|
void process_command(int n, BUFFER* bp)
|
||||||
|
{
|
||||||
|
dprintf(0, "process_command(%d, %s)\n", n, bp->body);
|
||||||
|
bool sics = false;
|
||||||
|
int error = 1;
|
||||||
|
char command[80];
|
||||||
|
char param[80];
|
||||||
|
int len = 0;
|
||||||
|
char* cp = bp->body;
|
||||||
|
while (isspace(*cp))
|
||||||
|
++cp;
|
||||||
|
len = 0;
|
||||||
|
while (*cp && !isspace(*cp))
|
||||||
|
{
|
||||||
|
if (len < 80 - 1)
|
||||||
|
command[len++] = *cp;
|
||||||
|
++cp;
|
||||||
|
}
|
||||||
|
command[len] = '\0';
|
||||||
|
if (strcasecmp(command, "SICS") == 0)
|
||||||
|
{
|
||||||
|
sics = true;
|
||||||
|
while (isspace(*cp))
|
||||||
|
++cp;
|
||||||
|
len = 0;
|
||||||
|
while (*cp && !isspace(*cp))
|
||||||
|
{
|
||||||
|
if (len < 80 - 1)
|
||||||
|
command[len++] = *cp;
|
||||||
|
++cp;
|
||||||
|
}
|
||||||
|
command[len] = '\0';
|
||||||
|
}
|
||||||
|
while (isspace(*cp))
|
||||||
|
++cp;
|
||||||
|
if (strcasecmp(command, "START") == 0)
|
||||||
|
error = cntr_start(&counter);
|
||||||
|
else if (strcasecmp(command, "STOP") == 0)
|
||||||
|
error = cntr_stop(&counter);
|
||||||
|
else if (strcasecmp(command, "PAUSE") == 0)
|
||||||
|
error = cntr_pause(&counter);
|
||||||
|
else if (strcasecmp(command, "RESUME") == 0)
|
||||||
|
error = cntr_resume(&counter);
|
||||||
|
else if (strcasecmp(command, "REPORT") == 0)
|
||||||
|
{
|
||||||
|
int match = 1;
|
||||||
|
error = 0;
|
||||||
|
if (sics)
|
||||||
|
match = 2;
|
||||||
|
len = 0;
|
||||||
|
while (*cp && !isspace(*cp))
|
||||||
|
{
|
||||||
|
if (len < 80 - 1)
|
||||||
|
param[len++] = *cp;
|
||||||
|
++cp;
|
||||||
|
}
|
||||||
|
param[len] = '\0';
|
||||||
|
if (strcasecmp(param, "OFF") == 0)
|
||||||
|
match = 0;
|
||||||
|
sock_set_match(n, match);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(command, "SET") == 0)
|
||||||
|
{
|
||||||
|
/* set parameter */
|
||||||
|
dprintf(0, "SET %s\n", cp);
|
||||||
|
if (param_set_cmd(&counter.params, cp))
|
||||||
|
error = 0;
|
||||||
|
}
|
||||||
|
else if (strcasecmp(command, "GET") == 0)
|
||||||
|
{
|
||||||
|
/* get parameter */
|
||||||
|
param_get_cmd(&counter.params, cp, n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (strcasecmp(command, "READ") == 0)
|
||||||
|
{
|
||||||
|
cntr_read(&counter, n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!sics)
|
||||||
|
{
|
||||||
|
cntr_send(&counter, n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (error == 0)
|
||||||
|
sock_ok(n);
|
||||||
|
else
|
||||||
|
sock_err(n);
|
||||||
|
}
|
||||||
15
site_ansto/hardsup/Monitor/display.h
Normal file
15
site_ansto/hardsup/Monitor/display.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Processing of display interaction
|
||||||
|
*/
|
||||||
|
#ifndef _DISPLAY_H_
|
||||||
|
#define _DISPLAY_H_
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
|
void put_page(int n);
|
||||||
|
void put_form(int n);
|
||||||
|
void process_form(int n, BUFFER* bp);
|
||||||
|
void put_page_refresh(int n);
|
||||||
|
void put_form_refresh(int n);
|
||||||
|
void process_command(int n, BUFFER* bp);
|
||||||
|
|
||||||
|
#endif
|
||||||
105
site_ansto/hardsup/Monitor/hctr.c
Normal file
105
site_ansto/hardsup/Monitor/hctr.c
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#include "hctr.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <NIDAQmx.h>
|
||||||
|
|
||||||
|
#define DAQmxErrChk(functionCall) \
|
||||||
|
if( DAQmxFailed(error=(functionCall)) ) \
|
||||||
|
goto Error; \
|
||||||
|
else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 counter value, as returned by NIDAQ
|
||||||
|
* read function */
|
||||||
|
uInt32 count32;
|
||||||
|
/** extended 64-bit counter value */
|
||||||
|
unsigned long long count64;
|
||||||
|
} COUNTER_PRIVATE;
|
||||||
|
|
||||||
|
int hctr_ctor(const char* device_name, pHCTR* ptr)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
*ptr = (COUNTER_PRIVATE*) malloc(sizeof(COUNTER_PRIVATE));
|
||||||
|
memset(*ptr, 0, sizeof(COUNTER_PRIVATE));
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
Error:
|
||||||
|
free(*ptr);
|
||||||
|
*ptr = NULL;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hctr_read(pHCTR hctr, unsigned long long* value)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
uInt32 ctr;
|
||||||
|
DAQmxErrChk (DAQmxReadCounterScalarU32(hctr->taskHandle,
|
||||||
|
1.0,
|
||||||
|
&ctr,
|
||||||
|
NULL));
|
||||||
|
hctr->count64 += ctr - hctr->count32;
|
||||||
|
hctr->count32 = ctr;
|
||||||
|
*value = hctr->count64;
|
||||||
|
return 0;
|
||||||
|
Error:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hctr_dtor(pHCTR* hctr)
|
||||||
|
{
|
||||||
|
if( hctr && *hctr && (*hctr)->taskHandle!=0 )
|
||||||
|
{
|
||||||
|
/*********************************************/
|
||||||
|
// DAQmx Stop Code
|
||||||
|
/*********************************************/
|
||||||
|
DAQmxStopTask((*hctr)->taskHandle);
|
||||||
|
DAQmxClearTask((*hctr)->taskHandle);
|
||||||
|
}
|
||||||
|
(*hctr)->taskHandle = 0;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
72
site_ansto/hardsup/Monitor/hctr.h
Normal file
72
site_ansto/hardsup/Monitor/hctr.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
|
||||||
384
site_ansto/hardsup/Monitor/params.c
Normal file
384
site_ansto/hardsup/Monitor/params.c
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
#include "params.h"
|
||||||
|
#include "sock.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#define CMD_DIRECTION 1
|
||||||
|
#define CMD_SCAN 2
|
||||||
|
#define CMD_SAMPLE 3
|
||||||
|
#define CMD_REPORT 4
|
||||||
|
#define CMD_INITIAL 5
|
||||||
|
#define CMD_TERMINAL 6
|
||||||
|
#define CMD_RANGE_LOW 7
|
||||||
|
#define CMD_RANGE_HIGH 8
|
||||||
|
#define CMD_TE_CHECK 9
|
||||||
|
#define CMD_RE_CHECK 10
|
||||||
|
#define CMD_RANGE_GATE 11
|
||||||
|
#define CMD_RANGE_MODE 12
|
||||||
|
|
||||||
|
#define TXT_DIRECTION "DIRECTION"
|
||||||
|
#define TXT_SCAN "SCAN"
|
||||||
|
#define TXT_SAMPLE "SAMPLE"
|
||||||
|
#define TXT_REPORT "REPORT"
|
||||||
|
#define TXT_INITIAL "INITIAL"
|
||||||
|
#define TXT_TERMINAL "TERMINAL"
|
||||||
|
#define TXT_RANGE_LOW "RANGE_LOW"
|
||||||
|
#define TXT_RANGE_HIGH "RANGE_HIGH"
|
||||||
|
#define TXT_TE_CHECK "TE_CHECK"
|
||||||
|
#define TXT_RE_CHECK "RE_CHECK"
|
||||||
|
#define TXT_RANGE_GATE "RANGE_GATE"
|
||||||
|
#define TXT_RANGE_MODE "RANGE_MODE"
|
||||||
|
|
||||||
|
static struct param_command_t {
|
||||||
|
int cmd;
|
||||||
|
char* txt;
|
||||||
|
} param_command[] = {
|
||||||
|
{CMD_DIRECTION, TXT_DIRECTION},
|
||||||
|
{CMD_SCAN, TXT_SCAN},
|
||||||
|
{CMD_SAMPLE, TXT_SAMPLE},
|
||||||
|
{CMD_REPORT, TXT_REPORT},
|
||||||
|
{CMD_INITIAL, TXT_INITIAL},
|
||||||
|
{CMD_TERMINAL, TXT_TERMINAL},
|
||||||
|
{CMD_RANGE_LOW, TXT_RANGE_LOW},
|
||||||
|
{CMD_RANGE_HIGH, TXT_RANGE_HIGH},
|
||||||
|
{CMD_TE_CHECK, TXT_TE_CHECK},
|
||||||
|
{CMD_RE_CHECK, TXT_RE_CHECK},
|
||||||
|
{CMD_RANGE_GATE, TXT_RANGE_GATE},
|
||||||
|
{CMD_RANGE_MODE, TXT_RANGE_MODE},
|
||||||
|
{0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool param_set(pPARAMETERS pp, char* name, char* value)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
switch (name[0])
|
||||||
|
{
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
if (strcasecmp(name, TXT_DIRECTION) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "Direction=%s", pp->direction ? "Down" : "Up");
|
||||||
|
if (strcasecmp(value, "down") == 0)
|
||||||
|
pp->direction = COUNT_DOWN;
|
||||||
|
else
|
||||||
|
pp->direction = COUNT_UP;
|
||||||
|
dprintf(0, "=>%s\n", pp->direction ? "Down" : "Up");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
case 'I':
|
||||||
|
if (strcasecmp(name, TXT_INITIAL) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "Initial=%llu", pp->initial_count);
|
||||||
|
pp->initial_count = strtoull(value, NULL, 10);
|
||||||
|
dprintf(0, "=>%llu\n", pp->initial_count);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
if (strcasecmp(name, TXT_REPORT) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "Report=%d", pp->report_period);
|
||||||
|
pp->report_period = strtol(value, NULL, 10);
|
||||||
|
if (pp->report_period < 1)
|
||||||
|
pp->report_period = 1;
|
||||||
|
else if (pp->report_period > 1000)
|
||||||
|
pp->report_period = 1000;
|
||||||
|
dprintf(0, "=>%d\n", pp->report_period);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RANGE_MODE) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "range_mode=%d", pp->range_mode);
|
||||||
|
pp->range_mode = strtol(value, NULL, 10);
|
||||||
|
if (pp->range_mode < 0)
|
||||||
|
pp->range_mode = 0;
|
||||||
|
else if (pp->range_mode > 2)
|
||||||
|
pp->range_mode = 0;
|
||||||
|
dprintf(0, "=>%d\n", pp->range_mode);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RANGE_GATE) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "range_gate=%s",
|
||||||
|
pp->range_gate_enable ? "Enabled" : "Disabled");
|
||||||
|
if (strcasecmp(value, "enabled") == 0)
|
||||||
|
pp->range_gate_enable = true;
|
||||||
|
else
|
||||||
|
pp->range_gate_enable = false;
|
||||||
|
dprintf(0, "=>%s\n",
|
||||||
|
pp->range_gate_enable ? "Enabled" : "Disabled");
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RE_CHECK) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "RE_Check=%s",
|
||||||
|
pp->range_check_enable ? "Enabled" : "Disabled");
|
||||||
|
if (strcasecmp(value, "enabled") == 0)
|
||||||
|
pp->range_check_enable = true;
|
||||||
|
else
|
||||||
|
pp->range_check_enable = false;
|
||||||
|
dprintf(0, "=>%s\n",
|
||||||
|
pp->range_check_enable ? "Enabled" : "Disabled");
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RANGE_HIGH) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "RangeHigh=%g", pp->range_high);
|
||||||
|
pp->range_high = strtod(value, NULL);
|
||||||
|
if (pp->range_high < 0.0)
|
||||||
|
pp->range_high = 0.0;
|
||||||
|
dprintf(0, "=>%g\n", pp->range_high);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RANGE_LOW) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "RangeLow=%g", pp->range_low);
|
||||||
|
pp->range_low = strtod(value, NULL);
|
||||||
|
if (pp->range_low < 0.0)
|
||||||
|
pp->range_low = 0.0;
|
||||||
|
dprintf(0, "=>%g\n", pp->range_low);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
case 'S':
|
||||||
|
if (strcasecmp(name, TXT_SCAN) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "Scan=%d", pp->poll_period);
|
||||||
|
pp->poll_period = strtol(value, NULL, 10);
|
||||||
|
if (pp->poll_period < 1)
|
||||||
|
pp->poll_period = 1;
|
||||||
|
else if (pp->poll_period > 1000)
|
||||||
|
pp->poll_period = 1000;
|
||||||
|
dprintf(0, "=>%d\n", pp->poll_period);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_SAMPLE) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "Sample=%d", pp->sample_period);
|
||||||
|
pp->sample_period = strtol(value, NULL, 10);
|
||||||
|
if (pp->sample_period < 1)
|
||||||
|
pp->sample_period = 1;
|
||||||
|
else if (pp->sample_period > 1000)
|
||||||
|
pp->sample_period = 1000;
|
||||||
|
dprintf(0, "=>%d\n", pp->sample_period);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
if (strcasecmp(name, TXT_TERMINAL) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "Sample=%llu", pp->terminal_count);
|
||||||
|
pp->terminal_count = strtoull(value, NULL, 10);
|
||||||
|
dprintf(0, "=>%llu\n", pp->terminal_count);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_TE_CHECK) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
dprintf(0, "TE_Check=%s",
|
||||||
|
pp->terminal_check_type == 0 ? "None" :
|
||||||
|
pp->terminal_check_type == 1 ? "Counter" :
|
||||||
|
pp->terminal_check_type == 2 ? "Timer" : "Unknown");
|
||||||
|
if (strcasecmp(value, "counter") == 0)
|
||||||
|
pp->terminal_check_type = 1;
|
||||||
|
else if (strcasecmp(value, "timer") == 0)
|
||||||
|
pp->terminal_check_type = 2;
|
||||||
|
else
|
||||||
|
pp->terminal_check_type = 0;
|
||||||
|
dprintf(0, "=>%s\n",
|
||||||
|
pp->terminal_check_type == 0 ? "None" :
|
||||||
|
pp->terminal_check_type == 1 ? "Counter" :
|
||||||
|
pp->terminal_check_type == 2 ? "Timer" : "Unknown");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintf(0, "Unknown Parameter: \"%s\" = \"%s\"\n", name, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool param_set_cmd(pPARAMETERS pp, char* cmd)
|
||||||
|
{
|
||||||
|
char name[100];
|
||||||
|
char value[100];
|
||||||
|
int len;
|
||||||
|
while (isspace(*cmd))
|
||||||
|
++cmd;
|
||||||
|
len = 0;
|
||||||
|
while (*cmd && !isspace(*cmd) && *cmd != '=')
|
||||||
|
{
|
||||||
|
if (len < 100 - 1)
|
||||||
|
name[len++] = *cmd;
|
||||||
|
++cmd;
|
||||||
|
}
|
||||||
|
name[len] = '\0';
|
||||||
|
|
||||||
|
while (isspace(*cmd))
|
||||||
|
++cmd;
|
||||||
|
if (*cmd != '=')
|
||||||
|
return false;
|
||||||
|
++cmd;
|
||||||
|
while (isspace(*cmd))
|
||||||
|
++cmd;
|
||||||
|
len = 0;
|
||||||
|
while (*cmd && !isspace(*cmd))
|
||||||
|
{
|
||||||
|
if (len < 100 - 1)
|
||||||
|
value[len++] = *cmd;
|
||||||
|
++cmd;
|
||||||
|
}
|
||||||
|
value[len] = '\0';
|
||||||
|
|
||||||
|
return param_set(pp, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool param_get_cmd(pPARAMETERS pp, char* cmd, int n)
|
||||||
|
{
|
||||||
|
char name[100];
|
||||||
|
int len;
|
||||||
|
bool result = false;
|
||||||
|
BUFFER buffer;
|
||||||
|
buffer.length = 0;
|
||||||
|
|
||||||
|
while (isspace(*cmd))
|
||||||
|
++cmd;
|
||||||
|
len = 0;
|
||||||
|
while (*cmd && !isspace(*cmd) && *cmd != '=')
|
||||||
|
{
|
||||||
|
if (len < 100 - 1)
|
||||||
|
name[len++] = *cmd;
|
||||||
|
++cmd;
|
||||||
|
}
|
||||||
|
name[len] = '\0';
|
||||||
|
|
||||||
|
switch (name[0])
|
||||||
|
{
|
||||||
|
case 'a':
|
||||||
|
case 'A':
|
||||||
|
if (strcasecmp(name, "ALL") == 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; param_command[i].txt; ++i)
|
||||||
|
param_get_cmd(pp, param_command[i].txt, n);
|
||||||
|
strcpy(buffer.body, "OK");
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
if (strcasecmp(name, TXT_DIRECTION) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%s", name,
|
||||||
|
pp->direction ? "Down" : "Up");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
case 'I':
|
||||||
|
if (strcasecmp(name, TXT_INITIAL) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%llu", name,
|
||||||
|
pp->initial_count);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
if (strcasecmp(name, TXT_REPORT) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%d", name,
|
||||||
|
pp->report_period);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RANGE_GATE) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%s", name,
|
||||||
|
pp->range_gate_enable ? "Enabled" : "Disabled");
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RE_CHECK) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%s", name,
|
||||||
|
pp->range_check_enable ? "Enabled" : "Disabled");
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RANGE_MODE) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%d", name,
|
||||||
|
pp->range_mode);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RANGE_HIGH) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%g", name,
|
||||||
|
pp->range_high);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_RANGE_LOW) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%g", name,
|
||||||
|
pp->range_low);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
case 'S':
|
||||||
|
if (strcasecmp(name, TXT_SCAN) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%d", name,
|
||||||
|
pp->poll_period);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_SAMPLE) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%d", name,
|
||||||
|
pp->sample_period);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
if (strcasecmp(name, TXT_TERMINAL) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%llu", name,
|
||||||
|
pp->terminal_count);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(name, TXT_TE_CHECK) == 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body),
|
||||||
|
"GET %s=%s", name,
|
||||||
|
pp->terminal_check_type == 0 ? "None" :
|
||||||
|
pp->terminal_check_type == 1 ? "Counter" :
|
||||||
|
pp->terminal_check_type == 2 ? "Timer" : "Unknown");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintf(0, "Unknown GET Parameter: \"%s\"\n", name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!result)
|
||||||
|
snprintf(buffer.body, sizeof(buffer.body), "GET ERR");
|
||||||
|
strcat(buffer.body, "\r\n");
|
||||||
|
buffer.length = strlen(buffer.body);
|
||||||
|
sock_send(n, &buffer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
44
site_ansto/hardsup/Monitor/params.h
Normal file
44
site_ansto/hardsup/Monitor/params.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef _PARAM_H_
|
||||||
|
#define _PARAM_H_
|
||||||
|
|
||||||
|
#include "utility.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counter Control Parameters
|
||||||
|
*/
|
||||||
|
typedef struct parameter_t
|
||||||
|
{
|
||||||
|
/** direction of counting for the logical counter */
|
||||||
|
enum { COUNT_UP = 0, COUNT_DOWN } direction;
|
||||||
|
/** counter read period in milliseconds */
|
||||||
|
int poll_period;
|
||||||
|
/** sample period in number of reads per sample */
|
||||||
|
int sample_period;
|
||||||
|
/** report period in number of samples per report */
|
||||||
|
int report_period;
|
||||||
|
/** value of the logical counter on START, normally zero */
|
||||||
|
uint64 initial_count;
|
||||||
|
/** value for terminal count exception if enabled */
|
||||||
|
uint64 terminal_count;
|
||||||
|
/** low limit for acceptable range or zero */
|
||||||
|
double range_low;
|
||||||
|
/** high limit for acceptable range or zero */
|
||||||
|
double range_high;
|
||||||
|
/** type = 0:none, 1:count, 2:time */
|
||||||
|
int terminal_check_type;
|
||||||
|
/** true if range exception enabled */
|
||||||
|
bool range_check_enable;
|
||||||
|
/** true if range gating enabled */
|
||||||
|
bool range_gate_enable;
|
||||||
|
/** mode = 0:report, 1:sample, 2:poll */
|
||||||
|
int range_mode;
|
||||||
|
|
||||||
|
} PARAMETERS, *pPARAMETERS;
|
||||||
|
|
||||||
|
bool param_set(pPARAMETERS pp, char* name, char* value);
|
||||||
|
bool param_set_cmd(pPARAMETERS pp, char* cmd);
|
||||||
|
bool param_get_cmd(pPARAMETERS pp, char* cmd, int n);
|
||||||
|
#endif
|
||||||
504
site_ansto/hardsup/Monitor/sock.c
Normal file
504
site_ansto/hardsup/Monitor/sock.c
Normal file
@@ -0,0 +1,504 @@
|
|||||||
|
#include "sock.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "cntr.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h> /* superset of previous */
|
||||||
|
|
||||||
|
#define LINE_LEN 1024
|
||||||
|
#define MAX_SOCK 50
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mode of the socket
|
||||||
|
*/
|
||||||
|
typedef enum terminal_mode_t
|
||||||
|
{
|
||||||
|
/** unknown or uninitialised */
|
||||||
|
term_idle = 0,
|
||||||
|
/** telnet socket */
|
||||||
|
term_tty,
|
||||||
|
/** web page GET */
|
||||||
|
term_page,
|
||||||
|
/** web form POST */
|
||||||
|
term_form,
|
||||||
|
/** SOAP request */
|
||||||
|
term_soap
|
||||||
|
} TERM_MODE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminal Control Structure
|
||||||
|
*
|
||||||
|
* Maintains the state of the connection
|
||||||
|
*/
|
||||||
|
typedef struct terminal_t
|
||||||
|
{
|
||||||
|
/** file descriptor for the socket */
|
||||||
|
int fd;
|
||||||
|
/** mode of the connection */
|
||||||
|
TERM_MODE mode;
|
||||||
|
/** current state of the connection */
|
||||||
|
int state;
|
||||||
|
/** value to match for reports */
|
||||||
|
int match;
|
||||||
|
/** TOD socket connected */
|
||||||
|
struct timeval connect_time;
|
||||||
|
/** address of peer */
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
/** function to handle input ready */
|
||||||
|
void (*input)(int idx);
|
||||||
|
/** input line buffer */
|
||||||
|
char line[LINE_LEN];
|
||||||
|
/** length of text in line */
|
||||||
|
int line_len;
|
||||||
|
/** URL for GET/POST */
|
||||||
|
char url[LINE_LEN];
|
||||||
|
/** value from Content-Length header */
|
||||||
|
int content_length;
|
||||||
|
} TERMINAL, *pTERMINAL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of terminal control structures
|
||||||
|
*/
|
||||||
|
static TERMINAL fdv[MAX_SOCK];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This structure parallels the terminal control structure
|
||||||
|
*/
|
||||||
|
static struct pollfd fds[MAX_SOCK];
|
||||||
|
/** Number of active connections */
|
||||||
|
static int num_fds = 0;
|
||||||
|
/** descriptor of the listen socket */
|
||||||
|
static int sock_l;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the socket interface
|
||||||
|
*
|
||||||
|
* Opens and binds the listen socket and listens for incomming
|
||||||
|
* connections.
|
||||||
|
*
|
||||||
|
* \param addr the TCP/IP port number on which to listen
|
||||||
|
*/
|
||||||
|
void sock_init(int addr)
|
||||||
|
{
|
||||||
|
dprintf(0, "sock_init\n");
|
||||||
|
int status;
|
||||||
|
long flags;
|
||||||
|
int i;
|
||||||
|
int one = 1;
|
||||||
|
struct sockaddr_in my_addr;
|
||||||
|
memset(fdv, 0, sizeof(fdv));
|
||||||
|
for (i = 0; i < MAX_SOCK; ++i)
|
||||||
|
{
|
||||||
|
fdv[i].fd = -1;
|
||||||
|
}
|
||||||
|
memset(fds, 0, sizeof(fds));
|
||||||
|
status = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
perror("socket");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
sock_l = status;
|
||||||
|
flags = fcntl(sock_l, F_GETFL);
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
fcntl(sock_l, F_SETFL, flags);
|
||||||
|
setsockopt(sock_l, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||||
|
memset(&my_addr, 0, sizeof(my_addr));
|
||||||
|
my_addr.sin_family = AF_INET;
|
||||||
|
my_addr.sin_port = htons(addr);
|
||||||
|
my_addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
status = bind(sock_l, (struct sockaddr*) &my_addr, sizeof(my_addr));
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
perror("bind");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
status = listen(sock_l, 5);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
perror("listen");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
fds[0].fd = sock_l;
|
||||||
|
fds[0].events = POLLIN | POLLOUT;
|
||||||
|
fdv[0].fd = sock_l;
|
||||||
|
fdv[0].input = sock_accept;
|
||||||
|
++num_fds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for socket activity
|
||||||
|
*
|
||||||
|
* Polls active sockets for activity: connections on the listen socket or
|
||||||
|
* received data on the active sockets.
|
||||||
|
*
|
||||||
|
* \param timeout wait time in milliseconds
|
||||||
|
*/
|
||||||
|
void sock_check(int timeout)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ready;
|
||||||
|
ready = poll(fds, num_fds, timeout);
|
||||||
|
if (ready < 0)
|
||||||
|
{
|
||||||
|
perror("poll");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ready == 0)
|
||||||
|
return;
|
||||||
|
dprintf(0, "sock_check, ready=%d\n", ready);
|
||||||
|
for (i = 0; i < MAX_SOCK; ++i)
|
||||||
|
{
|
||||||
|
if (fds[i].revents)
|
||||||
|
{
|
||||||
|
if (fds[i].revents & POLLIN)
|
||||||
|
fdv[i].input(i);
|
||||||
|
if (--ready)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close and remove an active or disconnected socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*/
|
||||||
|
void sock_close(int n)
|
||||||
|
{
|
||||||
|
dprintf(0, "sock_close\n");
|
||||||
|
shutdown(fdv[n].fd, SHUT_RDWR);
|
||||||
|
close(fdv[n].fd);
|
||||||
|
if (n != num_fds)
|
||||||
|
{
|
||||||
|
fdv[n] = fdv[num_fds];
|
||||||
|
fds[n] = fds[num_fds];
|
||||||
|
}
|
||||||
|
fdv[num_fds].fd = -1;
|
||||||
|
--num_fds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a line of input from a socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*/
|
||||||
|
void sock_line(int n)
|
||||||
|
{
|
||||||
|
char *cp = &fdv[n].line[0];
|
||||||
|
char *up;
|
||||||
|
dprintf(0, "%3d: %s", fdv[n].state, fdv[n].line);
|
||||||
|
if (fdv[n].line[fdv[n].line_len - 1] != '\n')
|
||||||
|
dprintf(0, "\n");
|
||||||
|
switch(fdv[n].state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
/*
|
||||||
|
* we are looking for HTTP GET or POST or a SICS command
|
||||||
|
*/
|
||||||
|
if (toupper(cp[0]) == 'G' &&
|
||||||
|
toupper(cp[1]) == 'E' &&
|
||||||
|
toupper(cp[2]) == 'T' &&
|
||||||
|
isspace(cp[3]) &&
|
||||||
|
strstr(cp, "HTTP/"))
|
||||||
|
{
|
||||||
|
cp+= 4;
|
||||||
|
while (isspace(*cp))
|
||||||
|
++cp;
|
||||||
|
up = &fdv[n].url[0];
|
||||||
|
while (*cp && !isspace(*cp))
|
||||||
|
*up++ = *cp++;
|
||||||
|
*up = '\0';
|
||||||
|
fdv[n].state = 1;
|
||||||
|
}
|
||||||
|
else if (toupper(cp[0]) == 'P' &&
|
||||||
|
toupper(cp[1]) == 'O' &&
|
||||||
|
toupper(cp[2]) == 'S' &&
|
||||||
|
toupper(cp[3]) == 'T' &&
|
||||||
|
isspace(cp[4]) &&
|
||||||
|
strstr(cp, "HTTP/"))
|
||||||
|
{
|
||||||
|
cp+= 4;
|
||||||
|
while (isspace(*cp))
|
||||||
|
++cp;
|
||||||
|
up = &fdv[n].url[0];
|
||||||
|
while (*cp && !isspace(*cp))
|
||||||
|
*up++ = *cp++;
|
||||||
|
*up = '\0';
|
||||||
|
fdv[n].content_length = 0;
|
||||||
|
fdv[n].state = 3;
|
||||||
|
}
|
||||||
|
else if (toupper(cp[0]) == 'S' &&
|
||||||
|
toupper(cp[1]) == 'I' &&
|
||||||
|
toupper(cp[2]) == 'C' &&
|
||||||
|
toupper(cp[3]) == 'S' &&
|
||||||
|
isspace(cp[4]))
|
||||||
|
{
|
||||||
|
BUFFER buf;
|
||||||
|
memcpy(buf.body, fdv[n].line, fdv[n].line_len);
|
||||||
|
buf.length = fdv[n].line_len;
|
||||||
|
buf.body[buf.length] = '\0';
|
||||||
|
process_command(n, &buf);
|
||||||
|
fdv[n].content_length = 0;
|
||||||
|
fdv[n].state = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BUFFER buf;
|
||||||
|
memcpy(buf.body, fdv[n].line, fdv[n].line_len);
|
||||||
|
buf.length = fdv[n].line_len;
|
||||||
|
buf.body[buf.length] = '\0';
|
||||||
|
process_command(n, &buf);
|
||||||
|
fdv[n].content_length = 0;
|
||||||
|
fdv[n].state = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/*
|
||||||
|
* We are scanning the header of a GET
|
||||||
|
*/
|
||||||
|
while (*cp == '\r' || *cp == '\n')
|
||||||
|
++cp;
|
||||||
|
if (!*cp)
|
||||||
|
{
|
||||||
|
if (strncasecmp(fdv[n].url, "/form", 5) == 0)
|
||||||
|
put_form(n);
|
||||||
|
else if (strncasecmp(fdv[n].url, "/cmd=", 5) == 0)
|
||||||
|
{
|
||||||
|
if (strncasecmp(fdv[n].url, "/cmd=pause", 10) == 0)
|
||||||
|
cntr_pause(&counter);
|
||||||
|
else if (strncasecmp(fdv[n].url, "/cmd=continue", 10) == 0)
|
||||||
|
cntr_resume(&counter);
|
||||||
|
else if (strncasecmp(fdv[n].url, "/cmd=resume", 10) == 0)
|
||||||
|
cntr_resume(&counter);
|
||||||
|
else if (strncasecmp(fdv[n].url, "/cmd=start", 10) == 0)
|
||||||
|
cntr_start(&counter);
|
||||||
|
else if (strncasecmp(fdv[n].url, "/cmd=stop", 10) == 0)
|
||||||
|
cntr_stop(&counter);
|
||||||
|
put_page_refresh(n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
put_page(n);
|
||||||
|
fdv[n].state = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/*
|
||||||
|
* we are scanning the header of a POST
|
||||||
|
*/
|
||||||
|
while (*cp == '\r' || *cp == '\n')
|
||||||
|
++cp;
|
||||||
|
if (!*cp)
|
||||||
|
{
|
||||||
|
if (fdv[n].content_length == 0)
|
||||||
|
fdv[n].state = 5;
|
||||||
|
else
|
||||||
|
fdv[n].state = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncasecmp("Content-Length", cp, 14) == 0 &&
|
||||||
|
(cp = strchr(&cp[14], ':')))
|
||||||
|
{
|
||||||
|
fdv[n].content_length = atoi(&cp[1]);
|
||||||
|
dprintf(0, "Content Length = %d\n", fdv[n].content_length);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
/*
|
||||||
|
* we are scanning the body of a POST
|
||||||
|
*/
|
||||||
|
dprintf(0, "Content-Length: %d, Line-Length: %d\n",
|
||||||
|
fdv[n].content_length, fdv[n].line_len);
|
||||||
|
fdv[n].content_length -= fdv[n].line_len;
|
||||||
|
if (fdv[n].content_length <= 0)
|
||||||
|
{
|
||||||
|
BUFFER buf;
|
||||||
|
memcpy(buf.body, fdv[n].line, fdv[n].line_len);
|
||||||
|
buf.length = fdv[n].line_len;
|
||||||
|
process_form(n, &buf);
|
||||||
|
fdv[n].state = 5;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If we have reached the end of a POST, send the new form
|
||||||
|
*/
|
||||||
|
if (fdv[n].state == 5)
|
||||||
|
{
|
||||||
|
put_form(n);
|
||||||
|
fdv[n].state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle data received on a socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*/
|
||||||
|
void sock_input(int n)
|
||||||
|
{
|
||||||
|
dprintf(0, "sock_input(%d)\n", n);
|
||||||
|
ssize_t sz;
|
||||||
|
char buffer[1024];
|
||||||
|
sz = recv(fdv[n].fd, &buffer, sizeof(buffer), 0);
|
||||||
|
if (sz == 0)
|
||||||
|
{
|
||||||
|
sock_close(n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sz < 0)
|
||||||
|
{
|
||||||
|
if (errno == EAGAIN) /* AKA EWOULDBLOCK */
|
||||||
|
dprintf(0, "EAGAIN:");
|
||||||
|
else if (errno == ESPIPE) /* Illegal seek (on pipe or socket) */
|
||||||
|
dprintf(0, "ESPIPE:");
|
||||||
|
else
|
||||||
|
perror("recv");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < sz; ++i)
|
||||||
|
{
|
||||||
|
if (fdv[n].line_len < LINE_LEN - 1)
|
||||||
|
fdv[n].line[fdv[n].line_len++] = buffer[i];
|
||||||
|
if (buffer[i] == '\n' ||
|
||||||
|
(fdv[n].state == 4 &&
|
||||||
|
fdv[n].line_len == fdv[n].content_length)) {
|
||||||
|
fdv[n].line[fdv[n].line_len] = '\0';
|
||||||
|
sock_line(n);
|
||||||
|
fdv[n].line_len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle connection arrived on listen socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*/
|
||||||
|
void sock_accept(int n)
|
||||||
|
{
|
||||||
|
dprintf(0, "sock_accept(%d)\n", n);
|
||||||
|
int sock_n;
|
||||||
|
struct sockaddr_in my_addr;
|
||||||
|
socklen_t my_len = sizeof(my_addr);
|
||||||
|
sock_n = accept(fdv[n].fd, (struct sockaddr*) &my_addr, &my_len);
|
||||||
|
if (sock_n < 0)
|
||||||
|
{
|
||||||
|
perror("accept");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (num_fds < MAX_SOCK)
|
||||||
|
{
|
||||||
|
fdv[num_fds].fd = sock_n;
|
||||||
|
fdv[num_fds].addr = my_addr;
|
||||||
|
fdv[num_fds].input = sock_input;
|
||||||
|
fdv[num_fds].line_len = 0;
|
||||||
|
fdv[num_fds].state = 0;
|
||||||
|
fds[num_fds].fd = sock_n;
|
||||||
|
fds[num_fds].events = POLLIN;
|
||||||
|
++num_fds;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* maximum connections active */
|
||||||
|
/* TODO log error */
|
||||||
|
close(sock_n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send data to active connection
|
||||||
|
*
|
||||||
|
* The data in the buffer is sent to the socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
* \param bp pointer to buffer to send
|
||||||
|
*/
|
||||||
|
void sock_send(int n, BUFFER* bp)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
status = send(fdv[n].fd, bp->body, bp->length, MSG_NOSIGNAL);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
if (errno == EAGAIN) /* flooded */
|
||||||
|
;
|
||||||
|
else if (errno == EPIPE)
|
||||||
|
{
|
||||||
|
perror("send EPIPE");
|
||||||
|
sock_close(n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perror("send");
|
||||||
|
sock_close(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The report in the buffer is sent to all active sockets which match
|
||||||
|
*
|
||||||
|
* \param bp pointer to buffer containing report
|
||||||
|
* \param match value to match for this report
|
||||||
|
*/
|
||||||
|
void sock_report(BUFFER* bp, int match)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 1; i < num_fds; ++i)
|
||||||
|
{
|
||||||
|
if (fdv[i].match == match)
|
||||||
|
sock_send(i, bp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the match parameter for the socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
* \param match value to match for this socket
|
||||||
|
*/
|
||||||
|
void sock_set_match(int n, int match)
|
||||||
|
{
|
||||||
|
fdv[n].match = match;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an OK to the socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*/
|
||||||
|
void sock_ok(int n)
|
||||||
|
{
|
||||||
|
BUFFER buffer;
|
||||||
|
strcpy(buffer.body, "OK\r\n");
|
||||||
|
buffer.length = strlen(buffer.body);
|
||||||
|
sock_send(n, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an ERR to the socket
|
||||||
|
*
|
||||||
|
* \param n index of socket
|
||||||
|
*/
|
||||||
|
void sock_err(int n)
|
||||||
|
{
|
||||||
|
BUFFER buffer;
|
||||||
|
strcpy(buffer.body, "ERR\r\n");
|
||||||
|
buffer.length = strlen(buffer.body);
|
||||||
|
sock_send(n, &buffer);
|
||||||
|
}
|
||||||
16
site_ansto/hardsup/Monitor/sock.h
Normal file
16
site_ansto/hardsup/Monitor/sock.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef _SOCK_H_
|
||||||
|
#define _SOCK_H_
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
|
void sock_init(int addr);
|
||||||
|
void sock_check(int timeout);
|
||||||
|
void sock_close(int n);
|
||||||
|
void sock_line(int n);
|
||||||
|
void sock_input(int n);
|
||||||
|
void sock_accept(int n);
|
||||||
|
void sock_send(int n, BUFFER* buffer);
|
||||||
|
void sock_report(BUFFER* bp, int match);
|
||||||
|
void sock_set_match(int n, int match);
|
||||||
|
void sock_ok(int n);
|
||||||
|
void sock_err(int n);
|
||||||
|
#endif
|
||||||
129
site_ansto/hardsup/Monitor/utility.c
Normal file
129
site_ansto/hardsup/Monitor/utility.c
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Utility functions and structures
|
||||||
|
*/
|
||||||
|
#include "utility.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define NUM_TIMESTAMPS 20
|
||||||
|
#define SZ_TIMESTAMP 40
|
||||||
|
|
||||||
|
static char ts_array[NUM_TIMESTAMPS][SZ_TIMESTAMP];
|
||||||
|
static int ts_index = -1;
|
||||||
|
|
||||||
|
char* make_timestamp(const struct timeval* tv)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
if (ts_index < 0 || ts_index >= NUM_TIMESTAMPS)
|
||||||
|
ts_index = 0;
|
||||||
|
str = ts_array[ts_index++];
|
||||||
|
struct timeval now;
|
||||||
|
if (tv == NULL)
|
||||||
|
{
|
||||||
|
tv = &now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
}
|
||||||
|
snprintf(str, SZ_TIMESTAMP, "%02d:%02d:%02d.%06d",
|
||||||
|
(int) (tv->tv_sec / 3600 % 24),
|
||||||
|
(int) (tv->tv_sec / 60 % 60),
|
||||||
|
(int) (tv->tv_sec % 60),
|
||||||
|
(int) (tv->tv_usec));
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
double time_diff(struct timeval* later, struct timeval* earlier)
|
||||||
|
{
|
||||||
|
double delta =
|
||||||
|
((double) later->tv_sec - (double) earlier->tv_sec)
|
||||||
|
+ 0.000001 * ((double) later->tv_usec - (double) earlier->tv_usec);
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* subtract the earlier time value from the later time value
|
||||||
|
*/
|
||||||
|
int time_sub(struct timeval* later, struct timeval* earlier)
|
||||||
|
{
|
||||||
|
if (later->tv_sec < earlier->tv_sec ||
|
||||||
|
(later->tv_sec == earlier->tv_sec &&
|
||||||
|
later->tv_usec < earlier->tv_usec))
|
||||||
|
return -1;
|
||||||
|
later->tv_sec -= earlier->tv_sec;
|
||||||
|
if (later->tv_usec < earlier->tv_usec)
|
||||||
|
{
|
||||||
|
later->tv_sec--;
|
||||||
|
later->tv_usec = 1000000 + later->tv_usec - earlier->tv_usec;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
later->tv_usec -= earlier->tv_usec;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int time_cmp(struct timeval* later, struct timeval* earlier)
|
||||||
|
{
|
||||||
|
double delta = (1.0 * later->tv_sec + 0.000001 * later->tv_usec) -
|
||||||
|
(1.0 * earlier->tv_sec + 0.000001 * earlier->tv_usec);
|
||||||
|
if (delta == 0.0)
|
||||||
|
return 0;
|
||||||
|
else if (delta > 0.0)
|
||||||
|
return 1;
|
||||||
|
else return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Advance the timer by <msec> milliseconds until it is in the future
|
||||||
|
*/
|
||||||
|
void time_adv(struct timeval* tmr, int msec)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
while (tmr->tv_sec < now.tv_sec ||
|
||||||
|
(tmr->tv_sec == now.tv_sec &&
|
||||||
|
tmr->tv_usec <= now.tv_usec))
|
||||||
|
{
|
||||||
|
tmr->tv_sec += msec / 1000;
|
||||||
|
tmr->tv_usec += (msec % 1000) * 1000;
|
||||||
|
if (tmr->tv_usec >= 1000000)
|
||||||
|
{
|
||||||
|
tmr->tv_sec += tmr->tv_usec / 1000000;
|
||||||
|
tmr->tv_usec = tmr->tv_usec % 1000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEBUG_FILE "debug_file.txt"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#ifndef dprintf
|
||||||
|
static int debug_level = -1;
|
||||||
|
int set_debug_level(int new_level)
|
||||||
|
{
|
||||||
|
int temp = debug_level;
|
||||||
|
debug_level = new_level;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dprintf(int level, const char* format, ...)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
int iRet = 0;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (level <= debug_level)
|
||||||
|
{
|
||||||
|
FILE* debug_file = fopen(DEBUG_FILE, "a");
|
||||||
|
if (debug_file)
|
||||||
|
{
|
||||||
|
va_start(ap, format);
|
||||||
|
iRet = fprintf(debug_file, "%s ", make_timestamp(NULL));
|
||||||
|
result = iRet;
|
||||||
|
iRet = vfprintf(debug_file, format, ap);
|
||||||
|
result += iRet;
|
||||||
|
va_end(ap);
|
||||||
|
fclose(debug_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
50
site_ansto/hardsup/Monitor/utility.h
Normal file
50
site_ansto/hardsup/Monitor/utility.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/* vim: ts=8 sts=2 tw=60
|
||||||
|
*
|
||||||
|
* General utility structure and function definitions
|
||||||
|
*/
|
||||||
|
#ifndef _UTILITY_H_
|
||||||
|
#define _UTILITY_H_
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
typedef unsigned long long uint64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text Buffer for accumulating text for input or output
|
||||||
|
*/
|
||||||
|
typedef struct buffer_t
|
||||||
|
{
|
||||||
|
/** length of text in the body of this buffer */
|
||||||
|
int length;
|
||||||
|
/** the body of the text, null terminated string */
|
||||||
|
char body[65536];
|
||||||
|
} BUFFER, *pBUFFER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a time value to a string
|
||||||
|
*
|
||||||
|
* Makes a string version of the time for printing. Uses
|
||||||
|
* only the time of day to produce a string in the format
|
||||||
|
* HH:MM:SS.UUUUUU at microsecond resolution.
|
||||||
|
*
|
||||||
|
* Uses a circular set of internal static buffers allowing
|
||||||
|
* several calls without overwriting - useful for
|
||||||
|
* formatting multiple times in one print function call.
|
||||||
|
*
|
||||||
|
* \param tv pointer to a timeval structure or NULL for
|
||||||
|
* current time
|
||||||
|
*
|
||||||
|
* \return address of the string given by str
|
||||||
|
*/
|
||||||
|
char* make_timestamp(const struct timeval* tv);
|
||||||
|
double time_diff(struct timeval* later, struct timeval* earlier);
|
||||||
|
int time_sub(struct timeval* later, struct timeval* earlier);
|
||||||
|
int time_cmp(struct timeval* later, struct timeval* earlier);
|
||||||
|
void time_adv(struct timeval* tmr, int msec);
|
||||||
|
#if 1
|
||||||
|
int set_debug_level(int new_level);
|
||||||
|
int dprintf(int level, const char* format, ...);
|
||||||
|
#else
|
||||||
|
#define dprintf fprintf
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user