Commit 7f79ec8f by zacharyc

Ran indent on code to fix inconsistent style.


git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7298 ddd99763-3ecb-0310-9145-efcb8ce7c51f
parent 1dd09ea5
......@@ -3,55 +3,83 @@
#include "compat.h"
#include <windows.h>
unsigned int sleep(unsigned int seconds)
unsigned int
sleep (unsigned int seconds)
{
Sleep(seconds * 1000);
return 0;
Sleep (seconds * 1000);
return 0;
}
static struct {
int num;
char *msg;
} win32_error[] = {
/* Errors that we might vaguely expect to see */
{ WSAEINTR, "Winsock: Interrupted system call" },
{ WSAEBADF, "Winsock: Bad file number" },
{ WSAEFAULT, "Winsock: Bad address" },
{ WSAEINVAL, "Winsock: Invalid argument" },
{ WSAEMFILE, "Winsock: Too many open files" },
{ WSAEWOULDBLOCK, "Winsock: Operation would block" },
{ WSAEINPROGRESS, "Winsock: Operation now in progress" },
{ WSAEALREADY, "Winsock: Operation already in progress" },
{ WSAENOTSOCK, "Winsock: Socket operation on nonsocket" },
{ WSAEADDRINUSE, "Winsock: Address already in use" },
{ WSAEADDRNOTAVAIL, "Winsock: Cannot assign requested address" },
{ WSAENETDOWN, "Winsock: Network is down" },
{ WSAENETUNREACH, "Winsock: Network is unreachable" },
{ WSAENETRESET, "Winsock: Network dropped connection on reset" },
{ WSAECONNABORTED, "Winsock: Software caused connection abort" },
{ WSAECONNRESET, "Winsock: Connection reset by peer" },
{ WSAETIMEDOUT, "Winsock: Connection timed out" },
{ WSAECONNREFUSED, "Winsock: Connection refused" },
{ WSAEHOSTDOWN, "Winsock: Host is down" },
{ WSAEHOSTUNREACH, "Winsock: No route to host" },
{ WSAVERNOTSUPPORTED, "Winsock: Unsupported Winsock version" },
{ ETIMEDOUT, "Connection timed out" },
{ ENOTCONN, "Not connected" },
{ -1, NULL },
};
char *compat_strerror(int errnum)
static struct
{
int i;
static char buf[128];
for (i = 0; win32_error[i].num != -1; i++)
if (errnum == win32_error[i].num)
return win32_error[i].msg;
if (errnum >= 10000) {
sprintf(buf, "Winsock: unknown error %d\n", errnum);
return buf;
}
return strerror(errnum);
int num;
char *msg;
} win32_error[] =
{
/* Errors that we might vaguely expect to see */
{
WSAEINTR, "Winsock: Interrupted system call"},
{
WSAEBADF, "Winsock: Bad file number"},
{
WSAEFAULT, "Winsock: Bad address"},
{
WSAEINVAL, "Winsock: Invalid argument"},
{
WSAEMFILE, "Winsock: Too many open files"},
{
WSAEWOULDBLOCK, "Winsock: Operation would block"},
{
WSAEINPROGRESS, "Winsock: Operation now in progress"},
{
WSAEALREADY, "Winsock: Operation already in progress"},
{
WSAENOTSOCK, "Winsock: Socket operation on nonsocket"},
{
WSAEADDRINUSE, "Winsock: Address already in use"},
{
WSAEADDRNOTAVAIL, "Winsock: Cannot assign requested address"},
{
WSAENETDOWN, "Winsock: Network is down"},
{
WSAENETUNREACH, "Winsock: Network is unreachable"},
{
WSAENETRESET, "Winsock: Network dropped connection on reset"},
{
WSAECONNABORTED, "Winsock: Software caused connection abort"},
{
WSAECONNRESET, "Winsock: Connection reset by peer"},
{
WSAETIMEDOUT, "Winsock: Connection timed out"},
{
WSAECONNREFUSED, "Winsock: Connection refused"},
{
WSAEHOSTDOWN, "Winsock: Host is down"},
{
WSAEHOSTUNREACH, "Winsock: No route to host"},
{
WSAVERNOTSUPPORTED, "Winsock: Unsupported Winsock version"},
{
ETIMEDOUT, "Connection timed out"},
{
ENOTCONN, "Not connected"},
{
-1, NULL},};
char *
compat_strerror (int errnum)
{
int i;
static char buf[128];
for (i = 0; win32_error[i].num != -1; i++)
if (errnum == win32_error[i].num)
return win32_error[i].msg;
if (errnum >= 10000)
{
sprintf (buf, "Winsock: unknown error %d\n", errnum);
return buf;
}
return strerror (errnum);
}
#ifdef __WIN32__
......@@ -80,4 +108,3 @@ char *compat_strerror(int errnum)
}
*/
#endif
......@@ -2,8 +2,8 @@
#define COMPAT_H
#ifdef __WIN32__
unsigned int sleep(unsigned int seconds);
char *compat_strerror(int errnum);
unsigned int sleep (unsigned int seconds);
char *compat_strerror (int errnum);
//const char *inet_ntop(int af, void *src, const char *dst, socklen_t cnt);
#define INET_ADDRSTRLEN 16
#define ETIMEDOUT 110
......
......@@ -4,15 +4,15 @@
int verb_count = 0;
int func_fprintf(const char *func, FILE *stream, const char *format, ...)
int
func_fprintf (const char *func, FILE * stream, const char *format, ...)
{
va_list ap;
int ret;
va_list ap;
int ret;
fprintf(stream, "%s: ", func);
va_start(ap, format);
ret = vfprintf(stream, format, ap);
va_end(ap);
return ret;
fprintf (stream, "%s: ", func);
va_start (ap, format);
ret = vfprintf (stream, format, ap);
va_end (ap);
return ret;
}
......@@ -14,8 +14,8 @@ extern int verb_count;
#include <stdio.h>
int func_fprintf(const char *func, FILE *stream, const char *format,
...) __attribute__ ((format (printf, 3, 4)));
int func_fprintf (const char *func, FILE * stream, const char *format,
...) __attribute__ ((format (printf, 3, 4)));
#define debug(x...) ({ \
if(verb_count >= 2) \
......
......@@ -36,512 +36,596 @@
#define UE9_DATA_PORT 52361
struct callbackInfo {
struct ue9Calibration calib;
int convert;
int maxlines;
struct callbackInfo
{
struct ue9Calibration calib;
int convert;
int maxlines;
};
struct options opt[] = {
{ 'a', "address", "string", "host/address of UE9 (192.168.1.209)" },
{ 'n', "numchannels", "n", "sample the first N ADC channels (2)" },
{ 'N', "nerdjack", NULL, "Use NerdJack device instead" },
{ 'd', "detect", NULL, "Detect NerdJack IP address" },
{ 'p', "precision", "0-3", "Set precision on NerdJack (0 - max range, 1 - max precision)"},
{ 'C', "channels", "a,b,c", "sample channels a, b, and c" },
{ 'r', "rate", "hz", "sample each channel at this rate (8000.0)" },
{ 'o', "oneshot", NULL, "don't retry in case of errors" },
{ 'f', "forceretry", NULL, "retry no matter what happens" },
{ 'c', "convert", NULL, "convert output to volts" },
{ 'H', "converthex", NULL, "convert output to hex" },
{ 'm', "showmem", NULL, "output memory stats with data (NJ only)" },
{ 'l', "lines", "num", "if set, output this many lines and quit" },
{ 'h', "help", NULL, "this help" },
{ 'v', "verbose", NULL, "be verbose" },
{ 'V', "version", NULL, "show version number and exit" },
{ 0, NULL, NULL, NULL }
{'a', "address", "string", "host/address of UE9 (192.168.1.209)"},
{'n', "numchannels", "n", "sample the first N ADC channels (2)"},
{'N', "nerdjack", NULL, "Use NerdJack device instead"},
{'d', "detect", NULL, "Detect NerdJack IP address"},
{'p', "precision", "0-3",
"Set precision on NerdJack (0 - max range, 1 - max precision)"},
{'C', "channels", "a,b,c", "sample channels a, b, and c"},
{'r', "rate", "hz", "sample each channel at this rate (8000.0)"},
{'o', "oneshot", NULL, "don't retry in case of errors"},
{'f', "forceretry", NULL, "retry no matter what happens"},
{'c', "convert", NULL, "convert output to volts"},
{'H', "converthex", NULL, "convert output to hex"},
{'m', "showmem", NULL, "output memory stats with data (NJ only)"},
{'l', "lines", "num", "if set, output this many lines and quit"},
{'h', "help", NULL, "this help"},
{'v', "verbose", NULL, "be verbose"},
{'V', "version", NULL, "show version number and exit"},
{0, NULL, NULL, NULL}
};
int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
int *channel_list, int channel_count, int convert, int maxlines);
int nerdDoStream(const char *address, int *channel_list, int channel_count, int precision,
unsigned long period, int convert, int lines, int showmem);
int data_callback(int channels, uint16_t *data, void *context);
int doStream (const char *address, uint8_t scanconfig, uint16_t scaninterval,
int *channel_list, int channel_count, int convert,
int maxlines);
int nerdDoStream (const char *address, int *channel_list, int channel_count,
int precision, unsigned long period, int convert, int lines,
int showmem);
int data_callback (int channels, uint16_t * data, void *context);
int columns_left = 0;
void handle_sig(int sig)
void
handle_sig (int sig)
{
while (columns_left--) {
printf(" 0");
}
fflush(stdout);
exit(0);
while (columns_left--)
{
printf (" 0");
}
fflush (stdout);
exit (0);
}
int main(int argc, char *argv[])
int
main (int argc, char *argv[])
{
int optind;
char *optarg, *endp;
char c;
int tmp, i;
FILE *help = stderr;
char *address = strdup(DEFAULT_HOST);
double desired_rate = 8000.0;
int lines = 0;
double actual_rate;
int oneshot = 0;
int forceretry = 0;
int convert = CONVERT_DEC;
int showmem = 0;
uint8_t scanconfig;
uint16_t scaninterval;
int optind;
char *optarg, *endp;
char c;
int tmp, i;
FILE *help = stderr;
char *address = strdup (DEFAULT_HOST);
double desired_rate = 8000.0;
int lines = 0;
double actual_rate;
int oneshot = 0;
int forceretry = 0;
int convert = CONVERT_DEC;
int showmem = 0;
uint8_t scanconfig;
uint16_t scaninterval;
#if UE9_CHANNELS > NERDJACK_CHANNELS
int channel_list[UE9_CHANNELS];
int channel_list[UE9_CHANNELS];
#else
int channel_list[NERDJACK_CHANNELS];
int channel_list[NERDJACK_CHANNELS];
#endif
int channel_count = 0;
int nerdjack = 0;
int detect = 0;
int precision = 0;
unsigned long period = NERDJACK_CLOCK_RATE / desired_rate;
/* Parse arguments */
opt_init(&optind);
while ((c = opt_parse(argc, argv, &optind, &optarg, opt)) != 0) {
switch (c) {
case 'a':
free(address);
address = strdup(optarg);
break;
case 'n':
channel_count = 0;
tmp = strtol(optarg, &endp, 0);
if (*endp || tmp < 1 || tmp > UE9_CHANNELS) {
info("bad number of channels: %s\n", optarg);
goto printhelp;
}
for (i = 0; i < tmp; i++)
channel_list[channel_count++] = i;
break;
case 'C':
channel_count = 0;
do {
tmp = strtol(optarg, &endp, 0);
if (*endp != '\0' && *endp != ',') {
//|| tmp < 0 || tmp >= UE9_CHANNELS) {
info("bad channel number: %s\n", optarg);
goto printhelp;
}
//We do not want to overflow channel_list, so we need the check here
//The rest of the sanity checking can come later after we know whether this is a
//LabJack or a NerdJack
int channel_count = 0;
int nerdjack = 0;
int detect = 0;
int precision = 0;
unsigned long period = NERDJACK_CLOCK_RATE / desired_rate;
/* Parse arguments */
opt_init (&optind);
while ((c = opt_parse (argc, argv, &optind, &optarg, opt)) != 0)
{
switch (c)
{
case 'a':
free (address);
address = strdup (optarg);
break;
case 'n':
channel_count = 0;
tmp = strtol (optarg, &endp, 0);
if (*endp || tmp < 1 || tmp > UE9_CHANNELS)
{
info ("bad number of channels: %s\n", optarg);
goto printhelp;
}
for (i = 0; i < tmp; i++)
channel_list[channel_count++] = i;
break;
case 'C':
channel_count = 0;
do
{
tmp = strtol (optarg, &endp, 0);
if (*endp != '\0' && *endp != ',')
{
//|| tmp < 0 || tmp >= UE9_CHANNELS) {
info ("bad channel number: %s\n", optarg);
goto printhelp;
}
//We do not want to overflow channel_list, so we need the check here
//The rest of the sanity checking can come later after we know whether this is a
//LabJack or a NerdJack
#if UE9_CHANNELS > NERDJACK_CHANNELS
if (channel_count >= UE9_CHANNELS) {
if (channel_count >= UE9_CHANNELS)
{
#else
if (channel_count >= NERDJACK_CHANNELS) {
if (channel_count >= NERDJACK_CHANNELS)
{
#endif
info("error: too many channels specified\n");
goto printhelp;
}
channel_list[channel_count++] = tmp;
optarg = endp + 1;
} while (*endp);
break;
case 'r':
desired_rate = strtod(optarg, &endp);
if(*endp || desired_rate <= 0) {
info("bad rate: %s\n", optarg);
goto printhelp;
}
break;
case 'l':
lines = strtol(optarg, &endp, 0);
if (*endp || lines <= 0) {
info("bad number of lines: %s\n", optarg);
goto printhelp;
}
break;
case 'p':
tmp = strtol(optarg, &endp, 0);
if (tmp <= 3 && tmp >= 0) {
precision = tmp;
} else {
info("Bad argument to p: %s\n",optarg);
goto printhelp;
}
break;
case 'N':
nerdjack++;
break;
case 'd':
detect++;
break;
case 'o':
oneshot++;
break;
case 'f':
forceretry++;
break;
case 'c':
if (convert != 0) {
info("specify only one conversion type\n");
goto printhelp;
}
convert = CONVERT_VOLTS;
break;
case 'H':
if (convert != 0) {
info("specify only one conversion type\n");
goto printhelp;
}
convert = CONVERT_HEX;
break;
case 'm':
showmem++;
case 'v':
verb_count++;
break;
case 'V':
printf("ljstream " VERSION "\n");
printf("Written by Jim Paris <jim@jtan.com>\n");
printf("This program comes with no warranty and is "
"provided under the GPLv2.\n");
return 0;
break;
case 'h':
help = stdout;
default:
printhelp:
fprintf(help, "Usage: %s [options]\n", *argv);
opt_help(opt, help);
fprintf(help, "Read data from the specified Labjack UE9"
" via Ethernet. See README for details.\n");
return (help == stdout) ? 0 : 1;
info ("error: too many channels specified\n");
goto printhelp;
}
channel_list[channel_count++] = tmp;
optarg = endp + 1;
}
while (*endp);
break;
case 'r':
desired_rate = strtod (optarg, &endp);
if (*endp || desired_rate <= 0)
{
info ("bad rate: %s\n", optarg);
goto printhelp;
}
break;
case 'l':
lines = strtol (optarg, &endp, 0);
if (*endp || lines <= 0)
{
info ("bad number of lines: %s\n", optarg);
goto printhelp;
}
break;
case 'p':
tmp = strtol (optarg, &endp, 0);
if (tmp <= 3 && tmp >= 0)
{
precision = tmp;
}
else
{
info ("Bad argument to p: %s\n", optarg);
goto printhelp;
}
break;
case 'N':
nerdjack++;
break;
case 'd':
detect++;
break;
case 'o':
oneshot++;
break;
case 'f':
forceretry++;
break;
case 'c':
if (convert != 0)
{
info ("specify only one conversion type\n");
goto printhelp;
}
convert = CONVERT_VOLTS;
break;
case 'H':
if (convert != 0)
{
info ("specify only one conversion type\n");
goto printhelp;
}
convert = CONVERT_HEX;
break;
case 'm':
showmem++;
case 'v':
verb_count++;
break;
case 'V':
printf ("ljstream " VERSION "\n");
printf ("Written by Jim Paris <jim@jtan.com>\n");
printf ("This program comes with no warranty and is "
"provided under the GPLv2.\n");
return 0;
break;
case 'h':
help = stdout;
default:
printhelp:
fprintf (help, "Usage: %s [options]\n", *argv);
opt_help (opt, help);
fprintf (help, "Read data from the specified Labjack UE9"
" via Ethernet. See README for details.\n");
return (help == stdout) ? 0 : 1;
}
doneparse:
if (nerdjack) {
if (channel_count > NERDJACK_CHANNELS) {
info("Too many channels for NerdJack\n");
goto printhelp;
}
for (i = 0; i < channel_count; i++) {
if (channel_list[i] >= NERDJACK_CHANNELS) {
info("Channel is out of NerdJack range: %d\n",channel_list[i]);
goto printhelp;
}
}
} else {
if (channel_count > UE9_CHANNELS) {
info("Too many channels for LabJack\n");
goto printhelp;
}
for (i = 0; i < channel_count; i++) {
if (channel_list[i] >= UE9_CHANNELS) {
info("Channel is out of LabJack range: %d\n",channel_list[i]);
goto printhelp;
}
}
}
if (optind < argc) {
info("error: too many arguments (%s)\n\n", argv[optind]);
goto printhelp;
}
doneparse:
if (forceretry && oneshot) {
info("forceretry and oneshot options are mutually exclusive\n");
goto printhelp;
if (nerdjack)
{
if (channel_count > NERDJACK_CHANNELS)
{
info ("Too many channels for NerdJack\n");
goto printhelp;
}
/* Two channels if none specified */
if (channel_count == 0) {
channel_list[channel_count++] = 0;
channel_list[channel_count++] = 1;
for (i = 0; i < channel_count; i++)
{
if (channel_list[i] >= NERDJACK_CHANNELS)
{
info ("Channel is out of NerdJack range: %d\n",
channel_list[i]);
goto printhelp;
}
}
if (verb_count) {
info("Scanning channels:");
for (i = 0; i < channel_count; i++)
info(" AIN%d", channel_list[i]);
info("\n");
}
else
{
if (channel_count > UE9_CHANNELS)
{
info ("Too many channels for LabJack\n");
goto printhelp;
}
for (i = 0; i < channel_count; i++)
{
if (channel_list[i] >= UE9_CHANNELS)
{
info ("Channel is out of LabJack range: %d\n", channel_list[i]);
goto printhelp;
}
}
}
/* Figure out actual rate. */
if (nerdjack) {
if (nerdjack_choose_scan(desired_rate, &actual_rate, &period) < 0) {
info("error: can't achieve requested scan rate (%lf Hz)\n",
desired_rate);
//return 1;
}
} else {
if (ue9_choose_scan(desired_rate, &actual_rate,
&scanconfig, &scaninterval) < 0) {
info("error: can't achieve requested scan rate (%lf Hz)\n",
desired_rate);
//return 1;
}
if (optind < argc)
{
info ("error: too many arguments (%s)\n\n", argv[optind]);
goto printhelp;
}
if ((desired_rate != actual_rate) || verb_count){
info("Actual scanrate is %lf Hz\n", actual_rate);
info("Period is %ld\n",period);
if (forceretry && oneshot)
{
info ("forceretry and oneshot options are mutually exclusive\n");
goto printhelp;
}
if (verb_count && lines) {
info("Stopping capture after %d lines\n", lines);
}
/* Two channels if none specified */
if (channel_count == 0)
{
channel_list[channel_count++] = 0;
channel_list[channel_count++] = 1;
}
signal(SIGINT, handle_sig);
signal(SIGTERM, handle_sig);
if (detect) {
info("Autodetecting NerdJack address\n");
free(address);
if(nerdjack_detect(address) < 0) {
info("Error with autodetection\n");
} else {
info("Found NerdJack at address: %s\n",address);
}
if (verb_count)
{
info ("Scanning channels:");
for (i = 0; i < channel_count; i++)
info (" AIN%d", channel_list[i]);
info ("\n");
}
for (;;) {
int ret;
if(nerdjack) {
ret = nerdDoStream(address, channel_list, channel_count, precision, period, convert, lines, showmem);
verb("nerdDoStream returned %d\n", ret);
} else {
ret = doStream(address, scanconfig, scaninterval,
channel_list, channel_count, convert,
lines);
verb("doStream returned %d\n", ret);
}
if (oneshot)
break;
if (ret == 0)
break;
if (ret == -ENOTCONN && !nerdjack) {
info("Could not connect LabJack...Trying NerdJack\n");
nerdjack = 1;
goto doneparse;
}
if (ret == -ENOTCONN && !forceretry) {
info("Initial connection failed, giving up\n");
break;
}
if (ret == -EAGAIN || ret == -ENOTCONN) {
/* Some transient error. Wait a tiny bit, then retry */
info("Retrying in 5 secs.\n");
sleep(5);
} else {
info("Retrying now.\n");
}
/* Figure out actual rate. */
if (nerdjack)
{
if (nerdjack_choose_scan (desired_rate, &actual_rate, &period) < 0)
{
info ("error: can't achieve requested scan rate (%lf Hz)\n",
desired_rate);
//return 1;
}
}
else
{
if (ue9_choose_scan (desired_rate, &actual_rate,
&scanconfig, &scaninterval) < 0)
{
info ("error: can't achieve requested scan rate (%lf Hz)\n",
desired_rate);
//return 1;
}
}
debug("Done loop\n");
return 0;
}
if ((desired_rate != actual_rate) || verb_count)
{
info ("Actual scanrate is %lf Hz\n", actual_rate);
info ("Period is %ld\n", period);
}
int nerdDoStream(const char *address, int *channel_list, int channel_count, int precision,
unsigned long period, int convert, int lines, int showmem)
{
int retval = -EAGAIN;
int fd_data;
static int first_call = 1;
static int started = 0;
getPacket command;
static unsigned short currentcount = 0;
//usleep(1000000);
if(first_call) {
if (nerd_generate_command(&command, channel_list, channel_count, precision, period) < 0) {
info("Failed to create configuration command\n");
goto out;
}
if (nerd_send_command(address,"STOP", 4) < 0) {
if (first_call)
retval = -ENOTCONN;
info("Failed to send STOP command\n");
goto out;
}
if (nerd_send_command(address,&command, sizeof(command)) < 0) {
info("Failed to send GET command\n");
goto out;
}
}
//We have sent the configuration commands. If we retry later, don't resend them. We would like
//to resume the interrupted transmission
first_call = 0;
//If we had a transmission in progress, send a command to resume from there
if(started == 1) {
char cmdbuf[10];
sprintf(cmdbuf,"SETC%05hd",currentcount);
if (nerd_send_command(address,cmdbuf,strlen(cmdbuf)) < 0) {
info("Failed to send SETC command\n");
goto out;
}
if (verb_count && lines)
{
info ("Stopping capture after %d lines\n", lines);
}
started = 1;
/* Open connection */
fd_data = nerd_open(address, NERDJACK_DATA_PORT);
if (fd_data < 0) {
info("Connect failed: %s:%d\n", address, NERDJACK_DATA_PORT);
goto out;
signal (SIGINT, handle_sig);
signal (SIGTERM, handle_sig);
if (detect)
{
info ("Autodetecting NerdJack address\n");
free (address);
if (nerdjack_detect (address) < 0)
{
info ("Error with autodetection\n");
}
else
{
info ("Found NerdJack at address: %s\n", address);
}
if (nerd_data_stream(fd_data, channel_count, channel_list, precision, convert, lines, showmem, &currentcount,period) < 0) {
info("Failed to open data stream\n");
goto out1;
}
info("Stream finished\n");
retval = 0;
out1:
nerd_close_conn(fd_data);
out:
return retval;
}
for (;;)
{
int ret;
if (nerdjack)
{
ret =
nerdDoStream (address, channel_list, channel_count, precision,
period, convert, lines, showmem);
verb ("nerdDoStream returned %d\n", ret);
int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
int *channel_list, int channel_count, int convert, int lines)
{
int retval = -EAGAIN;
int fd_cmd, fd_data;
int ret;
static int first_call = 1;
struct callbackInfo ci = {
.convert = convert,
.maxlines = lines,
};
/* Open command connection. If this fails, and this is the
first attempt, return a different error code so we give up. */
fd_cmd = ue9_open(address, UE9_COMMAND_PORT);
if (fd_cmd < 0) {
info("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
if (first_call)
retval = -ENOTCONN;
goto out;
}
first_call = 0;
/* Make sure nothing is left over from a previous stream */
if (ue9_stream_stop(fd_cmd) == 0)
verb("Stopped previous stream.\n");
ue9_buffer_flush(fd_cmd);
/* Open data connection */
fd_data = ue9_open(address, UE9_DATA_PORT);
if (fd_data < 0) {
info("Connect failed: %s:%d\n", address, UE9_DATA_PORT);
goto out1;
else
{
ret = doStream (address, scanconfig, scaninterval,
channel_list, channel_count, convert, lines);
verb ("doStream returned %d\n", ret);
}
if (oneshot)
break;
if (ret == 0)
break;
if (ret == -ENOTCONN && !nerdjack)
{
info ("Could not connect LabJack...Trying NerdJack\n");
nerdjack = 1;
goto doneparse;
}
if (ret == -ENOTCONN && !forceretry)
{
info ("Initial connection failed, giving up\n");
break;
}
if (ret == -EAGAIN || ret == -ENOTCONN)
{
/* Some transient error. Wait a tiny bit, then retry */
info ("Retrying in 5 secs.\n");
sleep (5);
}
/* Get calibration */
if (ue9_get_calibration(fd_cmd, &ci.calib) < 0) {
info("Failed to get device calibration\n");
goto out2;
else
{
info ("Retrying now.\n");
}
}
debug ("Done loop\n");
/* Set stream configuration */
if (ue9_streamconfig_simple(fd_cmd, channel_list, channel_count,
scanconfig, scaninterval,
UE9_BIPOLAR_GAIN1) < 0) {
info("Failed to set stream configuration\n");
goto out2;
return 0;
}
int
nerdDoStream (const char *address, int *channel_list, int channel_count,
int precision, unsigned long period, int convert, int lines,
int showmem)
{
int retval = -EAGAIN;
int fd_data;
static int first_call = 1;
static int started = 0;
getPacket command;
static unsigned short currentcount = 0;
//usleep(1000000);
if (first_call)
{
if (nerd_generate_command
(&command, channel_list, channel_count, precision, period) < 0)
{
info ("Failed to create configuration command\n");
goto out;
}
/* Start stream */
if (ue9_stream_start(fd_cmd) < 0) {
info("Failed to start stream\n");
goto out2;
if (nerd_send_command (address, "STOP", 4) < 0)
{
if (first_call)
retval = -ENOTCONN;
info ("Failed to send STOP command\n");
goto out;
}
/* Stream data */
ret = ue9_stream_data(fd_data, channel_count, data_callback, (void *)&ci);
if (ret < 0) {
info("Data stream failed with error %d\n", ret);
goto out3;
if (nerd_send_command (address, &command, sizeof (command)) < 0)
{
info ("Failed to send GET command\n");
goto out;
}
}
//We have sent the configuration commands. If we retry later, don't resend them. We would like
//to resume the interrupted transmission
first_call = 0;
//If we had a transmission in progress, send a command to resume from there
if (started == 1)
{
char cmdbuf[10];
sprintf (cmdbuf, "SETC%05hd", currentcount);
if (nerd_send_command (address, cmdbuf, strlen (cmdbuf)) < 0)
{
info ("Failed to send SETC command\n");
goto out;
}
}
info("Stream finished\n");
retval = 0;
out3:
/* Stop stream and clean up */
ue9_stream_stop(fd_cmd);
ue9_buffer_flush(fd_cmd);
out2:
ue9_close(fd_data);
out1:
ue9_close(fd_cmd);
out:
return retval;
started = 1;
/* Open connection */
fd_data = nerd_open (address, NERDJACK_DATA_PORT);
if (fd_data < 0)
{
info ("Connect failed: %s:%d\n", address, NERDJACK_DATA_PORT);
goto out;
}
if (nerd_data_stream
(fd_data, channel_count, channel_list, precision, convert, lines,
showmem, &currentcount, period) < 0)
{
info ("Failed to open data stream\n");
goto out1;
}
info ("Stream finished\n");
retval = 0;
out1:
nerd_close_conn (fd_data);
out:
return retval;
}
int data_callback(int channels, uint16_t *data, void *context)
int
doStream (const char *address, uint8_t scanconfig, uint16_t scaninterval,
int *channel_list, int channel_count, int convert, int lines)
{
int i;
struct callbackInfo *ci = (struct callbackInfo *)context;
static int lines = 0;
columns_left = channels;
for (i = 0; i < channels; i++) {
switch (ci->convert) {
case CONVERT_VOLTS:
if (printf("%lf", ue9_binary_to_analog(
&ci->calib, UE9_BIPOLAR_GAIN1, 12,
data[i])) < 0)
goto bad;
break;
case CONVERT_HEX:
if (printf("%04X", data[i]) < 0)
goto bad;
break;
default:
case CONVERT_DEC:
if (printf("%d", data[i]) < 0)
goto bad;
break;
}
columns_left--;
if (i < (channels - 1)) {
if (ci->convert != CONVERT_HEX && putchar(' ') < 0)
goto bad;
} else {
if (putchar('\n') < 0)
goto bad;
lines++;
if (ci->maxlines && lines >= ci->maxlines)
return -1;
}
int retval = -EAGAIN;
int fd_cmd, fd_data;
int ret;
static int first_call = 1;
struct callbackInfo ci = {
.convert = convert,
.maxlines = lines,
};
/* Open command connection. If this fails, and this is the
first attempt, return a different error code so we give up. */
fd_cmd = ue9_open (address, UE9_COMMAND_PORT);
if (fd_cmd < 0)
{
info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
if (first_call)
retval = -ENOTCONN;
goto out;
}
first_call = 0;
/* Make sure nothing is left over from a previous stream */
if (ue9_stream_stop (fd_cmd) == 0)
verb ("Stopped previous stream.\n");
ue9_buffer_flush (fd_cmd);
/* Open data connection */
fd_data = ue9_open (address, UE9_DATA_PORT);
if (fd_data < 0)
{
info ("Connect failed: %s:%d\n", address, UE9_DATA_PORT);
goto out1;
}
/* Get calibration */
if (ue9_get_calibration (fd_cmd, &ci.calib) < 0)
{
info ("Failed to get device calibration\n");
goto out2;
}
/* Set stream configuration */
if (ue9_streamconfig_simple (fd_cmd, channel_list, channel_count,
scanconfig, scaninterval,
UE9_BIPOLAR_GAIN1) < 0)
{
info ("Failed to set stream configuration\n");
goto out2;
}
/* Start stream */
if (ue9_stream_start (fd_cmd) < 0)
{
info ("Failed to start stream\n");
goto out2;
}
/* Stream data */
ret = ue9_stream_data (fd_data, channel_count, data_callback, (void *) &ci);
if (ret < 0)
{
info ("Data stream failed with error %d\n", ret);
goto out3;
}
info ("Stream finished\n");
retval = 0;
out3:
/* Stop stream and clean up */
ue9_stream_stop (fd_cmd);
ue9_buffer_flush (fd_cmd);
out2:
ue9_close (fd_data);
out1:
ue9_close (fd_cmd);
out:
return retval;
}
int
data_callback (int channels, uint16_t * data, void *context)
{
int i;
struct callbackInfo *ci = (struct callbackInfo *) context;
static int lines = 0;
columns_left = channels;
for (i = 0; i < channels; i++)
{
switch (ci->convert)
{
case CONVERT_VOLTS:
if (printf
("%lf",
ue9_binary_to_analog (&ci->calib, UE9_BIPOLAR_GAIN1, 12,
data[i])) < 0)
goto bad;
break;
case CONVERT_HEX:
if (printf ("%04X", data[i]) < 0)
goto bad;
break;
default:
case CONVERT_DEC:
if (printf ("%d", data[i]) < 0)
goto bad;
break;
}
return 0;
columns_left--;
if (i < (channels - 1))
{
if (ci->convert != CONVERT_HEX && putchar (' ') < 0)
goto bad;
}
else
{
if (putchar ('\n') < 0)
goto bad;
lines++;
if (ci->maxlines && lines >= ci->maxlines)
return -1;
}
}
return 0;
bad:
info("Output error (disk full?)\n");
return -1;
info ("Output error (disk full?)\n");
return -1;
}
......@@ -25,74 +25,78 @@
#define UE9_COMMAND_PORT 52360
struct options opt[] = {
{ 'a', "address", "string", "host/address of UE9 (192.168.1.209)" },
{ 'h', "help", NULL, "this help" },
{ 'v', "verbose", NULL, "be verbose" },
{ 'V', "version", NULL, "show version number and exit" },
{ 0, NULL, NULL, NULL }
{'a', "address", "string", "host/address of UE9 (192.168.1.209)"},
{'h', "help", NULL, "this help"},
{'v', "verbose", NULL, "be verbose"},
{'V', "version", NULL, "show version number and exit"},
{0, NULL, NULL, NULL}
};
int main(int argc, char *argv[])
int
main (int argc, char *argv[])
{
int optind;
char *optarg;
char c;
FILE *help = stderr;
char *address = strdup(DEFAULT_HOST);
int fd;
int ret;
int optind;
char *optarg;
char c;
FILE *help = stderr;
char *address = strdup (DEFAULT_HOST);
int fd;
int ret;
/* Parse arguments */
opt_init(&optind);
while ((c = opt_parse(argc, argv, &optind, &optarg, opt)) != 0) {
switch (c) {
case 'a':
free(address);
address = strdup(optarg);
break;
case 'v':
verb_count++;
break;
case 'V':
printf("ljconfig " VERSION "\n");
printf("Written by Jim Paris <jim@jtan.com>\n");
printf("This program comes with no warranty and is "
"provided under the GPLv2.\n");
return 0;
break;
case 'h':
help = stdout;
default:
printhelp:
fprintf(help, "Usage: %s [options]\n", *argv);
opt_help(opt, help);
fprintf(help, "Displays/changes Labjack UE9 config.\n");
return (help == stdout) ? 0 : 1;
}
/* Parse arguments */
opt_init (&optind);
while ((c = opt_parse (argc, argv, &optind, &optarg, opt)) != 0)
{
switch (c)
{
case 'a':
free (address);
address = strdup (optarg);
break;
case 'v':
verb_count++;
break;
case 'V':
printf ("ljconfig " VERSION "\n");
printf ("Written by Jim Paris <jim@jtan.com>\n");
printf ("This program comes with no warranty and is "
"provided under the GPLv2.\n");
return 0;
break;
case 'h':
help = stdout;
default:
printhelp:
fprintf (help, "Usage: %s [options]\n", *argv);
opt_help (opt, help);
fprintf (help, "Displays/changes Labjack UE9 config.\n");
return (help == stdout) ? 0 : 1;
}
}
if(optind<argc) {
info("Error: too many arguments (%s)\n\n", argv[optind]);
goto printhelp;
}
ret = 1;
if (optind < argc)
{
info ("Error: too many arguments (%s)\n\n", argv[optind]);
goto printhelp;
}
/* Open */
fd = ue9_open(address, UE9_COMMAND_PORT);
if (fd < 0) {
info("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
goto out0;
}
ret = 1;
goto out1;
ret = 0;
out1:
/* Close */
ue9_close(fd);
out0:
return ret;
}
/* Open */
fd = ue9_open (address, UE9_COMMAND_PORT);
if (fd < 0)
{
info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
goto out0;
}
goto out1;
ret = 0;
out1:
/* Close */
ue9_close (fd);
out0:
return ret;
}
......@@ -16,52 +16,53 @@
#include "ue9.h"
#include "compat.h"
int main(int argc, char *argv[])
int
main (int argc, char *argv[])
{
int fd_cmd;
struct ue9Calibration calib;
int fd_cmd;
struct ue9Calibration calib;
verb_count = 2;
verb_count = 2;
fd_cmd = ue9_open("192.168.1.209", 52360);
if (fd_cmd < 0) {
fprintf(stderr, "ue9_open: %s\n",
compat_strerror(errno));
return 1;
}
fd_cmd = ue9_open ("192.168.1.209", 52360);
if (fd_cmd < 0)
{
fprintf (stderr, "ue9_open: %s\n", compat_strerror (errno));
return 1;
}
if (ue9_get_calibration(fd_cmd, &calib) < 0) {
fprintf(stderr, "ue9_get_calibration: %s\n",
compat_strerror(errno));
return 1;
}
if (ue9_get_calibration (fd_cmd, &calib) < 0)
{
fprintf (stderr, "ue9_get_calibration: %s\n", compat_strerror (errno));
return 1;
}
printf("double unipolarSlope[0] = %lf\n", calib.unipolarSlope[0]);
printf("double unipolarSlope[1] = %lf\n", calib.unipolarSlope[1]);
printf("double unipolarSlope[2] = %lf\n", calib.unipolarSlope[2]);
printf("double unipolarSlope[3] = %lf\n", calib.unipolarSlope[3]);
printf("double unipolarOffset[0] = %lf\n", calib.unipolarOffset[0]);
printf("double unipolarOffset[1] = %lf\n", calib.unipolarOffset[1]);
printf("double unipolarOffset[2] = %lf\n", calib.unipolarOffset[2]);
printf("double unipolarOffset[3] = %lf\n", calib.unipolarOffset[3]);
printf("double bipolarSlope = %lf\n", calib.bipolarSlope);
printf("double bipolarOffset = %lf\n", calib.bipolarOffset);
printf("double DACSlope[0] = %lf\n", calib.DACSlope[0]);
printf("double DACSlope[1] = %lf\n", calib.DACSlope[1]);
printf("double DACOffset[0] = %lf\n", calib.DACOffset[0]);
printf("double DACOffset[1] = %lf\n", calib.DACOffset[1]);
printf("double tempSlope = %lf\n", calib.tempSlope);
printf("double tempSlopeLow = %lf\n", calib.tempSlopeLow);
printf("double calTemp = %lf\n", calib.calTemp);
printf("double Vref = %lf\n", calib.Vref);
printf("double VrefDiv2 = %lf\n", calib.VrefDiv2);
printf("double VsSlope = %lf\n", calib.VsSlope);
printf("double hiResUnipolarSlope = %lf\n", calib.hiResUnipolarSlope);
printf("double hiResUnipolarOffset = %lf\n", calib.hiResUnipolarOffset);
printf("double hiResBipolarSlope = %lf\n", calib.hiResBipolarSlope);
printf("double hiResBipolarOffset = %lf\n", calib.hiResBipolarOffset);
printf ("double unipolarSlope[0] = %lf\n", calib.unipolarSlope[0]);
printf ("double unipolarSlope[1] = %lf\n", calib.unipolarSlope[1]);
printf ("double unipolarSlope[2] = %lf\n", calib.unipolarSlope[2]);
printf ("double unipolarSlope[3] = %lf\n", calib.unipolarSlope[3]);
printf ("double unipolarOffset[0] = %lf\n", calib.unipolarOffset[0]);
printf ("double unipolarOffset[1] = %lf\n", calib.unipolarOffset[1]);
printf ("double unipolarOffset[2] = %lf\n", calib.unipolarOffset[2]);
printf ("double unipolarOffset[3] = %lf\n", calib.unipolarOffset[3]);
printf ("double bipolarSlope = %lf\n", calib.bipolarSlope);
printf ("double bipolarOffset = %lf\n", calib.bipolarOffset);
printf ("double DACSlope[0] = %lf\n", calib.DACSlope[0]);
printf ("double DACSlope[1] = %lf\n", calib.DACSlope[1]);
printf ("double DACOffset[0] = %lf\n", calib.DACOffset[0]);
printf ("double DACOffset[1] = %lf\n", calib.DACOffset[1]);
printf ("double tempSlope = %lf\n", calib.tempSlope);
printf ("double tempSlopeLow = %lf\n", calib.tempSlopeLow);
printf ("double calTemp = %lf\n", calib.calTemp);
printf ("double Vref = %lf\n", calib.Vref);
printf ("double VrefDiv2 = %lf\n", calib.VrefDiv2);
printf ("double VsSlope = %lf\n", calib.VsSlope);
printf ("double hiResUnipolarSlope = %lf\n", calib.hiResUnipolarSlope);
printf ("double hiResUnipolarOffset = %lf\n", calib.hiResUnipolarOffset);
printf ("double hiResBipolarSlope = %lf\n", calib.hiResBipolarSlope);
printf ("double hiResBipolarOffset = %lf\n", calib.hiResBipolarOffset);
ue9_close(fd_cmd);
ue9_close (fd_cmd);
return 0;
return 0;
}
......@@ -25,464 +25,553 @@
#include "netutil.h"
#include "ethstream.h"
#define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
#define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
//Struct holding information about how channels should be reordered for output
typedef struct {
int numCopies;
int * destlist;
typedef struct
{
int numCopies;
int *destlist;
} deststruct;
typedef struct __attribute__((__packed__)) {
unsigned char headerone;
unsigned char headertwo;
unsigned short packetNumber;
unsigned long lwipmemoryused;
unsigned short adcused;
unsigned short packetsready;
signed short data[NERDJACK_NUM_SAMPLES];
typedef struct __attribute__ ((__packed__))
{
unsigned char headerone;
unsigned char headertwo;
unsigned short packetNumber;
unsigned long lwipmemoryused;
unsigned short adcused;
unsigned short packetsready;
signed short data[NERDJACK_NUM_SAMPLES];
} dataPacket;
/* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns -1 if no valid config found */
int nerdjack_choose_scan(double desired_rate, double *actual_rate, unsigned long *period)
int
nerdjack_choose_scan (double desired_rate, double *actual_rate,
unsigned long *period)
{
//The ffffe is because of a silicon bug. The last bit is unusable in all
//devices so far. It is worked around on the chip, but giving it exactly
//0xfffff would cause the workaround code to roll over.
*period = floor((double) NERDJACK_CLOCK_RATE / desired_rate);
if(*period > 0x0ffffe) {
info("Cannot sample that slowly\n");
*actual_rate = (double)NERDJACK_CLOCK_RATE / (double) 0x0ffffe;
*period = 0x0ffffe;
//info("Sampling at slowest rate:%f\n",*actual_rate);
return -1;
//The ffffe is because of a silicon bug. The last bit is unusable in all
//devices so far. It is worked around on the chip, but giving it exactly
//0xfffff would cause the workaround code to roll over.
*period = floor ((double) NERDJACK_CLOCK_RATE / desired_rate);
if (*period > 0x0ffffe)
{
info ("Cannot sample that slowly\n");
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) 0x0ffffe;
*period = 0x0ffffe;
//info("Sampling at slowest rate:%f\n",*actual_rate);
return -1;
}
//Period holds the period register for the NerdJack, so it needs to be right
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period;
if(*actual_rate != desired_rate) {
//info("Sampling at nearest rate:%f\n",*actual_rate);
return -1;
}
return 0;
//Period holds the period register for the NerdJack, so it needs to be right
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period;
if (*actual_rate != desired_rate)
{
//info("Sampling at nearest rate:%f\n",*actual_rate);
return -1;
}
return 0;
}
int nerdjack_detect(char * ipAddress) {
int32_t sock, receivesock;
struct sockaddr_in sa, receiveaddr, sFromAddr;
int bytes_sent, buffer_length;
char buffer[200];
char incomingData[10];
unsigned int lFromLen;
sprintf(buffer, "TEST");
buffer_length = strlen(buffer) + 1;
net_init();
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
receivesock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
/* Set nonblocking */
if (soblock(sock, 0) < 0) {
verb("can't set nonblocking\n");
int
nerdjack_detect (char *ipAddress)
{
int32_t sock, receivesock;
struct sockaddr_in sa, receiveaddr, sFromAddr;
int bytes_sent, buffer_length;
char buffer[200];
char incomingData[10];
unsigned int lFromLen;
sprintf (buffer, "TEST");
buffer_length = strlen (buffer) + 1;
net_init ();
sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
receivesock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
/* Set nonblocking */
if (soblock (sock, 0) < 0)
{
verb ("can't set nonblocking\n");
return -1;
}
/* Set nonblocking */
if (soblock(receivesock, 0) < 0) {
verb("can't set nonblocking\n");
}
/* Set nonblocking */
if (soblock (receivesock, 0) < 0)
{
verb ("can't set nonblocking\n");
return -1;
}
}
int opt = 1;
setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(void *) &opt,sizeof(int));
if((-1 == sock) || (-1 == receivesock)) /* if socket failed to initialize, exit */
{
verb("Error Creating Socket\n");
int opt = 1;
setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (void *) &opt, sizeof (int));
if ((-1 == sock) || (-1 == receivesock)) /* if socket failed to initialize, exit */
{
verb ("Error Creating Socket\n");
return -1;
}
//Setup family for both sockets
sa.sin_family = PF_INET;
receiveaddr.sin_family = PF_INET;
//Setup ports to send on DATA and receive on RECEIVE
receiveaddr.sin_port = htons(NERDJACK_UDP_RECEIVE_PORT);
sa.sin_port = htons(NERDJACK_DATA_PORT);
//Receive from any IP address, Will send to broadcast
receiveaddr.sin_addr.s_addr = INADDR_ANY;
sa.sin_addr.s_addr = INADDR_BROADCAST;
bind(receivesock,(struct sockaddr*) &receiveaddr, sizeof(struct sockaddr_in));
bytes_sent = sendto(sock, buffer, buffer_length, 0,(struct sockaddr*) &sa, sizeof(struct sockaddr_in) );
if(bytes_sent < 0) {
info("Error sending packet: %s\n", strerror(errno) );
return -1;
}
}
//Setup family for both sockets
sa.sin_family = PF_INET;
receiveaddr.sin_family = PF_INET;
//Setup ports to send on DATA and receive on RECEIVE
receiveaddr.sin_port = htons (NERDJACK_UDP_RECEIVE_PORT);
sa.sin_port = htons (NERDJACK_DATA_PORT);
//Receive from any IP address, Will send to broadcast
receiveaddr.sin_addr.s_addr = INADDR_ANY;
sa.sin_addr.s_addr = INADDR_BROADCAST;
lFromLen = sizeof(sFromAddr);
if(0 > recvfrom_timeout(receivesock, incomingData, sizeof(incomingData),0,(struct sockaddr *) &sFromAddr, &lFromLen,
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT })) {
return -1;
bind (receivesock, (struct sockaddr *) &receiveaddr,
sizeof (struct sockaddr_in));
bytes_sent =
sendto (sock, buffer, buffer_length, 0, (struct sockaddr *) &sa,
sizeof (struct sockaddr_in));
if (bytes_sent < 0)
{
info ("Error sending packet: %s\n", strerror (errno));
return -1;
}
ipAddress = malloc(INET_ADDRSTRLEN);
//It isn't ipv6 friendly, but inet_ntop isn't on Windows...
strcpy(ipAddress, inet_ntoa(sFromAddr.sin_addr));
close(sock); /* close the socket */
close(receivesock);
return 0;
lFromLen = sizeof (sFromAddr);
if (0 >
recvfrom_timeout (receivesock, incomingData, sizeof (incomingData), 0,
(struct sockaddr *) &sFromAddr, &lFromLen,
&(struct timeval)
{
.tv_sec = NERDJACK_TIMEOUT}))
{
return -1;
}
ipAddress = malloc (INET_ADDRSTRLEN);
//It isn't ipv6 friendly, but inet_ntop isn't on Windows...
strcpy (ipAddress, inet_ntoa (sFromAddr.sin_addr));
close (sock); /* close the socket */
close (receivesock);
return 0;
}
int nerd_send_command(const char * address, void * command, int length)
int
nerd_send_command (const char *address, void *command, int length)
{
int ret,fd_command;
char buf[3];
fd_command = nerd_open(address, NERDJACK_COMMAND_PORT);
if (fd_command < 0) {
info("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT);
return -2;
int ret, fd_command;
char buf[3];
fd_command = nerd_open (address, NERDJACK_COMMAND_PORT);
if (fd_command < 0)
{
info ("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT);
return -2;
}
/* Send request */
ret = send_all_timeout(fd_command, command, length, 0,
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT });
if (ret < 0 || ret != length) {
verb("short send %d\n", (int)ret);
return -1;
}
/* Send request */
ret = send_all_timeout (fd_command, command, length, 0, &(struct timeval)
{
.tv_sec = NERDJACK_TIMEOUT});
if (ret < 0 || ret != length)
{
verb ("short send %d\n", (int) ret);
return -1;
}
ret = recv_all_timeout(fd_command,buf,3,0,
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT });
ret = recv_all_timeout (fd_command, buf, 3, 0, &(struct timeval)
{
.tv_sec = NERDJACK_TIMEOUT});
nerd_close_conn(fd_command);
nerd_close_conn (fd_command);
if (ret < 0 || ret != 3) {
verb("Error receiving OK for command\n");
return -1;
}
if (ret < 0 || ret != 3)
{
verb ("Error receiving OK for command\n");
return -1;
}
if (0 != strcmp("OK",buf)){
verb("Did not receive OK. Received %s\n",buf);
return -3;
if (0 != strcmp ("OK", buf))
{
verb ("Did not receive OK. Received %s\n", buf);
return -3;
}
return 0;
return 0;
}
//Initialize the channel structure to distill how data should be displayed
static void nerd_init_channels(deststruct * destination, int numChannels, int numChannelsSampled, int *channel_list) {
int channelprocessing = 0;
int currentalign = 0; //Index into sampled channels
int i;
int tempdestlist[NERDJACK_CHANNELS];
//Clear out destination stuff
for(i=0; i < numChannelsSampled;i++) {
destination[i].numCopies = 0;
static void
nerd_init_channels (deststruct * destination, int numChannels,
int numChannelsSampled, int *channel_list)
{
int channelprocessing = 0;
int currentalign = 0; //Index into sampled channels
int i;
int tempdestlist[NERDJACK_CHANNELS];
//Clear out destination stuff
for (i = 0; i < numChannelsSampled; i++)
{
destination[i].numCopies = 0;
}
for(channelprocessing = 0; channelprocessing < numChannelsSampled; channelprocessing++) {
//Find out how many copies of each channel so we malloc the right things
currentalign = 0;
for(i = 0; i < numChannels; i++) {
if(channelprocessing == channel_list[i]) {
tempdestlist[currentalign] = i;
currentalign++;
}
}
//If this channel is wanted, set it up.
if(currentalign > 0) {
destination[channelprocessing].numCopies = currentalign;
destination[channelprocessing].destlist = malloc( destination[channelprocessing].numCopies * sizeof(int) );
memcpy(destination[channelprocessing].destlist, tempdestlist, destination[channelprocessing].numCopies * sizeof(int) );
}
for (channelprocessing = 0; channelprocessing < numChannelsSampled;
channelprocessing++)
{
//Find out how many copies of each channel so we malloc the right things
currentalign = 0;
for (i = 0; i < numChannels; i++)
{
if (channelprocessing == channel_list[i])
{
tempdestlist[currentalign] = i;
currentalign++;
}
}
//If this channel is wanted, set it up.
if (currentalign > 0)
{
destination[channelprocessing].numCopies = currentalign;
destination[channelprocessing].destlist =
malloc (destination[channelprocessing].numCopies * sizeof (int));
memcpy (destination[channelprocessing].destlist, tempdestlist,
destination[channelprocessing].numCopies * sizeof (int));
}
}
return;
return;
}
int nerd_data_stream(int data_fd, int numChannels, int *channel_list, int precision, int convert, int lines, int showmem, unsigned short * currentcount, unsigned int period)
int
nerd_data_stream (int data_fd, int numChannels, int *channel_list,
int precision, int convert, int lines, int showmem,
unsigned short *currentcount, unsigned int period)
{
//Variables that should persist across retries
static dataPacket buf;
static int linesleft = 0;
static int linesdumped = 0;
int index = 0;
int charsprocessed = 0;
int alignment = 0;
signed short datapoint = 0;
unsigned short dataline[NERDJACK_CHANNELS];
long double voltline[NERDJACK_CHANNELS];
int i;
unsigned long memused = 0;
unsigned short packetsready = 0;
unsigned short adcused = 0;
unsigned short tempshort = 0;
int charsread = 0;
int numgroups = 0;
long double volts;
unsigned int expectedtimeout = (period * NERDJACK_NUM_SAMPLES / NERDJACK_CLOCK_RATE) + 2;
//Check to see if we're trying to resume
//Don't blow away linesleft in that case
if(lines != 0 && linesleft == 0) {
linesleft = lines;
//Variables that should persist across retries
static dataPacket buf;
static int linesleft = 0;
static int linesdumped = 0;
int index = 0;
int charsprocessed = 0;
int alignment = 0;
signed short datapoint = 0;
unsigned short dataline[NERDJACK_CHANNELS];
long double voltline[NERDJACK_CHANNELS];
int i;
unsigned long memused = 0;
unsigned short packetsready = 0;
unsigned short adcused = 0;
unsigned short tempshort = 0;
int charsread = 0;
int numgroups = 0;
long double volts;
unsigned int expectedtimeout =
(period * NERDJACK_NUM_SAMPLES / NERDJACK_CLOCK_RATE) + 2;
//Check to see if we're trying to resume
//Don't blow away linesleft in that case
if (lines != 0 && linesleft == 0)
{
linesleft = lines;
}
int numChannelsSampled = channel_list[0] + 1;
//The number sampled will be the highest channel requested plus 1 (i.e. channel 0 requested means 1 sampled)
for(i = 0; i < numChannels; i++) {
if (channel_list[i] + 1 > numChannelsSampled)
numChannelsSampled = channel_list[i] + 1;
int numChannelsSampled = channel_list[0] + 1;
//The number sampled will be the highest channel requested plus 1 (i.e. channel 0 requested means 1 sampled)
for (i = 0; i < numChannels; i++)
{
if (channel_list[i] + 1 > numChannelsSampled)
numChannelsSampled = channel_list[i] + 1;
}
deststruct destination[numChannelsSampled];
nerd_init_channels(destination,numChannels,numChannelsSampled, channel_list);
//Now destination structure array is set as well as numDuplicates.
deststruct destination[numChannelsSampled];
//int numChannelsSampled = numChannels - numDuplicates;
int numGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled;
nerd_init_channels (destination, numChannels, numChannelsSampled,
channel_list);
//Loop forever to grab data
while((charsread = recv_all_timeout(data_fd,&buf,NERDJACK_PACKET_SIZE,0,
& (struct timeval) { .tv_sec = expectedtimeout }))){
//Now destination structure array is set as well as numDuplicates.
//We want a complete packet, so take the chars so far and keep waiting
if(charsread != NERDJACK_PACKET_SIZE) {
//There was a problem getting data. Probably a closed
//connection.
info("Packet timed out or was too short\n");
return -2;
}
//int numChannelsSampled = numChannels - numDuplicates;
int numGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled;
//First check the header info
if(buf.headerone != 0xF0 || buf.headertwo != 0xAA) {
info("No Header info\n");
return -1;
}
//Check counter info to make sure not out of order
tempshort = ntohs(buf.packetNumber);
//tempshort = (buf[2] << 8) | buf[3];
if(tempshort != *currentcount ){
info("Count wrong. Expected %hd but got %hd\n", *currentcount, tempshort);
return -1;
//Loop forever to grab data
while ((charsread =
recv_all_timeout (data_fd, &buf, NERDJACK_PACKET_SIZE, 0,
&(struct timeval)
{
.tv_sec = expectedtimeout})))
{
//We want a complete packet, so take the chars so far and keep waiting
if (charsread != NERDJACK_PACKET_SIZE)
{
//There was a problem getting data. Probably a closed
//connection.
info ("Packet timed out or was too short\n");
return -2;
}
//First check the header info
if (buf.headerone != 0xF0 || buf.headertwo != 0xAA)
{
info ("No Header info\n");
return -1;
}
//Check counter info to make sure not out of order
tempshort = ntohs (buf.packetNumber);
//tempshort = (buf[2] << 8) | buf[3];
if (tempshort != *currentcount)
{
info ("Count wrong. Expected %hd but got %hd\n", *currentcount,
tempshort);
return -1;
}
//Increment number of packets received
*currentcount = *currentcount + 1;
//Process the rest of the header and update the index value to be pointing after it
charsprocessed = 12;
memused = ntohl (buf.lwipmemoryused);
adcused = ntohs (buf.adcused);
packetsready = ntohs (buf.packetsready);
alignment = 0;
numgroups = 0;
if (showmem)
{
printf ("%lX %hd %hd\n", memused, adcused, packetsready);
continue;
}
index = 0;
//While there is still more data in the packet, process it
//use the destination structure to load the line before printing
while (charsread > charsprocessed)
{
datapoint = ntohs (buf.data[index]);
if (destination[alignment].numCopies != 0)
{
switch (convert)
{
case CONVERT_VOLTS:
if (alignment <= 5)
{
volts =
(long double) (datapoint / 32767.0) *
((precision & 0x01) ? 5.0 : 10.0);
}
else
{
volts =
(long double) (datapoint / 32767.0) *
((precision & 0x02) ? 5.0 : 10.0);
}
for (i = 0; i < destination[alignment].numCopies; i++)
{
voltline[destination[alignment].destlist[i]] = volts;
}
break;
default:
case CONVERT_HEX:
case CONVERT_DEC:
for (i = 0; i < destination[alignment].numCopies; i++)
{
dataline[destination[alignment].destlist[i]] =
(unsigned short) (datapoint - INT16_MIN);
}
break;
}
//Increment number of packets received
*currentcount = *currentcount + 1;
//Process the rest of the header and update the index value to be pointing after it
charsprocessed = 12;
memused = ntohl(buf.lwipmemoryused);
adcused = ntohs(buf.adcused);
packetsready = ntohs(buf.packetsready);
alignment = 0;
numgroups = 0;
if(showmem) {
printf("%lX %hd %hd\n",memused, adcused, packetsready);
continue;
}
index = 0;
//While there is still more data in the packet, process it
//use the destination structure to load the line before printing
while(charsread > charsprocessed) {
datapoint = ntohs(buf.data[index]);
if(destination[alignment].numCopies != 0) {
switch(convert) {
case CONVERT_VOLTS:
if(alignment <= 5) {
volts = (long double) ( datapoint / 32767.0 ) * ((precision & 0x01) ? 5.0 : 10.0);
} else {
volts = (long double) (datapoint / 32767.0 ) * ((precision & 0x02) ? 5.0 : 10.0);
}
for(i = 0; i < destination[alignment].numCopies; i++) {
voltline[destination[alignment].destlist[i]] = volts;
}
break;
default:
case CONVERT_HEX:
case CONVERT_DEC:
for(i = 0; i < destination[alignment].numCopies; i++) {
dataline[destination[alignment].destlist[i]] =
(unsigned short) (datapoint - INT16_MIN);
}
break;
}
//Each point is two bytes, so increment index and total bytes read
charsprocessed++;
charsprocessed++;
index++;
alignment++;
//Since channel data is packed, we need to know when to insert a newline
if (alignment == numChannelsSampled)
{
if (linesdumped != 0)
{
switch (convert)
{
case CONVERT_VOLTS:
for (i = 0; i < numChannels; i++)
{
if (printf ("%Lf ", voltline[i]) < 0)
goto bad;
}
break;
case CONVERT_HEX:
for (i = 0; i < numChannels; i++)
{
if (printf ("%04hX", dataline[i]) < 0)
goto bad;
}
}
//Each point is two bytes, so increment index and total bytes read
charsprocessed++;
charsprocessed++;
index++;
alignment++;
//Since channel data is packed, we need to know when to insert a newline
if(alignment == numChannelsSampled){
if(linesdumped != 0){
switch(convert) {
case CONVERT_VOLTS:
for(i = 0; i < numChannels; i++) {
if (printf("%Lf ",voltline[i]) < 0)
goto bad;
}
break;
case CONVERT_HEX:
for(i = 0; i < numChannels; i++) {
if (printf("%04hX",dataline[i]) < 0)
goto bad;
}
break;
default:
case CONVERT_DEC:
for(i = 0; i < numChannels; i++) {
if (printf("%hu ",dataline[i]) < 0)
goto bad;
}
break;
}
if(printf("\n") < 0)
goto bad;
} else {
linesdumped = linesdumped + 1;
if(lines != 0) {
linesleft++;
}
}
alignment = 0;
numgroups++;
if(lines != 0) {
linesleft--;
if(linesleft == 0) {
return 0;
}
}
//If numgroups so far is equal to the numGroups in a packet, this packet is done
if(numgroups == numGroups) {
break;
}
break;
default:
case CONVERT_DEC:
for (i = 0; i < numChannels; i++)
{
if (printf ("%hu ", dataline[i]) < 0)
goto bad;
}
break;
}
if (printf ("\n") < 0)
goto bad;
}
else
{
linesdumped = linesdumped + 1;
if (lines != 0)
{
linesleft++;
}
}
alignment = 0;
numgroups++;
if (lines != 0)
{
linesleft--;
if (linesleft == 0)
{
return 0;
}
}
index = 0;
charsprocessed = 0;
//If numgroups so far is equal to the numGroups in a packet, this packet is done
if (numgroups == numGroups)
{
break;
}
}
}
index = 0;
charsprocessed = 0;
}
return 0;
return 0;
bad:
info("Output error (disk full?)\n");
return -1;
info ("Output error (disk full?)\n");
return -1;
}
int nerd_open(const char *address,int port) {
struct hostent *he;
net_init();
int32_t i32SocketFD = socket(PF_INET, SOCK_STREAM, 0);
int
nerd_open (const char *address, int port)
{
if(-1 == i32SocketFD)
struct hostent *he;
net_init ();
int32_t i32SocketFD = socket (PF_INET, SOCK_STREAM, 0);
if (-1 == i32SocketFD)
{
verb("cannot create socket");
verb ("cannot create socket");
return -1;
}
/* Set nonblocking */
if (soblock (i32SocketFD, 0) < 0)
{
verb ("can't set nonblocking\n");
return -1;
}
/* Set nonblocking */
if (soblock(i32SocketFD, 0) < 0) {
verb("can't set nonblocking\n");
return -1;
}
struct sockaddr_in stSockAddr;
memset(&stSockAddr, 0, sizeof(stSockAddr));
struct sockaddr_in stSockAddr;
memset (&stSockAddr, 0, sizeof (stSockAddr));
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(port);
he = gethostbyname(address);
if (he == NULL) {
verb("gethostbyname(\"%s\") failed\n", address);
return -1;
}
stSockAddr.sin_addr = *((struct in_addr *) he->h_addr);
debug("Resolved %s -> %s\n", address, inet_ntoa(stSockAddr.sin_addr));
/* Connect */
if (connect_timeout(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof(stSockAddr),
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }) < 0) {
verb("connection to %s:%d failed: %s\n",
inet_ntoa(stSockAddr.sin_addr), port, compat_strerror(errno));
return -1;
}
return i32SocketFD;
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons (port);
he = gethostbyname (address);
if (he == NULL)
{
verb ("gethostbyname(\"%s\") failed\n", address);
return -1;
}
stSockAddr.sin_addr = *((struct in_addr *) he->h_addr);
debug ("Resolved %s -> %s\n", address, inet_ntoa (stSockAddr.sin_addr));
/* Connect */
if (connect_timeout
(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof (stSockAddr),
&(struct timeval)
{
.tv_sec = NERDJACK_TIMEOUT}) < 0)
{
verb ("connection to %s:%d failed: %s\n",
inet_ntoa (stSockAddr.sin_addr), port, compat_strerror (errno));
return -1;
}
return i32SocketFD;
}
//Generate an appropriate sample initiation command
int nerd_generate_command(getPacket * command, int * channel_list, int channel_count, int precision,
unsigned long period) {
short channelbit = 0;
int i;
for( i = 0; i < channel_count; i++) {
channelbit = channelbit | (0x1 << channel_list[i]);
int
nerd_generate_command (getPacket * command, int *channel_list,
int channel_count, int precision, unsigned long period)
{
short channelbit = 0;
int i;
for (i = 0; i < channel_count; i++)
{
channelbit = channelbit | (0x1 << channel_list[i]);
}
//command->word = "GETD";
command->word[0] = 'G';
command->word[1] = 'E';
command->word[2] = 'T';
command->word[3] = 'D';
command->channelbit = htons(channelbit);
command->precision = precision;
command->period = htonl(period);
command->prescaler = 0;
//sprintf(command,"GETD%3.3X%d%5.5d", channelbit,precision,period);
return 0;
//command->word = "GETD";
command->word[0] = 'G';
command->word[1] = 'E';
command->word[2] = 'T';
command->word[3] = 'D';
command->channelbit = htons (channelbit);
command->precision = precision;
command->period = htonl (period);
command->prescaler = 0;
//sprintf(command,"GETD%3.3X%d%5.5d", channelbit,precision,period);
return 0;
}
int nerd_close_conn(int data_fd)
int
nerd_close_conn (int data_fd)
{
shutdown(data_fd, 2);
close(data_fd);
return 0;
shutdown (data_fd, 2);
close (data_fd);
return 0;
}
......@@ -24,33 +24,38 @@
#define NERDJACK_PACKET_SIZE 1460
#define NERDJACK_NUM_SAMPLES 724
typedef struct __attribute__((__packed__)) {
char word[4];
unsigned short channelbit;
unsigned char precision;
unsigned long period;
unsigned char prescaler;
typedef struct __attribute__ ((__packed__))
{
char word[4];
unsigned short channelbit;
unsigned char precision;
unsigned long period;
unsigned char prescaler;
} getPacket;
/* Open/close TCP/IP connection to the NerdJack */
int nerd_open(const char *address,int port);
int nerd_close_conn(int data_fd);
int nerd_open (const char *address, int port);
int nerd_close_conn (int data_fd);
/* Generate the command word for the NerdJack */
int nerd_generate_command(getPacket * command, int * channel_list, int channel_count, int precision,
unsigned long period);
int nerd_generate_command (getPacket * command, int *channel_list,
int channel_count, int precision,
unsigned long period);
/* Send given command to NerdJack */
int nerd_send_command(const char * address, void * command, int length);
int nerd_send_command (const char *address, void *command, int length);
/* Stream data out of the NerdJack */
int nerd_data_stream(int data_fd, int numChannels, int * channel_list, int precision, int convert, int lines, int showmem, unsigned short * currentcount, unsigned int period);
int nerd_data_stream (int data_fd, int numChannels, int *channel_list,
int precision, int convert, int lines, int showmem,
unsigned short *currentcount, unsigned int period);
/* Detect the IP Address of the NerdJack and return in ipAddress */
int nerdjack_detect(char * ipAddress);
int nerdjack_detect (char *ipAddress);
/* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns -1 if no valid config found */
int nerdjack_choose_scan(double desired_rate, double *actual_rate, unsigned long *period);
int nerdjack_choose_scan (double desired_rate, double *actual_rate,
unsigned long *period);
#endif
......@@ -5,239 +5,262 @@
#include <stdio.h>
/* Initialize networking */
void net_init(void)
void
net_init (void)
{
#ifdef __WIN32__
WSADATA blah;
WSAStartup(0x0101, &blah);
WSADATA blah;
WSAStartup (0x0101, &blah);
#endif
}
/* Set socket blocking/nonblocking */
int soblock(int socket, int blocking)
int
soblock (int socket, int blocking)
{
#ifdef __WIN32__
unsigned long arg = blocking ? 0 : 1;
if (ioctlsocket(socket, FIONBIO, &arg) != 0)
return -1;
return 0;
unsigned long arg = blocking ? 0 : 1;
if (ioctlsocket (socket, FIONBIO, &arg) != 0)
return -1;
return 0;
#else
int sockopt;
/* Get flags */
sockopt = fcntl(socket, F_GETFL);
if (sockopt == -1) {
return -1;
}
/* Modify */
if (blocking)
sockopt &= ~O_NONBLOCK;
else
sockopt |= O_NONBLOCK;
/* Set flags */
if (fcntl(socket, F_SETFL, sockopt) != 0)
return -1;
return 0;
int sockopt;
/* Get flags */
sockopt = fcntl (socket, F_GETFL);
if (sockopt == -1)
{
return -1;
}
/* Modify */
if (blocking)
sockopt &= ~O_NONBLOCK;
else
sockopt |= O_NONBLOCK;
/* Set flags */
if (fcntl (socket, F_SETFL, sockopt) != 0)
return -1;
return 0;
#endif
}
/* Like connect(2), but with a timeout. Socket must be non-blocking. */
int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
struct timeval *timeout)
int
connect_timeout (int s, const struct sockaddr *serv_addr, socklen_t addrlen,
struct timeval *timeout)
{
int ret;
fd_set writefds;
fd_set exceptfds;
int optval;
socklen_t optlen;
/* Start connect */
ret = connect(s, serv_addr, addrlen);
if (ret == 0) {
/* Success */
return 0;
}
/* Check for immediate failure */
int ret;
fd_set writefds;
fd_set exceptfds;
int optval;
socklen_t optlen;
/* Start connect */
ret = connect (s, serv_addr, addrlen);
if (ret == 0)
{
/* Success */
return 0;
}
/* Check for immediate failure */
#ifdef __WIN32__
errno = WSAGetLastError();
if (ret < 0 && errno != WSAEWOULDBLOCK && errno != WSAEINVAL)
return -1;
errno = WSAGetLastError ();
if (ret < 0 && errno != WSAEWOULDBLOCK && errno != WSAEINVAL)
return -1;
#else
if (ret < 0 && errno != EINPROGRESS && errno != EALREADY)
return -1;
if (ret < 0 && errno != EINPROGRESS && errno != EALREADY)
return -1;
#endif
/* In progress, wait for result. */
FD_ZERO(&writefds);
FD_SET(s, &writefds);
FD_ZERO(&exceptfds);
FD_SET(s, &exceptfds);
ret = select(s + 1, NULL, &writefds, &exceptfds, timeout);
if (ret < 0) {
/* Error */
return -1;
}
if (ret == 0) {
/* Timed out */
errno = ETIMEDOUT;
return -1;
}
/* Check the socket state */
optlen = sizeof(optval);
if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen) != 0)
return -1;
if (optval != 0) {
/* Connection failed. */
errno = optval;
return -1;
}
/* On Windows, SO_ERROR sometimes shows no error but the connection
still failed. Sigh. */
if (FD_ISSET(s, &exceptfds) || !FD_ISSET(s, &writefds)) {
errno = EIO;
return -1;
}
/* Success */
return 0;
/* In progress, wait for result. */
FD_ZERO (&writefds);
FD_SET (s, &writefds);
FD_ZERO (&exceptfds);
FD_SET (s, &exceptfds);
ret = select (s + 1, NULL, &writefds, &exceptfds, timeout);
if (ret < 0)
{
/* Error */
return -1;
}
if (ret == 0)
{
/* Timed out */
errno = ETIMEDOUT;
return -1;
}
/* Check the socket state */
optlen = sizeof (optval);
if (getsockopt (s, SOL_SOCKET, SO_ERROR, (void *) &optval, &optlen) != 0)
return -1;
if (optval != 0)
{
/* Connection failed. */
errno = optval;
return -1;
}
/* On Windows, SO_ERROR sometimes shows no error but the connection
still failed. Sigh. */
if (FD_ISSET (s, &exceptfds) || !FD_ISSET (s, &writefds))
{
errno = EIO;
return -1;
}
/* Success */
return 0;
}
/* Like send(2), but with a timeout. Socket must be non-blocking.
The timeout only applies if no data at all is sent -- this function
may still send less than requested. */
ssize_t send_timeout(int s, const void *buf, size_t len, int flags,
struct timeval *timeout)
ssize_t
send_timeout (int s, const void *buf, size_t len, int flags,
struct timeval * timeout)
{
fd_set writefds;
int ret;
FD_ZERO(&writefds);
FD_SET(s, &writefds);
ret = select(s + 1, NULL, &writefds, NULL, timeout);
if (ret == 0) {
/* Timed out */
errno = ETIMEDOUT;
return -1;
}
if (ret != 1) {
/* Error */
return -1;
}
return send(s, buf, len, flags);
fd_set writefds;
int ret;
FD_ZERO (&writefds);
FD_SET (s, &writefds);
ret = select (s + 1, NULL, &writefds, NULL, timeout);
if (ret == 0)
{
/* Timed out */
errno = ETIMEDOUT;
return -1;
}
if (ret != 1)
{
/* Error */
return -1;
}
return send (s, buf, len, flags);
}
/* Like recv(2), but with a timeout. Socket must be non-blocking.
The timeout only applies if no data at all is received -- this
function may still return less than requested. */
ssize_t recv_timeout(int s, void *buf, size_t len, int flags,
struct timeval *timeout)
ssize_t
recv_timeout (int s, void *buf, size_t len, int flags,
struct timeval * timeout)
{
fd_set readfds;
int ret;
FD_ZERO(&readfds);
FD_SET(s, &readfds);
ret = select(s + 1, &readfds, NULL, NULL, timeout);
if (ret == 0) {
/* Timed out */
errno = ETIMEDOUT;
return -1;
}
if (ret != 1) {
/* Error */
return -1;
}
return recv(s, buf, len, flags);
fd_set readfds;
int ret;
FD_ZERO (&readfds);
FD_SET (s, &readfds);
ret = select (s + 1, &readfds, NULL, NULL, timeout);
if (ret == 0)
{
/* Timed out */
errno = ETIMEDOUT;
return -1;
}
if (ret != 1)
{
/* Error */
return -1;
}
return recv (s, buf, len, flags);
}
/* Like recvfrom(2), but with a timeout. Socket must be non-blocking.
The timeout only applies if no data at all is received -- this
function may still return less than requested. */
ssize_t recvfrom_timeout(int s, void *buf, size_t len, int flags, struct sockaddr *address, socklen_t *address_len,
struct timeval *timeout)
ssize_t
recvfrom_timeout (int s, void *buf, size_t len, int flags,
struct sockaddr * address, socklen_t * address_len,
struct timeval * timeout)
{
fd_set readfds;
int ret;
FD_ZERO(&readfds);
FD_SET(s, &readfds);
ret = select(s + 1, &readfds, NULL, NULL, timeout);
if (ret == 0) {
/* Timed out */
errno = ETIMEDOUT;
return -1;
}
if (ret != 1) {
/* Error */
return -1;
}
return recvfrom(s, buf, len, flags, address, address_len);
fd_set readfds;
int ret;
FD_ZERO (&readfds);
FD_SET (s, &readfds);
ret = select (s + 1, &readfds, NULL, NULL, timeout);
if (ret == 0)
{
/* Timed out */
errno = ETIMEDOUT;
return -1;
}
if (ret != 1)
{
/* Error */
return -1;
}
return recvfrom (s, buf, len, flags, address, address_len);
}
/* Like send_timeout, but retries (with the same timeout) in case of
partial transfers. This is a stronger attempt to send all
requested data. */
ssize_t send_all_timeout(int s, const void *buf, size_t len, int flags,
struct timeval *timeout)
ssize_t
send_all_timeout (int s, const void *buf, size_t len, int flags,
struct timeval * timeout)
{
struct timeval tv;
size_t left = len;
ssize_t ret;
struct timeval tv;
size_t left = len;
ssize_t ret;
while (left > 0) {
tv.tv_sec = timeout->tv_sec;
tv.tv_usec = timeout->tv_usec;
ret = send_timeout(s, buf, left, flags, &tv);
while (left > 0)
{
tv.tv_sec = timeout->tv_sec;
tv.tv_usec = timeout->tv_usec;
ret = send_timeout (s, buf, left, flags, &tv);
if (ret < 0)
return ret;
if (ret < 0)
return ret;
if (ret == 0)
break;
if (ret == 0)
break;
left -= ret;
buf += ret;
}
left -= ret;
buf += ret;
}
return len - left;
return len - left;
}
/* Like recv_timeout, but retries (with the same timeout) in case of
partial transfers. This is a stronger attempt to recv all
requested data. */
ssize_t recv_all_timeout(int s, void *buf, size_t len, int flags,
struct timeval *timeout)
ssize_t
recv_all_timeout (int s, void *buf, size_t len, int flags,
struct timeval * timeout)
{
struct timeval tv;
size_t left = len;
ssize_t ret;
struct timeval tv;
size_t left = len;
ssize_t ret;
while (left > 0) {
tv.tv_sec = timeout->tv_sec;
tv.tv_usec = timeout->tv_usec;
ret = recv_timeout(s, buf, left, flags, &tv);
while (left > 0)
{
tv.tv_sec = timeout->tv_sec;
tv.tv_usec = timeout->tv_usec;
ret = recv_timeout (s, buf, left, flags, &tv);
if (ret < 0)
return ret;
if (ret < 0)
return ret;
if (ret == 0)
break;
if (ret == 0)
break;
left -= ret;
buf += ret;
}
left -= ret;
buf += ret;
}
return len - left;
return len - left;
}
......@@ -19,27 +19,28 @@
#endif
/* Initialize networking */
void net_init(void);
void net_init (void);
/* Set socket blocking/nonblocking */
int soblock(int socket, int blocking);
int soblock (int socket, int blocking);
/* Like send(2), recv(2), connect(2), but with timeouts.
Socket must be O_NONBLOCK. */
int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
struct timeval *timeout);
ssize_t send_timeout(int s, const void *buf, size_t len, int flags,
struct timeval *timeout);
ssize_t recv_timeout(int s, void *buf, size_t len, int flags,
struct timeval *timeout);
ssize_t recvfrom_timeout(int s, void *buf, size_t len, int flags, struct sockaddr *address, socklen_t *address_len,
struct timeval *timeout);
int connect_timeout (int s, const struct sockaddr *serv_addr,
socklen_t addrlen, struct timeval *timeout);
ssize_t send_timeout (int s, const void *buf, size_t len, int flags,
struct timeval *timeout);
ssize_t recv_timeout (int s, void *buf, size_t len, int flags,
struct timeval *timeout);
ssize_t recvfrom_timeout (int s, void *buf, size_t len, int flags,
struct sockaddr *address, socklen_t * address_len,
struct timeval *timeout);
/* Like send_timeout and recv_timeout, but they retry (with the same timeout)
in case of partial transfers, in order to try to transfer all data. */
ssize_t send_all_timeout(int s, const void *buf, size_t len, int flags,
struct timeval *timeout);
ssize_t recv_all_timeout(int s, void *buf, size_t len, int flags,
struct timeval *timeout);
ssize_t send_all_timeout (int s, const void *buf, size_t len, int flags,
struct timeval *timeout);
ssize_t recv_all_timeout (int s, void *buf, size_t len, int flags,
struct timeval *timeout);
#endif
......@@ -11,85 +11,98 @@
#include <string.h>
#include "opt.h"
void opt_init(int *optind) {
*optind=0;
void
opt_init (int *optind)
{
*optind = 0;
}
char opt_parse(int argc, char **argv, int *optind, char **optarg,
struct options *opt) {
char c;
int i;
(*optind)++;
if(*optind>=argc)
return 0;
if(argv[*optind][0]=='-' &&
argv[*optind][1]!='-' &&
argv[*optind][1]!=0) {
/* Short option (or a bunch of 'em) */
/* Save this and shift others over */
c=argv[*optind][1];
for(i=2;argv[*optind][i]!=0;i++)
argv[*optind][i-1]=argv[*optind][i];
argv[*optind][i-1]=0;
if(argv[*optind][1]!=0)
(*optind)--;
/* Now find it */
for(i=0;opt[i].shortopt!=0;i++)
if(opt[i].shortopt==c)
break;
if(opt[i].shortopt==0) {
fprintf(stderr,"Error: unknown option '-%c'\n",c);
return '?';
}
if(opt[i].arg==NULL)
return c;
(*optind)++;
if(*optind>=argc || (argv[*optind][0]=='-' &&
argv[*optind][1]!=0)) {
fprintf(stderr,"Error: option '-%c' requires an "
"argument\n",c);
return '?';
}
(*optarg)=argv[*optind];
return c;
} else if(argv[*optind][0]=='-' &&
argv[*optind][1]=='-' &&
argv[*optind][2]!=0) {
/* Long option */
for(i=0;(c=opt[i].shortopt)!=0;i++)
if(strcmp(opt[i].longopt,argv[*optind]+2)==0)
break;
if(opt[i].shortopt==0) {
fprintf(stderr,"Error: unknown option '%s'\n",
argv[*optind]);
return '?';
}
if(opt[i].arg==NULL)
return c;
(*optind)++;
if(*optind>=argc || (argv[*optind][0]=='-' &&
argv[*optind][1]!=0)) {
fprintf(stderr,"Error: option '%s' requires an "
"argument\n",argv[*optind-1]);
return '?';
}
(*optarg)=argv[*optind];
return c;
} else {
/* End of options */
return 0;
char
opt_parse (int argc, char **argv, int *optind, char **optarg,
struct options *opt)
{
char c;
int i;
(*optind)++;
if (*optind >= argc)
return 0;
if (argv[*optind][0] == '-' &&
argv[*optind][1] != '-' && argv[*optind][1] != 0)
{
/* Short option (or a bunch of 'em) */
/* Save this and shift others over */
c = argv[*optind][1];
for (i = 2; argv[*optind][i] != 0; i++)
argv[*optind][i - 1] = argv[*optind][i];
argv[*optind][i - 1] = 0;
if (argv[*optind][1] != 0)
(*optind)--;
/* Now find it */
for (i = 0; opt[i].shortopt != 0; i++)
if (opt[i].shortopt == c)
break;
if (opt[i].shortopt == 0)
{
fprintf (stderr, "Error: unknown option '-%c'\n", c);
return '?';
}
if (opt[i].arg == NULL)
return c;
(*optind)++;
if (*optind >= argc || (argv[*optind][0] == '-' &&
argv[*optind][1] != 0))
{
fprintf (stderr, "Error: option '-%c' requires an "
"argument\n", c);
return '?';
}
(*optarg) = argv[*optind];
return c;
}
else if (argv[*optind][0] == '-' &&
argv[*optind][1] == '-' && argv[*optind][2] != 0)
{
/* Long option */
for (i = 0; (c = opt[i].shortopt) != 0; i++)
if (strcmp (opt[i].longopt, argv[*optind] + 2) == 0)
break;
if (opt[i].shortopt == 0)
{
fprintf (stderr, "Error: unknown option '%s'\n", argv[*optind]);
return '?';
}
if (opt[i].arg == NULL)
return c;
(*optind)++;
if (*optind >= argc || (argv[*optind][0] == '-' &&
argv[*optind][1] != 0))
{
fprintf (stderr, "Error: option '%s' requires an "
"argument\n", argv[*optind - 1]);
return '?';
}
(*optarg) = argv[*optind];
return c;
}
else
{
/* End of options */
return 0;
}
}
void opt_help(struct options *opt, FILE *out) {
int i;
int printed;
void
opt_help (struct options *opt, FILE * out)
{
int i;
int printed;
for(i=0;opt[i].shortopt!=0;i++) {
fprintf(out," -%c, --%s%n",opt[i].shortopt,
opt[i].longopt,&printed);
fprintf(out," %-*s%s\n",30-printed,
opt[i].arg?opt[i].arg:"",opt[i].help);
}
for (i = 0; opt[i].shortopt != 0; i++)
{
fprintf (out, " -%c, --%s%n", opt[i].shortopt,
opt[i].longopt, &printed);
fprintf (out, " %-*s%s\n", 30 - printed,
opt[i].arg ? opt[i].arg : "", opt[i].help);
}
}
......@@ -11,18 +11,19 @@
#include <stdlib.h>
struct options {
char shortopt;
char *longopt;
char *arg;
char *help;
struct options
{
char shortopt;
char *longopt;
char *arg;
char *help;
};
void opt_init(int *optind);
void opt_init (int *optind);
char opt_parse(int argc, char **argv, int *optind, char **optarg,
struct options *opt);
char opt_parse (int argc, char **argv, int *optind, char **optarg,
struct options *opt);
void opt_help(struct options *opt, FILE *out);
void opt_help (struct options *opt, FILE * out);
#endif
......@@ -25,629 +25,725 @@
#include "util.h"
#include "netutil.h"
#define UE9_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
#define UE9_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
/* Fill checksums in data buffers, with "normal" checksum format */
void ue9_checksum_normal(uint8_t *buffer, size_t len)
void
ue9_checksum_normal (uint8_t * buffer, size_t len)
{
uint16_t sum = 0;
if (len < 1) {
fprintf(stderr, "ue9_checksum_normal: len too short\n");
exit(1);
}
while (--len >= 1)
sum += (uint16_t) buffer[len];
sum = (sum / 256) + (sum % 256);
sum = (sum / 256) + (sum % 256);
buffer[0] = (uint8_t) sum;
uint16_t sum = 0;
if (len < 1)
{
fprintf (stderr, "ue9_checksum_normal: len too short\n");
exit (1);
}
while (--len >= 1)
sum += (uint16_t) buffer[len];
sum = (sum / 256) + (sum % 256);
sum = (sum / 256) + (sum % 256);
buffer[0] = (uint8_t) sum;
}
/* Fill checksums in data buffers, with "extended" checksum format */
void ue9_checksum_extended(uint8_t *buffer, size_t len)
void
ue9_checksum_extended (uint8_t * buffer, size_t len)
{
uint16_t sum = 0;
if (len < 6) {
fprintf(stderr, "ue9_checksum_extended: len too short\n");
exit(1);
}
/* 16-bit extended checksum */
while (--len >= 6)
sum += (uint16_t) buffer[len];
buffer[4] = (uint8_t) (sum & 0xff);
buffer[5] = (uint8_t) (sum >> 8);
/* 8-bit normal checksum over first 6 bytes */
ue9_checksum_normal(buffer, 6);
uint16_t sum = 0;
if (len < 6)
{
fprintf (stderr, "ue9_checksum_extended: len too short\n");
exit (1);
}
/* 16-bit extended checksum */
while (--len >= 6)
sum += (uint16_t) buffer[len];
buffer[4] = (uint8_t) (sum & 0xff);
buffer[5] = (uint8_t) (sum >> 8);
/* 8-bit normal checksum over first 6 bytes */
ue9_checksum_normal (buffer, 6);
}
/* Verify checksums in data buffers, with "normal" checksum format. */
int ue9_verify_normal(uint8_t *buffer, size_t len)
int
ue9_verify_normal (uint8_t * buffer, size_t len)
{
uint8_t saved, new;
if (len < 1) {
fprintf(stderr, "ue9_verify_normal: len too short\n");
exit(1);
}
saved = buffer[0];
ue9_checksum_normal(buffer, len);
new = buffer[0];
buffer[0] = saved;
if (new != saved) {
verb("got %02x, expected %02x\n",
saved, new);
return 0;
}
return 1;
uint8_t saved, new;
if (len < 1)
{
fprintf (stderr, "ue9_verify_normal: len too short\n");
exit (1);
}
saved = buffer[0];
ue9_checksum_normal (buffer, len);
new = buffer[0];
buffer[0] = saved;
if (new != saved)
{
verb ("got %02x, expected %02x\n", saved, new);
return 0;
}
return 1;
}
/* Verify checksums in data buffers, with "extended" checksum format. */
int ue9_verify_extended(uint8_t *buffer, size_t len)
int
ue9_verify_extended (uint8_t * buffer, size_t len)
{
uint8_t saved[3], new[3];
if (len < 6) {
fprintf(stderr, "ue9_verify_extended: len too short\n");
exit(1);
}
saved[0] = buffer[0];
saved[1] = buffer[4];
saved[2] = buffer[5];
ue9_checksum_extended(buffer, len);
new[0] = buffer[0];
new[1] = buffer[4];
new[2] = buffer[5];
buffer[0] = saved[0];
buffer[4] = saved[1];
buffer[5] = saved[2];
if (saved[0] != new[0] ||
saved[1] != new[1] ||
saved[2] != new[2]) {
verb("got %02x %02x %02x, expected %02x %02x %02x\n",
saved[0], saved[1], saved[2], new[0], new[1], new[2]);
return 0;
}
return 1;
}
uint8_t saved[3], new[3];
if (len < 6)
{
fprintf (stderr, "ue9_verify_extended: len too short\n");
exit (1);
}
saved[0] = buffer[0];
saved[1] = buffer[4];
saved[2] = buffer[5];
ue9_checksum_extended (buffer, len);
new[0] = buffer[0];
new[1] = buffer[4];
new[2] = buffer[5];
buffer[0] = saved[0];
buffer[4] = saved[1];
buffer[5] = saved[2];
if (saved[0] != new[0] || saved[1] != new[1] || saved[2] != new[2])
{
verb ("got %02x %02x %02x, expected %02x %02x %02x\n",
saved[0], saved[1], saved[2], new[0], new[1], new[2]);
return 0;
}
return 1;
}
/* Data conversion. If calib is NULL, use uncalibrated conversions. */
double ue9_binary_to_analog(struct ue9Calibration *calib,
uint8_t gain, uint8_t resolution, uint16_t data)
double
ue9_binary_to_analog (struct ue9Calibration *calib,
uint8_t gain, uint8_t resolution, uint16_t data)
{
double slope = 0, offset;
if (calib == NULL) {
double uncal[9] = { 5.08, 2.54, 1.27, 0.63, 0, 0, 0, 0, 10.25 };
if (gain >= ARRAY_SIZE(uncal) || uncal[gain] == 0) {
fprintf(stderr, "ue9_binary_to_analog: bad gain\n");
exit(1);
}
return data * uncal[gain] / 65536.0;
double slope = 0, offset;
if (calib == NULL)
{
double uncal[9] = { 5.08, 2.54, 1.27, 0.63, 0, 0, 0, 0, 10.25 };
if (gain >= ARRAY_SIZE (uncal) || uncal[gain] == 0)
{
fprintf (stderr, "ue9_binary_to_analog: bad gain\n");
exit (1);
}
if (resolution < 18) {
if (gain <= 3) {
slope = calib->unipolarSlope[gain];
offset = calib->unipolarOffset[gain];
} else if (gain == 8) {
slope = calib->bipolarSlope;
offset = calib->bipolarOffset;
}
} else {
if (gain == 0) {
slope = calib->hiResUnipolarSlope;
offset = calib->hiResUnipolarOffset;
} else if (gain == 8) {
slope = calib->hiResBipolarSlope;
offset = calib->hiResBipolarOffset;
}
return data * uncal[gain] / 65536.0;
}
if (resolution < 18)
{
if (gain <= 3)
{
slope = calib->unipolarSlope[gain];
offset = calib->unipolarOffset[gain];
}
if (slope == 0) {
fprintf(stderr, "ue9_binary_to_analog: bad gain\n");
exit(1);
else if (gain == 8)
{
slope = calib->bipolarSlope;
offset = calib->bipolarOffset;
}
}
else
{
if (gain == 0)
{
slope = calib->hiResUnipolarSlope;
offset = calib->hiResUnipolarOffset;
}
else if (gain == 8)
{
slope = calib->hiResBipolarSlope;
offset = calib->hiResBipolarOffset;
}
return data * slope + offset;
}
if (slope == 0)
{
fprintf (stderr, "ue9_binary_to_analog: bad gain\n");
exit (1);
}
return data * slope + offset;
}
/* Execute a command on the UE9. Returns -1 on error. Fills the
checksums on the outgoing packets, and verifies them on the
incoming packets. Data in "out" is transmitted, data in "in" is
received. */
int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen)
int
ue9_command (int fd, uint8_t * out, uint8_t * in, int inlen)
{
int extended = 0, outlen;
uint8_t saved_1, saved_3;
ssize_t ret;
if ((out[1] & 0x78) == 0x78)
extended = 1;
/* Figure out length of data payload, and fill checksums. */
if (extended) {
outlen = 6 + (out[2]) * 2;
ue9_checksum_extended(out, outlen);
} else {
outlen = 2 + (out[1] & 7) * 2;
ue9_checksum_normal(out, outlen);
}
/* Send request */
ret = send_all_timeout(fd, out, outlen, 0,
& (struct timeval) { .tv_sec = UE9_TIMEOUT });
if (ret < 0 || ret != outlen) {
verb("short send %d\n", (int)ret);
return -1;
}
/* Save a few bytes that we'll want to compare against later,
in case the caller passed the same buffer twice. */
saved_1 = out[1];
if (extended)
saved_3 = out[3];
/* Receive result */
ret = recv_all_timeout(fd, in, inlen, 0,
& (struct timeval) { .tv_sec = UE9_TIMEOUT });
if (ret < 0 || ret != inlen) {
verb("short recv %d\n", (int)ret);
return -1;
}
/* Verify it */
if ((in[1] & 0xF8) != (saved_1 & 0xF8))
verb("returned command doesn't match\n");
else if (extended && (in[3] != saved_3))
verb("extended command doesn't match\n");
else if (extended && (inlen != (6 + (in[2]) * 2)))
verb("returned extended data is the wrong len\n");
else if (!extended && (inlen != (2 + (in[1] & 7) * 2)))
verb("returned data is the wrong len\n");
else if (extended && !ue9_verify_extended(in, inlen))
verb("extended checksum is invalid\n");
else if (!ue9_verify_normal(in, extended ? 6 : inlen))
verb("normal checksum is invalid\n");
else
return 0; /* looks good */
return -1;
int extended = 0, outlen;
uint8_t saved_1, saved_3;
ssize_t ret;
if ((out[1] & 0x78) == 0x78)
extended = 1;
/* Figure out length of data payload, and fill checksums. */
if (extended)
{
outlen = 6 + (out[2]) * 2;
ue9_checksum_extended (out, outlen);
}
else
{
outlen = 2 + (out[1] & 7) * 2;
ue9_checksum_normal (out, outlen);
}
/* Send request */
ret = send_all_timeout (fd, out, outlen, 0, &(struct timeval)
{
.tv_sec = UE9_TIMEOUT});
if (ret < 0 || ret != outlen)
{
verb ("short send %d\n", (int) ret);
return -1;
}
/* Save a few bytes that we'll want to compare against later,
in case the caller passed the same buffer twice. */
saved_1 = out[1];
if (extended)
saved_3 = out[3];
/* Receive result */
ret = recv_all_timeout (fd, in, inlen, 0, &(struct timeval)
{
.tv_sec = UE9_TIMEOUT});
if (ret < 0 || ret != inlen)
{
verb ("short recv %d\n", (int) ret);
return -1;
}
/* Verify it */
if ((in[1] & 0xF8) != (saved_1 & 0xF8))
verb ("returned command doesn't match\n");
else if (extended && (in[3] != saved_3))
verb ("extended command doesn't match\n");
else if (extended && (inlen != (6 + (in[2]) * 2)))
verb ("returned extended data is the wrong len\n");
else if (!extended && (inlen != (2 + (in[1] & 7) * 2)))
verb ("returned data is the wrong len\n");
else if (extended && !ue9_verify_extended (in, inlen))
verb ("extended checksum is invalid\n");
else if (!ue9_verify_normal (in, extended ? 6 : inlen))
verb ("normal checksum is invalid\n");
else
return 0; /* looks good */
return -1;
}
/* Read a memory block from the device. Returns -1 on error. */
int ue9_memory_read(int fd, int blocknum, uint8_t *buffer, int len)
int
ue9_memory_read (int fd, int blocknum, uint8_t * buffer, int len)
{
uint8_t sendbuf[8], recvbuf[136];
if (len != 128) {
fprintf(stderr,"ue9_memory_read: buffer length must be 128\n");
exit(1);
}
/* Request memory block */
sendbuf[1] = 0xf8;
sendbuf[2] = 0x01;
sendbuf[3] = 0x2a;
sendbuf[6] = 0x00;
sendbuf[7] = blocknum;
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
verb("command failed\n");
return -1;
}
/* Got it */
memcpy(buffer, recvbuf + 8, len);
return 0;
uint8_t sendbuf[8], recvbuf[136];
if (len != 128)
{
fprintf (stderr, "ue9_memory_read: buffer length must be 128\n");
exit (1);
}
/* Request memory block */
sendbuf[1] = 0xf8;
sendbuf[2] = 0x01;
sendbuf[3] = 0x2a;
sendbuf[6] = 0x00;
sendbuf[7] = blocknum;
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n");
return -1;
}
/* Got it */
memcpy (buffer, recvbuf + 8, len);
return 0;
}
/* Convert 64-bit fixed point to double type */
double ue9_fp64_to_double(uint8_t *data)
double
ue9_fp64_to_double (uint8_t * data)
{
int32_t a;
uint32_t b;
int32_t a;
uint32_t b;
a = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
b = (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0];
a = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
b = (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0];
return (double)a + (double)b / (double)4294967296.0L;
return (double) a + (double) b / (double) 4294967296.0L;
}
/* Retrieve calibration data from the device. Returns -1 on error. */
int ue9_get_calibration(int fd, struct ue9Calibration *calib)
int
ue9_get_calibration (int fd, struct ue9Calibration *calib)
{
uint8_t buf[128];
/* Block 0 */
if (ue9_memory_read(fd, 0, buf, 128) < 0) return -1;
calib->unipolarSlope[0] = ue9_fp64_to_double(buf + 0);
calib->unipolarOffset[0] = ue9_fp64_to_double(buf + 8);
calib->unipolarSlope[1] = ue9_fp64_to_double(buf + 16);
calib->unipolarOffset[1] = ue9_fp64_to_double(buf + 24);
calib->unipolarSlope[2] = ue9_fp64_to_double(buf + 32);
calib->unipolarOffset[2] = ue9_fp64_to_double(buf + 40);
calib->unipolarSlope[3] = ue9_fp64_to_double(buf + 48);
calib->unipolarOffset[3] = ue9_fp64_to_double(buf + 56);
/* Block 1 */
if (ue9_memory_read(fd, 1, buf, 128) < 0) return -1;
calib->bipolarSlope = ue9_fp64_to_double(buf + 0);
calib->bipolarOffset = ue9_fp64_to_double(buf + 8);
/* Block 2 */
if (ue9_memory_read(fd, 2, buf, 128) < 0) return -1;
calib->DACSlope[0] = ue9_fp64_to_double(buf + 0);
calib->DACOffset[0] = ue9_fp64_to_double(buf + 8);
calib->DACSlope[1] = ue9_fp64_to_double(buf + 16);
calib->DACOffset[1] = ue9_fp64_to_double(buf + 24);
calib->tempSlope = ue9_fp64_to_double(buf + 32);
calib->tempSlopeLow = ue9_fp64_to_double(buf + 48);
calib->calTemp = ue9_fp64_to_double(buf + 64);
calib->Vref = ue9_fp64_to_double(buf + 72);
calib->VrefDiv2 = ue9_fp64_to_double(buf + 88);
calib->VsSlope = ue9_fp64_to_double(buf + 96);
/* Block 3 */
if (ue9_memory_read(fd, 3, buf, 128) < 0) return -1;
calib->hiResUnipolarSlope = ue9_fp64_to_double(buf + 0);
calib->hiResUnipolarOffset = ue9_fp64_to_double(buf + 8);
/* Block 4 */
if (ue9_memory_read(fd, 4, buf, 128) < 0) return -1;
calib->hiResBipolarSlope = ue9_fp64_to_double(buf + 0);
calib->hiResBipolarOffset = ue9_fp64_to_double(buf + 8);
/* All done */
return 1;
uint8_t buf[128];
/* Block 0 */
if (ue9_memory_read (fd, 0, buf, 128) < 0)
return -1;
calib->unipolarSlope[0] = ue9_fp64_to_double (buf + 0);
calib->unipolarOffset[0] = ue9_fp64_to_double (buf + 8);
calib->unipolarSlope[1] = ue9_fp64_to_double (buf + 16);
calib->unipolarOffset[1] = ue9_fp64_to_double (buf + 24);
calib->unipolarSlope[2] = ue9_fp64_to_double (buf + 32);
calib->unipolarOffset[2] = ue9_fp64_to_double (buf + 40);
calib->unipolarSlope[3] = ue9_fp64_to_double (buf + 48);
calib->unipolarOffset[3] = ue9_fp64_to_double (buf + 56);
/* Block 1 */
if (ue9_memory_read (fd, 1, buf, 128) < 0)
return -1;
calib->bipolarSlope = ue9_fp64_to_double (buf + 0);
calib->bipolarOffset = ue9_fp64_to_double (buf + 8);
/* Block 2 */
if (ue9_memory_read (fd, 2, buf, 128) < 0)
return -1;
calib->DACSlope[0] = ue9_fp64_to_double (buf + 0);
calib->DACOffset[0] = ue9_fp64_to_double (buf + 8);
calib->DACSlope[1] = ue9_fp64_to_double (buf + 16);
calib->DACOffset[1] = ue9_fp64_to_double (buf + 24);
calib->tempSlope = ue9_fp64_to_double (buf + 32);
calib->tempSlopeLow = ue9_fp64_to_double (buf + 48);
calib->calTemp = ue9_fp64_to_double (buf + 64);
calib->Vref = ue9_fp64_to_double (buf + 72);
calib->VrefDiv2 = ue9_fp64_to_double (buf + 88);
calib->VsSlope = ue9_fp64_to_double (buf + 96);
/* Block 3 */
if (ue9_memory_read (fd, 3, buf, 128) < 0)
return -1;
calib->hiResUnipolarSlope = ue9_fp64_to_double (buf + 0);
calib->hiResUnipolarOffset = ue9_fp64_to_double (buf + 8);
/* Block 4 */
if (ue9_memory_read (fd, 4, buf, 128) < 0)
return -1;
calib->hiResBipolarSlope = ue9_fp64_to_double (buf + 0);
calib->hiResBipolarOffset = ue9_fp64_to_double (buf + 8);
/* All done */
return 1;
}
/* Retrieve comm config, returns -1 on error */
int ue9_get_comm_config(int fd, struct ue9CommConfig *config)
int
ue9_get_comm_config (int fd, struct ue9CommConfig *config)
{
uint8_t sendbuf[18];
uint8_t recvbuf[24];
memset(sendbuf, 0, sizeof(sendbuf));
memset(config, 0, sizeof(struct ue9CommConfig));
sendbuf[1] = 0xf8;
sendbuf[2] = 0x09;
sendbuf[3] = 0x08;
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
verb("command failed\n");
return -1;
}
verb("todo\n");
return -1;
uint8_t sendbuf[18];
uint8_t recvbuf[24];
memset (sendbuf, 0, sizeof (sendbuf));
memset (config, 0, sizeof (struct ue9CommConfig));
sendbuf[1] = 0xf8;
sendbuf[2] = 0x09;
sendbuf[3] = 0x08;
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n");
return -1;
}
verb ("todo\n");
return -1;
}
/* Retrieve control config, returns -1 on error */
int ue9_get_control_config(int fd, struct ue9ControlConfig *config)
int
ue9_get_control_config (int fd, struct ue9ControlConfig *config)
{
uint8_t sendbuf[18];
uint8_t recvbuf[24];
memset(sendbuf, 0, sizeof(sendbuf));
memset(config, 0, sizeof(struct ue9ControlConfig));
sendbuf[1] = 0xf8;
sendbuf[2] = 0x06;
sendbuf[3] = 0x08;
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
verb("command failed\n");
return -1;
}
verb("todo\n");
return -1;
uint8_t sendbuf[18];
uint8_t recvbuf[24];
memset (sendbuf, 0, sizeof (sendbuf));
memset (config, 0, sizeof (struct ue9ControlConfig));
sendbuf[1] = 0xf8;
sendbuf[2] = 0x06;
sendbuf[3] = 0x08;
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n");
return -1;
}
verb ("todo\n");
return -1;
}
/* Open TCP/IP connection to the UE9 */
int ue9_open(const char *host, int port)
int
ue9_open (const char *host, int port)
{
int fd;
struct sockaddr_in address;
struct hostent *he;
int window_size = 128 * 1024;
net_init();
/* Create socket */
fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0) {
verb("socket returned %d\n", fd);
return -1;
}
/* Set nonblocking */
if (soblock(fd, 0) < 0) {
verb("can't set nonblocking\n");
return -1;
}
/* Set initial window size hint to workaround LabJack firmware bug */
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *)&window_size,
sizeof(window_size));
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&window_size,
sizeof(window_size));
/* Resolve host */
address.sin_family = AF_INET;
address.sin_port = htons(port);
he = gethostbyname(host);
if (he == NULL) {
verb("gethostbyname(\"%s\") failed\n", host);
return -1;
}
address.sin_addr = *((struct in_addr *) he->h_addr);
debug("Resolved %s -> %s\n", host, inet_ntoa(address.sin_addr));
/* Connect */
if (connect_timeout(fd, (struct sockaddr *) &address, sizeof(address),
& (struct timeval) { .tv_sec = UE9_TIMEOUT }) < 0) {
verb("connection to %s:%d failed: %s\n",
inet_ntoa(address.sin_addr), port, compat_strerror(errno));
return -1;
}
return fd;
int fd;
struct sockaddr_in address;
struct hostent *he;
int window_size = 128 * 1024;
net_init ();
/* Create socket */
fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0)
{
verb ("socket returned %d\n", fd);
return -1;
}
/* Set nonblocking */
if (soblock (fd, 0) < 0)
{
verb ("can't set nonblocking\n");
return -1;
}
/* Set initial window size hint to workaround LabJack firmware bug */
setsockopt (fd, SOL_SOCKET, SO_SNDBUF, (void *) &window_size,
sizeof (window_size));
setsockopt (fd, SOL_SOCKET, SO_RCVBUF, (void *) &window_size,
sizeof (window_size));
/* Resolve host */
address.sin_family = AF_INET;
address.sin_port = htons (port);
he = gethostbyname (host);
if (he == NULL)
{
verb ("gethostbyname(\"%s\") failed\n", host);
return -1;
}
address.sin_addr = *((struct in_addr *) he->h_addr);
debug ("Resolved %s -> %s\n", host, inet_ntoa (address.sin_addr));
/* Connect */
if (connect_timeout (fd, (struct sockaddr *) &address, sizeof (address),
&(struct timeval)
{
.tv_sec = UE9_TIMEOUT}) < 0)
{
verb ("connection to %s:%d failed: %s\n",
inet_ntoa (address.sin_addr), port, compat_strerror (errno));
return -1;
}
return fd;
}
/* Close connection to the UE9 */
void ue9_close(int fd)
void
ue9_close (int fd)
{
/* does anyone actually call shutdown these days? */
shutdown(fd, 2 /* SHUT_RDWR */);
close(fd);
/* does anyone actually call shutdown these days? */
shutdown (fd, 2 /* SHUT_RDWR */ );
close (fd);
}
/* Compute scanrate based on the provided values. */
double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval)
double
ue9_compute_rate (uint8_t scanconfig, uint16_t scaninterval)
{
double clock;
/* A "scan" is across all channels. Each scan is triggered at
a fixed rate, and not affected by the number of channels.
Channels are scanned as quickly as possible. */
switch ((scanconfig >> 3) & 3) {
case 0: clock = 4e6; break;
case 1: clock = 48e6; break;
case 2: clock = 750e3; break;
case 3: clock = 24e6; break;
}
if (scanconfig & 0x2)
clock /= 256;
if (scaninterval == 0)
return 0;
return clock / scaninterval;
double clock;
/* A "scan" is across all channels. Each scan is triggered at
a fixed rate, and not affected by the number of channels.
Channels are scanned as quickly as possible. */
switch ((scanconfig >> 3) & 3)
{
case 0:
clock = 4e6;
break;
case 1:
clock = 48e6;
break;
case 2:
clock = 750e3;
break;
case 3:
clock = 24e6;
break;
}
if (scanconfig & 0x2)
clock /= 256;
if (scaninterval == 0)
return 0;
return clock / scaninterval;
}
/* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns -1 if no valid config found */
int ue9_choose_scan(double desired_rate, double *actual_rate,
uint8_t *scanconfig, uint16_t *scaninterval)
int
ue9_choose_scan (double desired_rate, double *actual_rate,
uint8_t * scanconfig, uint16_t * scaninterval)
{
int i;
struct { double clock; uint8_t config; } valid[] = {
{ 48e6, 0x08 },
{ 24e6, 0x18 },
{ 4e6, 0x00 },
{ 750e3, 0x10 },
{ 48e6 / 256, 0x0a },
{ 24e6 / 256, 0x1a },
{ 4e6 / 256, 0x02 },
{ 750e3 / 256, 0x12 },
{ 0, 0 } };
/* Start with the fastest clock frequency. If the
scaninterval would be too large, knock it down until it
fits. */
for (i = 0; valid[i].clock != 0; i++) {
double interval = valid[i].clock / desired_rate;
debug("Considering clock %lf (interval %lf)\n",
valid[i].clock, interval);
if (interval >= 0.5 && interval < 65535.5) {
*scaninterval = floor(interval + 0.5);
*scanconfig = valid[i].config;
*actual_rate = ue9_compute_rate(
*scanconfig, *scaninterval);
debug("Config 0x%02x, desired %lf, actual %lf\n",
*scanconfig, desired_rate, *actual_rate);
return 0;
}
int i;
struct
{
double clock;
uint8_t config;
} valid[] =
{
{
48e6, 0x08},
{
24e6, 0x18},
{
4e6, 0x00},
{
750e3, 0x10},
{
48e6 / 256, 0x0a},
{
24e6 / 256, 0x1a},
{
4e6 / 256, 0x02},
{
750e3 / 256, 0x12},
{
0, 0}};
/* Start with the fastest clock frequency. If the
scaninterval would be too large, knock it down until it
fits. */
for (i = 0; valid[i].clock != 0; i++)
{
double interval = valid[i].clock / desired_rate;
debug ("Considering clock %lf (interval %lf)\n",
valid[i].clock, interval);
if (interval >= 0.5 && interval < 65535.5)
{
*scaninterval = floor (interval + 0.5);
*scanconfig = valid[i].config;
*actual_rate = ue9_compute_rate (*scanconfig, *scaninterval);
debug ("Config 0x%02x, desired %lf, actual %lf\n",
*scanconfig, desired_rate, *actual_rate);
return 0;
}
}
return -1;
return -1;
}
/* Flush data buffers */
void ue9_buffer_flush(int fd)
void
ue9_buffer_flush (int fd)
{
uint8_t sendbuf[2], recvbuf[2];
sendbuf[1] = 0x08; /* FlushBuffer */
uint8_t sendbuf[2], recvbuf[2];
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
verb("command failed\n");
}
sendbuf[1] = 0x08; /* FlushBuffer */
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n");
}
}
/* Stop stream. Returns < 0 on failure. */
int ue9_stream_stop(int fd)
int
ue9_stream_stop (int fd)
{
uint8_t sendbuf[2], recvbuf[4];
sendbuf[1] = 0xB0;
uint8_t sendbuf[2], recvbuf[4];
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
verb("command failed\n");
return -1;
}
if (recvbuf[2] == STREAM_NOT_RUNNING || recvbuf[2] == 0)
return 0;
sendbuf[1] = 0xB0;
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n");
return -1;
}
debug("error %s\n", ue9_error(recvbuf[2]));
return -recvbuf[2];
if (recvbuf[2] == STREAM_NOT_RUNNING || recvbuf[2] == 0)
return 0;
debug ("error %s\n", ue9_error (recvbuf[2]));
return -recvbuf[2];
}
/* Start stream. Returns < 0 on failure. */
int ue9_stream_start(int fd)
int
ue9_stream_start (int fd)
{
uint8_t sendbuf[2], recvbuf[4];
sendbuf[1] = 0xA8;
uint8_t sendbuf[2], recvbuf[4];
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
verb("command failed\n");
return -1;
}
if (recvbuf[2] == 0)
return 0;
sendbuf[1] = 0xA8;
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n");
return -1;
}
debug("error %s\n", ue9_error(recvbuf[2]));
return -recvbuf[2];
if (recvbuf[2] == 0)
return 0;
debug ("error %s\n", ue9_error (recvbuf[2]));
return -recvbuf[2];
}
/* "Simple" stream configuration, assumes the channels are all
configured with the same gain. */
int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
uint8_t scanconfig, uint16_t scaninterval,
uint8_t gain)
int
ue9_streamconfig_simple (int fd, int *channel_list, int channel_count,
uint8_t scanconfig, uint16_t scaninterval,
uint8_t gain)
{
int i;
uint8_t buf[256];
/* Set up StreamConfig command with channels and scan options */
buf[1] = 0xF8; /* Extended command */
buf[2] = channel_count + 3; /* Command data words */
buf[3] = 0x11; /* StreamConfig */
buf[6] = channel_count; /* Number of channels */
buf[7] = 12; /* Bit resolution */
buf[8] = 0; /* Extra settling time */
buf[9] = scanconfig;
buf[10] = scaninterval & 0xff;
buf[11] = scaninterval >> 8;
for (i = 0; i < channel_count; i++)
{
buf[12 + 2 * i] = channel_list[i]; /* Channel number */
buf[13 + 2 * i] = gain; /* Gain/bipolar setup */
}
/* Send StreamConfig */
if (ue9_command (fd, buf, buf, 8) < 0)
{
debug ("command failed\n");
return -1;
}
if (buf[6] != 0)
{
verb ("returned error %s\n", ue9_error (buf[6]));
return -1;
}
return 0;
}
/* Stream data and pass it to the data callback. If callback returns
negative, stops reading and returns 0. Returns < 0 on error. */
int
ue9_stream_data (int fd, int channels,
ue9_stream_cb_t callback, void *context)
{
int i;
uint8_t buf[256];
/* Set up StreamConfig command with channels and scan options */
buf[1] = 0xF8; /* Extended command */
buf[2] = channel_count + 3; /* Command data words */
buf[3] = 0x11; /* StreamConfig */
buf[6] = channel_count; /* Number of channels */
buf[7] = 12; /* Bit resolution */
buf[8] = 0; /* Extra settling time */
buf[9] = scanconfig;
buf[10] = scaninterval & 0xff;
buf[11] = scaninterval >> 8;
for (i = 0; i < channel_count; i++) {
buf[12 + 2*i] = channel_list[i]; /* Channel number */
buf[13 + 2*i] = gain; /* Gain/bipolar setup */
int ret;
uint8_t buf[46];
uint8_t packet = 0;
int channel = 0;
int i;
uint16_t data[channels];
for (;;)
{
/* Receive data */
ret = recv_all_timeout (fd, buf, 46, 0, &(struct timeval)
{
.tv_sec = UE9_TIMEOUT});
/* Verify packet format */
if (ret != 46)
{
verb ("short recv %d\n", (int) ret);
return -1;
}
/* Send StreamConfig */
if (ue9_command(fd, buf, buf, 8) < 0) {
debug("command failed\n");
return -1;
if (!ue9_verify_extended (buf, 46) || !ue9_verify_normal (buf, 6))
{
verb ("bad checksum\n");
return -2;
}
if (buf[6] != 0) {
verb("returned error %s\n", ue9_error(buf[6]));
return -1;
if (buf[1] != 0xF9 || buf[2] != 0x14 || buf[3] != 0xC0)
{
verb ("bad command bytes\n");
return -3;
}
return 0;
}
if (buf[11] != 0)
{
verb ("stream error: %s\n", ue9_error (buf[11]));
return -4;
}
/* Stream data and pass it to the data callback. If callback returns
negative, stops reading and returns 0. Returns < 0 on error. */
int ue9_stream_data(int fd, int channels,
ue9_stream_cb_t callback, void *context)
{
int ret;
uint8_t buf[46];
uint8_t packet = 0;
int channel = 0;
int i;
uint16_t data[channels];
for (;;) {
/* Receive data */
ret = recv_all_timeout(fd, buf, 46, 0, & (struct timeval)
{ .tv_sec = UE9_TIMEOUT });
/* Verify packet format */
if (ret != 46) {
verb("short recv %d\n", (int)ret);
return -1;
}
if (!ue9_verify_extended(buf, 46) ||
!ue9_verify_normal(buf, 6)) {
verb("bad checksum\n");
return -2;
}
if (buf[1] != 0xF9 || buf[2] != 0x14 || buf[3] != 0xC0) {
verb("bad command bytes\n");
return -3;
}
if (buf[11] != 0) {
verb("stream error: %s\n", ue9_error(buf[11]));
return -4;
}
/* Check for dropped packets. */
if (buf[10] != packet) {
verb("expected packet %d, but received packet %d\n",
packet, buf[10]);
return -5;
}
packet++;
/* Check comm processor backlog (up to 512 kB) */
if (buf[45] & 0x80) {
verb("buffer overflow in CommBacklog, aborting\n");
return -6;
}
if ((buf[45] & 0x7f) > 112)
debug("warning: CommBacklog is high (%d bytes)\n",
(buf[45] & 0x7f) * 4096);
/* Check control processor backlog (up to 256 bytes). */
if (buf[44] == 255) {
verb("ControlBacklog is maxed out, aborting\n");
return -7;
}
if (buf[44] > 224)
debug("warning: ControlBacklog is high (%d bytes)\n",
buf[44]);
/* Read samples from the buffer */
for (i = 12; i <= 42; i += 2) {
data[channel++] = buf[i] + (buf[i+1] << 8);
if (channel < channels)
continue;
/* Received a full scan, send to callback */
channel = 0;
if ((*callback)(channels, data, context) < 0) {
/* We're done */
return 0;
}
}
/* Check for dropped packets. */
if (buf[10] != packet)
{
verb ("expected packet %d, but received packet %d\n",
packet, buf[10]);
return -5;
}
packet++;
/* Check comm processor backlog (up to 512 kB) */
if (buf[45] & 0x80)
{
verb ("buffer overflow in CommBacklog, aborting\n");
return -6;
}
if ((buf[45] & 0x7f) > 112)
debug ("warning: CommBacklog is high (%d bytes)\n",
(buf[45] & 0x7f) * 4096);
/* Check control processor backlog (up to 256 bytes). */
if (buf[44] == 255)
{
verb ("ControlBacklog is maxed out, aborting\n");
return -7;
}
if (buf[44] > 224)
debug ("warning: ControlBacklog is high (%d bytes)\n", buf[44]);
/* Read samples from the buffer */
for (i = 12; i <= 42; i += 2)
{
data[channel++] = buf[i] + (buf[i + 1] << 8);
if (channel < channels)
continue;
/* Received a full scan, send to callback */
channel = 0;
if ((*callback) (channels, data, context) < 0)
{
/* We're done */
return 0;
}
}
}
}
......@@ -16,56 +16,59 @@
#include "netutil.h"
/* Calibration data */
struct ue9Calibration {
double unipolarSlope[4];
double unipolarOffset[4];
double bipolarSlope;
double bipolarOffset;
double DACSlope[2];
double DACOffset[2];
double tempSlope;
double tempSlopeLow;
double calTemp;
double Vref;
double VrefDiv2;
double VsSlope;
double hiResUnipolarSlope;
double hiResUnipolarOffset;
double hiResBipolarSlope;
double hiResBipolarOffset;
struct ue9Calibration
{
double unipolarSlope[4];
double unipolarOffset[4];
double bipolarSlope;
double bipolarOffset;
double DACSlope[2];
double DACOffset[2];
double tempSlope;
double tempSlopeLow;
double calTemp;
double Vref;
double VrefDiv2;
double VsSlope;
double hiResUnipolarSlope;
double hiResUnipolarOffset;
double hiResBipolarSlope;
double hiResBipolarOffset;
};
/* Comm config */
struct ue9CommConfig {
uint8_t local_id;
uint8_t power_level;
in_addr_t address;
in_addr_t gateway;
in_addr_t subnet;
in_port_t portA;
in_port_t portB;
uint8_t dhcp_enabled;
uint8_t product_id;
uint8_t mac_address[6];
double hw_version;
double comm_fw_version;
struct ue9CommConfig
{
uint8_t local_id;
uint8_t power_level;
in_addr_t address;
in_addr_t gateway;
in_addr_t subnet;
in_port_t portA;
in_port_t portB;
uint8_t dhcp_enabled;
uint8_t product_id;
uint8_t mac_address[6];
double hw_version;
double comm_fw_version;
};
/* Control config */
struct ue9ControlConfig {
uint8_t power_level;
uint8_t reset_source;
double control_fw_version;
double control_bl_version;
uint8_t hires;
uint8_t fio_dir;
uint8_t fio_state;
uint8_t eio_dir;
uint8_t eio_state;
uint8_t cio_dirstate;;
uint8_t mio_dirstate;
uint16_t dac0;
uint16_t dac1;
struct ue9ControlConfig
{
uint8_t power_level;
uint8_t reset_source;
double control_fw_version;
double control_bl_version;
uint8_t hires;
uint8_t fio_dir;
uint8_t fio_state;
uint8_t eio_dir;
uint8_t eio_state;
uint8_t cio_dirstate;;
uint8_t mio_dirstate;
uint16_t dac0;
uint16_t dac1;
};
#define UE9_UNIPOLAR_GAIN1 0x00
......@@ -77,65 +80,65 @@ struct ue9ControlConfig {
#define UE9_CHANNELS 14
/* Fill checksums in data buffers */
void ue9_checksum_normal(uint8_t *buffer, size_t len);
void ue9_checksum_extended(uint8_t *buffer, size_t len);
void ue9_checksum_normal (uint8_t * buffer, size_t len);
void ue9_checksum_extended (uint8_t * buffer, size_t len);
/* Verify checksums in data buffers. Returns 0 on error. */
int ue9_verify_normal(uint8_t *buffer, size_t len);
int ue9_verify_extended(uint8_t *buffer, size_t len);
int ue9_verify_normal (uint8_t * buffer, size_t len);
int ue9_verify_extended (uint8_t * buffer, size_t len);
/* Open/close TCP/IP connection to the UE9 */
int ue9_open(const char *host, int port);
void ue9_close(int fd);
int ue9_open (const char *host, int port);
void ue9_close (int fd);
/* Read a memory block from the device. Returns -1 on error. */
int ue9_memory_read(int fd, int blocknum, uint8_t *buffer, int len);
int ue9_memory_read (int fd, int blocknum, uint8_t * buffer, int len);
/* Convert 64-bit fixed point to double type */
double ue9_fp64_to_double(uint8_t *data);
double ue9_fp64_to_double (uint8_t * data);
/* Retrieve calibration data or configuration from the device */
int ue9_get_calibration(int fd, struct ue9Calibration *calib);
int ue9_get_comm_config(int fd, struct ue9CommConfig *config);
int ue9_get_control_config(int fd, struct ue9ControlConfig *config);
int ue9_get_calibration (int fd, struct ue9Calibration *calib);
int ue9_get_comm_config (int fd, struct ue9CommConfig *config);
int ue9_get_control_config (int fd, struct ue9ControlConfig *config);
/* Data conversion. If calib is NULL, use uncalibrated conversions. */
double ue9_binary_to_analog(struct ue9Calibration *calib,
uint8_t gain, uint8_t resolution, uint16_t data);
double ue9_binary_to_analog (struct ue9Calibration *calib,
uint8_t gain, uint8_t resolution, uint16_t data);
/* Compute scanrate based on the provided values. */
double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval);
double ue9_compute_rate (uint8_t scanconfig, uint16_t scaninterval);
/* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns 0 if nothing can be chosen. */
int ue9_choose_scan(double desired_rate, double *actual_rate,
uint8_t *scanconfig, uint16_t *scaninterval);
int ue9_choose_scan (double desired_rate, double *actual_rate,
uint8_t * scanconfig, uint16_t * scaninterval);
/* Flush data buffers */
void ue9_buffer_flush(int fd);
void ue9_buffer_flush (int fd);
/* Stop stream. Returns < 0 on failure. */
int ue9_stream_stop(int fd);
int ue9_stream_stop (int fd);
/* Start stream. Returns < 0 on failure. */
int ue9_stream_start(int fd);
int ue9_stream_start (int fd);
/* Execute a command on the UE9. Returns -1 on error. Fills the
checksums on the outgoing packets, and verifies them on the
incoming packets. Data in "out" is transmitted, data in "in" is
received. */
int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen);
int ue9_command (int fd, uint8_t * out, uint8_t * in, int inlen);
/* "Simple" stream configuration, assumes the channels are all
configured with the same gain. */
int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
uint8_t scanconfig, uint16_t scaninterval,
uint8_t gain);
int ue9_streamconfig_simple (int fd, int *channel_list, int channel_count,
uint8_t scanconfig, uint16_t scaninterval,
uint8_t gain);
/* Stream data and pass it to the data callback. If callback returns
negative, stops reading and returns 0. Returns < 0 on error. */
typedef int (*ue9_stream_cb_t)(int channels, uint16_t *data, void *context);
int ue9_stream_data(int fd, int channels,
ue9_stream_cb_t callback, void *context);
typedef int (*ue9_stream_cb_t) (int channels, uint16_t * data, void *context);
int ue9_stream_data (int fd, int channels,
ue9_stream_cb_t callback, void *context);
#endif
#include "ue9error.h"
const char *ue9_error_text[] = {
[0] = "(no error)",
[SCRATCH_WRT_FAIL] = "SCRATCH_WRT_FAIL",
[SCRATCH_ERASE_FAIL] = "SCRATCH_ERASE_FAIL",
[DATA_BUFFER_OVERFLOW] = "DATA_BUFFER_OVERFLOW",
[ADC0_BUFFER_OVERFLOW] = "ADC0_BUFFER_OVERFLOW",
[FUNCTION_INVALID] = "FUNCTION_INVALID",
[SWDT_TIME_INVALID] = "SWDT_TIME_INVALID",
[FLASH_WRITE_FAIL] = "FLASH_WRITE_FAIL",
[FLASH_ERASE_FAIL] = "FLASH_ERASE_FAIL",
[FLASH_JMP_FAIL] = "FLASH_JMP_FAIL",
[FLASH_PSP_TIMEOUT] = "FLASH_PSP_TIMEOUT",
[FLASH_ABORT_RECEIVED] = "FLASH_ABORT_RECEIVED",
[FLASH_PAGE_MISMATCH] = "FLASH_PAGE_MISMATCH",
[FLASH_BLOCK_MISMATCH] = "FLASH_BLOCK_MISMATCH",
[FLASH_PAGE_NOT_IN_CODE_AREA] = "FLASH_PAGE_NOT_IN_CODE_AREA",
[MEM_ILLEGAL_ADDRESS] = "MEM_ILLEGAL_ADDRESS",
[FLASH_LOCKED] = "FLASH_LOCKED",
[INVALID_BLOCK] = "INVALID_BLOCK",
[FLASH_ILLEGAL_PAGE] = "FLASH_ILLEGAL_PAGE",
[STREAM_IS_ACTIVE] = "STREAM_IS_ACTIVE",
[STREAM_TABLE_INVALID] = "STREAM_TABLE_INVALID",
[STREAM_CONFIG_INVALID] = "STREAM_CONFIG_INVALID",
[STREAM_BAD_TRIGGER_SOURCE] = "STREAM_BAD_TRIGGER_SOURCE",
[STREAM_NOT_RUNNING] = "STREAM_NOT_RUNNING",
[STREAM_INVALID_TRIGGER] = "STREAM_INVALID_TRIGGER",
[STREAM_CONTROL_BUFFER_OVERFLOW] = "STREAM_CONTROL_BUFFER_OVERFLOW",
[STREAM_SCAN_OVERLAP] = "STREAM_SCAN_OVERLAP",
[STREAM_SAMPLE_NUM_INVALID] = "STREAM_SAMPLE_NUM_INVALID",
[STREAM_BIPOLAR_GAIN_INVALID] = "STREAM_BIPOLAR_GAIN_INVALID",
[STREAM_SCAN_RATE_INVALID] = "STREAM_SCAN_RATE_INVALID",
[TIMER_INVALID_MODE] = "TIMER_INVALID_MODE",
[TIMER_QUADRATURE_AB_ERROR] = "TIMER_QUADRATURE_AB_ERROR",
[TIMER_QUAD_PULSE_SEQUENCE] = "TIMER_QUAD_PULSE_SEQUENCE",
[TIMER_BAD_CLOCK_SOURCE] = "TIMER_BAD_CLOCK_SOURCE",
[TIMER_STREAM_ACTIVE] = "TIMER_STREAM_ACTIVE",
[TIMER_PWMSTOP_MODULE_ERROR] = "TIMER_PWMSTOP_MODULE_ERROR",
[EXT_OSC_NOT_STABLE] = "EXT_OSC_NOT_STABLE",
[INVALID_POWER_SETTING] = "INVALID_POWER_SETTING",
[PLL_NOT_LOCKED] = "PLL_NOT_LOCKED"
[0] = "(no error)",
[SCRATCH_WRT_FAIL] = "SCRATCH_WRT_FAIL",
[SCRATCH_ERASE_FAIL] = "SCRATCH_ERASE_FAIL",
[DATA_BUFFER_OVERFLOW] = "DATA_BUFFER_OVERFLOW",
[ADC0_BUFFER_OVERFLOW] = "ADC0_BUFFER_OVERFLOW",
[FUNCTION_INVALID] = "FUNCTION_INVALID",
[SWDT_TIME_INVALID] = "SWDT_TIME_INVALID",
[FLASH_WRITE_FAIL] = "FLASH_WRITE_FAIL",
[FLASH_ERASE_FAIL] = "FLASH_ERASE_FAIL",
[FLASH_JMP_FAIL] = "FLASH_JMP_FAIL",
[FLASH_PSP_TIMEOUT] = "FLASH_PSP_TIMEOUT",
[FLASH_ABORT_RECEIVED] = "FLASH_ABORT_RECEIVED",
[FLASH_PAGE_MISMATCH] = "FLASH_PAGE_MISMATCH",
[FLASH_BLOCK_MISMATCH] = "FLASH_BLOCK_MISMATCH",
[FLASH_PAGE_NOT_IN_CODE_AREA] = "FLASH_PAGE_NOT_IN_CODE_AREA",
[MEM_ILLEGAL_ADDRESS] = "MEM_ILLEGAL_ADDRESS",
[FLASH_LOCKED] = "FLASH_LOCKED",
[INVALID_BLOCK] = "INVALID_BLOCK",
[FLASH_ILLEGAL_PAGE] = "FLASH_ILLEGAL_PAGE",
[STREAM_IS_ACTIVE] = "STREAM_IS_ACTIVE",
[STREAM_TABLE_INVALID] = "STREAM_TABLE_INVALID",
[STREAM_CONFIG_INVALID] = "STREAM_CONFIG_INVALID",
[STREAM_BAD_TRIGGER_SOURCE] = "STREAM_BAD_TRIGGER_SOURCE",
[STREAM_NOT_RUNNING] = "STREAM_NOT_RUNNING",
[STREAM_INVALID_TRIGGER] = "STREAM_INVALID_TRIGGER",
[STREAM_CONTROL_BUFFER_OVERFLOW] = "STREAM_CONTROL_BUFFER_OVERFLOW",
[STREAM_SCAN_OVERLAP] = "STREAM_SCAN_OVERLAP",
[STREAM_SAMPLE_NUM_INVALID] = "STREAM_SAMPLE_NUM_INVALID",
[STREAM_BIPOLAR_GAIN_INVALID] = "STREAM_BIPOLAR_GAIN_INVALID",
[STREAM_SCAN_RATE_INVALID] = "STREAM_SCAN_RATE_INVALID",
[TIMER_INVALID_MODE] = "TIMER_INVALID_MODE",
[TIMER_QUADRATURE_AB_ERROR] = "TIMER_QUADRATURE_AB_ERROR",
[TIMER_QUAD_PULSE_SEQUENCE] = "TIMER_QUAD_PULSE_SEQUENCE",
[TIMER_BAD_CLOCK_SOURCE] = "TIMER_BAD_CLOCK_SOURCE",
[TIMER_STREAM_ACTIVE] = "TIMER_STREAM_ACTIVE",
[TIMER_PWMSTOP_MODULE_ERROR] = "TIMER_PWMSTOP_MODULE_ERROR",
[EXT_OSC_NOT_STABLE] = "EXT_OSC_NOT_STABLE",
[INVALID_POWER_SETTING] = "INVALID_POWER_SETTING",
[PLL_NOT_LOCKED] = "PLL_NOT_LOCKED"
};
const char *ue9_error(int errorcode)
const char *
ue9_error (int errorcode)
{
if (errorcode > ARRAY_SIZE(ue9_error_text))
return "(invalid errorcode)";
else
return ue9_error_text[errorcode];
if (errorcode > ARRAY_SIZE (ue9_error_text))
return "(invalid errorcode)";
else
return ue9_error_text[errorcode];
}
......@@ -44,6 +44,6 @@
extern const char *ue9_error_text[];
const char *ue9_error(int errorcode);
const char *ue9_error (int errorcode);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment