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