Compare commits
35 Commits
ethstream-
...
ethstream-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ec1ae04a5b | ||
![]() |
67163dc1a2 | ||
![]() |
a29bf180ab | ||
![]() |
4cccb783f0 | ||
![]() |
5e7f4ac97e | ||
![]() |
a57c0c22c2 | ||
![]() |
2e3f2f4b23 | ||
![]() |
4592b6a75b | ||
![]() |
d1447e2af8 | ||
![]() |
b9130788f2 | ||
![]() |
ed150ead35 | ||
![]() |
519a0c2e29 | ||
![]() |
190fd3f3a7 | ||
![]() |
9c174d12b0 | ||
![]() |
b1e049eed0 | ||
![]() |
d461365275 | ||
![]() |
a4eede145b | ||
![]() |
6562c0b787 | ||
![]() |
7f79ec8ff3 | ||
![]() |
1dd09ea52d | ||
![]() |
ded6c7e5f4 | ||
![]() |
f2d6566051 | ||
![]() |
357e808986 | ||
![]() |
0ed2935deb | ||
![]() |
1a2ed51d0c | ||
![]() |
679b4ef64f | ||
![]() |
770a83b8f7 | ||
![]() |
627a1bf22b | ||
![]() |
43c8e19c67 | ||
![]() |
4aab606162 | ||
![]() |
c81d372d23 | ||
![]() |
407a91c764 | ||
![]() |
1d760e033b | ||
![]() |
57cfac2bec | ||
![]() |
5b731f3e7e |
2
Makefile
2
Makefile
@@ -21,7 +21,7 @@ BINPATH = ${PREFIX}/bin
|
||||
|
||||
WINCC = i386-mingw32-gcc
|
||||
WINCFLAGS += $(CFLAGS)
|
||||
WINLDFLAGS += $(LDFLAGS) -lws2_32 -s
|
||||
WINLDFLAGS += $(LDFLAGS) -lws2_32 -liphlpapi -s
|
||||
|
||||
# Targets
|
||||
|
||||
|
@@ -3,43 +3,70 @@
|
||||
#include "compat.h"
|
||||
#include <windows.h>
|
||||
|
||||
unsigned int sleep(unsigned int seconds)
|
||||
unsigned int
|
||||
sleep (unsigned int seconds)
|
||||
{
|
||||
Sleep(seconds * 1000);
|
||||
Sleep (seconds * 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct {
|
||||
static struct
|
||||
{
|
||||
int num;
|
||||
char *msg;
|
||||
} win32_error[] = {
|
||||
} 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)
|
||||
{
|
||||
WSAEINTR, "Winsock: Interrupted system call"},
|
||||
{
|
||||
WSAEBADF, "Winsock: Bad file number"},
|
||||
{
|
||||
WSAEFAULT, "Winsock: Bad address"},
|
||||
{
|
||||
WSAEINVAL, "Winsock: Invalid argument"},
|
||||
{
|
||||
WSAEMFILE, "Winsock: Too many open files"},
|
||||
{
|
||||
WSAEWOULDBLOCK, "Winsock: Operation would block"},
|
||||
{
|
||||
WSAEINPROGRESS, "Winsock: Operation now in progress"},
|
||||
{
|
||||
WSAEALREADY, "Winsock: Operation already in progress"},
|
||||
{
|
||||
WSAENOTSOCK, "Winsock: Socket operation on nonsocket"},
|
||||
{
|
||||
WSAEADDRINUSE, "Winsock: Address already in use"},
|
||||
{
|
||||
WSAEADDRNOTAVAIL, "Winsock: Cannot assign requested address"},
|
||||
{
|
||||
WSAENETDOWN, "Winsock: Network is down"},
|
||||
{
|
||||
WSAENETUNREACH, "Winsock: Network is unreachable"},
|
||||
{
|
||||
WSAENETRESET, "Winsock: Network dropped connection on reset"},
|
||||
{
|
||||
WSAECONNABORTED, "Winsock: Software caused connection abort"},
|
||||
{
|
||||
WSAECONNRESET, "Winsock: Connection reset by peer"},
|
||||
{
|
||||
WSAETIMEDOUT, "Winsock: Connection timed out"},
|
||||
{
|
||||
WSAECONNREFUSED, "Winsock: Connection refused"},
|
||||
{
|
||||
WSAEHOSTDOWN, "Winsock: Host is down"},
|
||||
{
|
||||
WSAEHOSTUNREACH, "Winsock: No route to host"},
|
||||
{
|
||||
WSAVERNOTSUPPORTED, "Winsock: Unsupported Winsock version"},
|
||||
{
|
||||
ETIMEDOUT, "Connection timed out"},
|
||||
{
|
||||
ENOTCONN, "Not connected"},
|
||||
{
|
||||
-1, NULL},};
|
||||
char *
|
||||
compat_strerror (int errnum)
|
||||
{
|
||||
int i;
|
||||
static char buf[128];
|
||||
@@ -47,11 +74,12 @@ char *compat_strerror(int errnum)
|
||||
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);
|
||||
if (errnum >= 10000)
|
||||
{
|
||||
sprintf (buf, "Winsock: unknown error %d\n", errnum);
|
||||
return buf;
|
||||
}
|
||||
return strerror(errnum);
|
||||
return strerror (errnum);
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
@@ -80,4 +108,3 @@ char *compat_strerror(int errnum)
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
4
compat.h
4
compat.h
@@ -2,8 +2,8 @@
|
||||
#define COMPAT_H
|
||||
|
||||
#ifdef __WIN32__
|
||||
unsigned int sleep(unsigned int seconds);
|
||||
char *compat_strerror(int errnum);
|
||||
unsigned int sleep (unsigned int seconds);
|
||||
char *compat_strerror (int errnum);
|
||||
//const char *inet_ntop(int af, void *src, const char *dst, socklen_t cnt);
|
||||
#define INET_ADDRSTRLEN 16
|
||||
#define ETIMEDOUT 110
|
||||
|
12
debug.c
12
debug.c
@@ -4,15 +4,15 @@
|
||||
|
||||
int verb_count = 0;
|
||||
|
||||
int func_fprintf(const char *func, FILE *stream, const char *format, ...)
|
||||
int
|
||||
func_fprintf (const char *func, FILE * stream, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
fprintf(stream, "%s: ", func);
|
||||
va_start(ap, format);
|
||||
ret = vfprintf(stream, format, ap);
|
||||
va_end(ap);
|
||||
fprintf (stream, "%s: ", func);
|
||||
va_start (ap, format);
|
||||
ret = vfprintf (stream, format, ap);
|
||||
va_end (ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
2
debug.h
2
debug.h
@@ -14,7 +14,7 @@ extern int verb_count;
|
||||
|
||||
#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)));
|
||||
|
||||
#define debug(x...) ({ \
|
||||
|
635
ethstream.c
635
ethstream.c
@@ -29,65 +29,78 @@
|
||||
#include "opt.h"
|
||||
#include "version.h"
|
||||
#include "compat.h"
|
||||
#include "ethstream.h"
|
||||
|
||||
#define DEFAULT_HOST "192.168.1.209"
|
||||
#define UE9_COMMAND_PORT 52360
|
||||
#define UE9_DATA_PORT 52361
|
||||
|
||||
struct callbackInfo {
|
||||
|
||||
struct callbackInfo
|
||||
{
|
||||
struct ue9Calibration calib;
|
||||
int convert;
|
||||
int maxlines;
|
||||
};
|
||||
|
||||
struct options opt[] = {
|
||||
{ 'a', "address", "string", "host/address of UE9 (192.168.1.209)" },
|
||||
{ 'n', "numchannels", "n", "sample the first N ADC channels (2)" },
|
||||
{ 'N', "nerdjack", NULL, "Use NerdJack device instead" },
|
||||
{ 'd', "detect", NULL, "Detect NerdJack IP address" },
|
||||
{ 'p', "precision", "0-3", "Set precision on NerdJack (0 - max range, 1 - max precision)"},
|
||||
{ 'C', "channels", "a,b,c", "sample channels a, b, and c" },
|
||||
{ 'r', "rate", "hz", "sample each channel at this rate (8000.0)" },
|
||||
{ 'o', "oneshot", NULL, "don't retry in case of errors" },
|
||||
{ 'f', "forceretry", NULL, "retry no matter what happens" },
|
||||
{ 'c', "convert", NULL, "display output in volts" },
|
||||
{ 'l', "lines", "num", "if set, output this many lines and quit" },
|
||||
{ 'h', "help", NULL, "this help" },
|
||||
{ 'v', "verbose", NULL, "be verbose" },
|
||||
{ 'V', "version", NULL, "show version number and exit" },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
{'a', "address", "string", "host/address of device (192.168.1.209)"},
|
||||
{'n', "numchannels", "n", "sample the first N ADC channels (2)"},
|
||||
{'N', "nerdjack", NULL, "Force NerdJack device"},
|
||||
{'L', "labjack",NULL,"Force LabJack device"},
|
||||
{'d', "detect", NULL, "Detect NerdJack IP address"},
|
||||
{'R', "range", "a,b",
|
||||
"Set range on NerdJack for channels 0-5,6-11 to either 5 or 10 (10,10)"},
|
||||
{'C', "channels", "a,b,c", "sample channels a, b, and c"},
|
||||
{'r', "rate", "hz", "sample each channel at this rate (8000.0)"},
|
||||
{'o', "oneshot", NULL, "don't retry in case of errors"},
|
||||
{'f', "forceretry", NULL, "retry no matter what happens"},
|
||||
{'c', "convert", NULL, "convert output to volts"},
|
||||
{'H', "converthex", NULL, "convert output to hex"},
|
||||
{'m', "showmem", NULL, "output memory stats with data (NJ only)"},
|
||||
{'l', "lines", "num", "if set, output this many lines and quit"},
|
||||
{'h', "help", NULL, "this help"},
|
||||
{'v', "verbose", NULL, "be verbose"},
|
||||
{'V', "version", NULL, "show version number and exit"},
|
||||
{0, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
|
||||
int *channel_list, int channel_count, int convert, int maxlines);
|
||||
int nerdDoStream(const char *address, int *channel_list, int channel_count, int precision,
|
||||
unsigned short period, int convert, int lines);
|
||||
int data_callback(int channels, uint16_t *data, void *context);
|
||||
int doStream (const char *address, uint8_t scanconfig, uint16_t scaninterval,
|
||||
int *channel_list, int channel_count, int convert,
|
||||
int maxlines);
|
||||
int nerdDoStream (const char *address, int *channel_list, int channel_count,
|
||||
int precision, unsigned long period, int convert, int lines,
|
||||
int showmem);
|
||||
int data_callback (int channels, uint16_t * data, void *context);
|
||||
|
||||
int columns_left = 0;
|
||||
void handle_sig(int sig)
|
||||
void
|
||||
handle_sig (int sig)
|
||||
{
|
||||
while (columns_left--) {
|
||||
printf(" 0");
|
||||
while (columns_left--)
|
||||
{
|
||||
printf (" 0");
|
||||
}
|
||||
fflush(stdout);
|
||||
exit(0);
|
||||
fflush (stdout);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int optind;
|
||||
char *optarg, *endp;
|
||||
char c;
|
||||
int tmp, i;
|
||||
FILE *help = stderr;
|
||||
char *address = strdup(DEFAULT_HOST);
|
||||
char *address = strdup (DEFAULT_HOST);
|
||||
double desired_rate = 8000.0;
|
||||
int lines = 0;
|
||||
double actual_rate;
|
||||
int oneshot = 0;
|
||||
int forceretry = 0;
|
||||
int convert = 0;
|
||||
int convert = CONVERT_DEC;
|
||||
int showmem = 0;
|
||||
uint8_t scanconfig;
|
||||
uint16_t scaninterval;
|
||||
#if UE9_CHANNELS > NERDJACK_CHANNELS
|
||||
@@ -97,23 +110,30 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
int channel_count = 0;
|
||||
int nerdjack = 0;
|
||||
int labjack = 0;
|
||||
int detect = 0;
|
||||
int precision = 0;
|
||||
int period = NERDJACK_CLOCK_RATE / desired_rate;
|
||||
int addressSpecified = 0;
|
||||
int donerdjack = 0;
|
||||
unsigned long period = NERDJACK_CLOCK_RATE / desired_rate;
|
||||
|
||||
/* Parse arguments */
|
||||
opt_init(&optind);
|
||||
while ((c = opt_parse(argc, argv, &optind, &optarg, opt)) != 0) {
|
||||
switch (c) {
|
||||
opt_init (&optind);
|
||||
while ((c = opt_parse (argc, argv, &optind, &optarg, opt)) != 0)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
free(address);
|
||||
address = strdup(optarg);
|
||||
free (address);
|
||||
address = strdup (optarg);
|
||||
addressSpecified = 1;
|
||||
break;
|
||||
case 'n':
|
||||
channel_count = 0;
|
||||
tmp = strtol(optarg, &endp, 0);
|
||||
if (*endp || tmp < 1 || tmp > UE9_CHANNELS) {
|
||||
info("bad number of channels: %s\n", optarg);
|
||||
tmp = strtol (optarg, &endp, 0);
|
||||
if (*endp || tmp < 1 || tmp > UE9_CHANNELS)
|
||||
{
|
||||
info ("bad number of channels: %s\n", optarg);
|
||||
goto printhelp;
|
||||
}
|
||||
for (i = 0; i < tmp; i++)
|
||||
@@ -121,48 +141,84 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case 'C':
|
||||
channel_count = 0;
|
||||
do {
|
||||
tmp = strtol(optarg, &endp, 0);
|
||||
if (*endp != '\0' && *endp != ',') {
|
||||
//|| tmp < 0 || tmp >= UE9_CHANNELS) {
|
||||
info("bad channel number: %s\n", optarg);
|
||||
do
|
||||
{
|
||||
tmp = strtol (optarg, &endp, 0);
|
||||
if (*endp != '\0' && *endp != ',')
|
||||
{
|
||||
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
|
||||
//The rest of the sanity checking can come later after we know
|
||||
//whether this is a
|
||||
//LabJack or a NerdJack
|
||||
#if UE9_CHANNELS > NERDJACK_CHANNELS
|
||||
if (channel_count >= UE9_CHANNELS) {
|
||||
if (channel_count >= UE9_CHANNELS)
|
||||
{
|
||||
#else
|
||||
if (channel_count >= NERDJACK_CHANNELS) {
|
||||
if (channel_count >= NERDJACK_CHANNELS)
|
||||
{
|
||||
#endif
|
||||
info("error: too many channels specified\n");
|
||||
info ("error: too many channels specified\n");
|
||||
goto printhelp;
|
||||
}
|
||||
channel_list[channel_count++] = tmp;
|
||||
optarg = endp + 1;
|
||||
} while (*endp);
|
||||
}
|
||||
while (*endp);
|
||||
break;
|
||||
case 'r':
|
||||
desired_rate = strtod(optarg, &endp);
|
||||
if(*endp || desired_rate <= 0) {
|
||||
info("bad rate: %s\n", optarg);
|
||||
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);
|
||||
lines = strtol (optarg, &endp, 0);
|
||||
if (*endp || lines <= 0)
|
||||
{
|
||||
info ("bad number of lines: %s\n", optarg);
|
||||
goto printhelp;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
precision++;
|
||||
case 'R':
|
||||
tmp = strtol (optarg, &endp, 0);
|
||||
if (*endp != ',')
|
||||
{
|
||||
info ("bad range number: %s\n", optarg);
|
||||
goto printhelp;
|
||||
}
|
||||
if(tmp != 5 && tmp != 10) {
|
||||
info("valid choices for range are 5 or 10\n");
|
||||
goto printhelp;
|
||||
}
|
||||
if(tmp == 5) precision = precision + 1;
|
||||
|
||||
optarg = endp + 1;
|
||||
if (*endp == '\0') {
|
||||
info("Range needs two numbers, one for channels 0-5 and another for 6-11\n");
|
||||
goto printhelp;
|
||||
}
|
||||
tmp = strtol (optarg, &endp, 0);
|
||||
if (*endp != '\0') {
|
||||
info("Range needs only two numbers, one for channels 0-5 and another for 6-11\n");
|
||||
goto printhelp;
|
||||
}
|
||||
if(tmp != 5 && tmp != 10) {
|
||||
info("valid choices for range are 5 or 10\n");
|
||||
goto printhelp;
|
||||
}
|
||||
if(tmp == 5) precision = precision + 2;
|
||||
break;
|
||||
case 'N':
|
||||
nerdjack++;
|
||||
break;
|
||||
case 'L':
|
||||
labjack++;
|
||||
break;
|
||||
case 'd':
|
||||
detect++;
|
||||
break;
|
||||
@@ -173,15 +229,31 @@ int main(int argc, char *argv[])
|
||||
forceretry++;
|
||||
break;
|
||||
case 'c':
|
||||
convert++;
|
||||
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 "
|
||||
printf ("etherstream " VERSION "\n");
|
||||
printf ("Written by Jim Paris <jim@jtan.com>\n");
|
||||
printf ("and Zachary Clifford <zacharyc@mit.edu>\n");
|
||||
printf ("This program comes with no warranty and is "
|
||||
"provided under the GPLv2.\n");
|
||||
return 0;
|
||||
break;
|
||||
@@ -189,33 +261,76 @@ int main(int argc, char *argv[])
|
||||
help = stdout;
|
||||
default:
|
||||
printhelp:
|
||||
fprintf(help, "Usage: %s [options]\n", *argv);
|
||||
opt_help(opt, help);
|
||||
fprintf(help, "Read data from the specified Labjack UE9"
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (nerdjack) {
|
||||
if (channel_count > NERDJACK_CHANNELS) {
|
||||
info("Too many channels for NerdJack\n");
|
||||
if (detect && labjack) {
|
||||
info("The LabJack does not support autodetection\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]);
|
||||
|
||||
if (detect && !nerdjack) {
|
||||
info("Only the NerdJack supports autodetection - assuming -N option\n");
|
||||
nerdjack = 1;
|
||||
}
|
||||
|
||||
if (detect && addressSpecified) {
|
||||
info("Autodetection and specifying address are mutually exclusive\n");
|
||||
goto printhelp;
|
||||
}
|
||||
|
||||
if (nerdjack && labjack) {
|
||||
info("Nerdjack and Labjack options are mutually exclusive\n");
|
||||
goto printhelp;
|
||||
}
|
||||
|
||||
donerdjack = nerdjack;
|
||||
|
||||
//First if no options were supplied try the Nerdjack
|
||||
//The second time through, donerdjack will be true and this will not fire
|
||||
if (!nerdjack && !labjack) {
|
||||
info("No device specified...Defaulting to Nerdjack\n");
|
||||
donerdjack = 1;
|
||||
}
|
||||
|
||||
doneparse:
|
||||
|
||||
|
||||
|
||||
if (donerdjack)
|
||||
{
|
||||
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");
|
||||
}
|
||||
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]);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -223,78 +338,100 @@ int main(int argc, char *argv[])
|
||||
|
||||
|
||||
|
||||
if (optind < argc) {
|
||||
info("error: too many arguments (%s)\n\n", argv[optind]);
|
||||
if (optind < argc)
|
||||
{
|
||||
info ("error: too many arguments (%s)\n\n", argv[optind]);
|
||||
goto printhelp;
|
||||
}
|
||||
|
||||
if (forceretry && oneshot) {
|
||||
info("forceretry and oneshot options are mutually exclusive\n");
|
||||
if (forceretry && oneshot)
|
||||
{
|
||||
info ("forceretry and oneshot options are mutually exclusive\n");
|
||||
goto printhelp;
|
||||
}
|
||||
|
||||
/* Two channels if none specified */
|
||||
if (channel_count == 0) {
|
||||
if (channel_count == 0)
|
||||
{
|
||||
channel_list[channel_count++] = 0;
|
||||
channel_list[channel_count++] = 1;
|
||||
}
|
||||
|
||||
if (verb_count) {
|
||||
info("Scanning channels:");
|
||||
if (verb_count)
|
||||
{
|
||||
info ("Scanning channels:");
|
||||
for (i = 0; i < channel_count; i++)
|
||||
info(" AIN%d", channel_list[i]);
|
||||
info("\n");
|
||||
info (" AIN%d", channel_list[i]);
|
||||
info ("\n");
|
||||
}
|
||||
|
||||
/* Figure out actual rate. */
|
||||
if (nerdjack) {
|
||||
if (nerdjack_choose_scan(desired_rate, &actual_rate, &period) < 0) {
|
||||
info("error: can't achieve requested scan rate (%lf Hz)\n",
|
||||
if (donerdjack)
|
||||
{
|
||||
if (nerdjack_choose_scan (desired_rate, &actual_rate, &period) < 0)
|
||||
{
|
||||
info ("error: can't achieve requested scan rate (%lf Hz)\n",
|
||||
desired_rate);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (ue9_choose_scan(desired_rate, &actual_rate,
|
||||
&scanconfig, &scaninterval) < 0) {
|
||||
info("error: can't achieve requested scan rate (%lf Hz)\n",
|
||||
}
|
||||
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)
|
||||
info("Actual scanrate is %lf Hz\n", actual_rate);
|
||||
|
||||
if (verb_count && lines) {
|
||||
info("Stopping capture after %d lines\n", lines);
|
||||
{
|
||||
info ("Actual scanrate is %lf Hz\n", actual_rate);
|
||||
info ("Period is %ld\n", period);
|
||||
}
|
||||
|
||||
signal(SIGINT, handle_sig);
|
||||
signal(SIGTERM, handle_sig);
|
||||
|
||||
if (detect) {
|
||||
info("Autodetecting NerdJack address\n");
|
||||
free(address);
|
||||
if(nerdjack_detect(address) < 0) {
|
||||
info("Error with autodetection\n");
|
||||
} else {
|
||||
info("Found NerdJack at address: %s\n",address);
|
||||
if (verb_count && lines)
|
||||
{
|
||||
info ("Stopping capture after %d lines\n", lines);
|
||||
}
|
||||
|
||||
signal (SIGINT, handle_sig);
|
||||
signal (SIGTERM, handle_sig);
|
||||
|
||||
if (detect)
|
||||
{
|
||||
info ("Autodetecting NerdJack address\n");
|
||||
free (address);
|
||||
if (nerdjack_detect (address) < 0)
|
||||
{
|
||||
info ("Error with autodetection\n");
|
||||
goto printhelp;
|
||||
}
|
||||
else
|
||||
{
|
||||
info ("Found NerdJack at address: %s\n", address);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (;;) {
|
||||
for (;;)
|
||||
{
|
||||
int ret;
|
||||
if(nerdjack) {
|
||||
ret = nerdDoStream(address, channel_list, channel_count, precision, period, convert, lines);
|
||||
verb("nerdDoStream returned %d\n", ret);
|
||||
if (donerdjack)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = doStream (address, scanconfig, scaninterval,
|
||||
channel_list, channel_count, convert, lines);
|
||||
verb ("doStream returned %d\n", ret);
|
||||
}
|
||||
if (oneshot)
|
||||
break;
|
||||
@@ -302,64 +439,158 @@ int main(int argc, char *argv[])
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
if (ret == -ENOTCONN && !forceretry) {
|
||||
info("Initial connection failed, giving up\n");
|
||||
//Neither options specified at command line and first time through.
|
||||
//Try LabJack
|
||||
if (ret == -ENOTCONN && donerdjack && !labjack && !nerdjack)
|
||||
{
|
||||
info ("Could not connect NerdJack...Trying LabJack\n");
|
||||
donerdjack = 0;
|
||||
goto doneparse;
|
||||
}
|
||||
|
||||
//Neither option supplied, no address, and second time through.
|
||||
//Try autodetection
|
||||
if (ret == -ENOTCONN && !donerdjack && !labjack && !nerdjack && !addressSpecified) {
|
||||
info ("Could not connect LabJack...Trying to autodetect Nerdjack\n");
|
||||
detect = 1;
|
||||
donerdjack = 1;
|
||||
goto doneparse;
|
||||
}
|
||||
|
||||
if (ret == -ENOTCONN && nerdjack && !detect && !addressSpecified) {
|
||||
info ("Could not reach NerdJack...Trying to autodetect\n");
|
||||
detect = 1;
|
||||
goto doneparse;
|
||||
}
|
||||
|
||||
if (ret == -ENOTCONN && !forceretry)
|
||||
{
|
||||
info ("Initial connection failed, giving up\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == -EAGAIN || ret == -ENOTCONN) {
|
||||
if (ret == -EAGAIN || ret == -ENOTCONN)
|
||||
{
|
||||
/* Some transient error. Wait a tiny bit, then retry */
|
||||
info("Retrying in 5 secs.\n");
|
||||
sleep(5);
|
||||
} else {
|
||||
info("Retrying now.\n");
|
||||
info ("Retrying in 5 secs.\n");
|
||||
sleep (5);
|
||||
}
|
||||
else
|
||||
{
|
||||
info ("Retrying now.\n");
|
||||
}
|
||||
}
|
||||
|
||||
debug("Done loop\n");
|
||||
debug ("Done loop\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nerdDoStream(const char *address, int *channel_list, int channel_count, int precision,
|
||||
unsigned short period, int convert, int lines)
|
||||
int
|
||||
nerdDoStream (const char *address, int *channel_list, int channel_count,
|
||||
int precision, unsigned long period, int convert, int lines,
|
||||
int showmem)
|
||||
{
|
||||
int retval = -EAGAIN;
|
||||
int fd_data;
|
||||
static int first_call = 1;
|
||||
char command[13];
|
||||
static int started = 0;
|
||||
static int wasreset = 0;
|
||||
getPacket command;
|
||||
static unsigned short currentcount = 0;
|
||||
tryagain:
|
||||
|
||||
/* Open connection. If this fails, and this is the
|
||||
first attempt, return a different error code so we give up. */
|
||||
fd_data = nerd_open(address, NERDJACK_DATA_PORT);
|
||||
if (fd_data < 0) {
|
||||
info("Connect failed: %s:%d\n", address, NERDJACK_DATA_PORT);
|
||||
if (first_call)
|
||||
retval = -ENOTCONN;
|
||||
//If this is the first time, set up acquisition
|
||||
//Otherwise try to resume the previous one
|
||||
if (started == 0)
|
||||
{
|
||||
if (nerd_generate_command
|
||||
(&command, channel_list, channel_count, precision, period) < 0)
|
||||
{
|
||||
info ("Failed to create configuration command\n");
|
||||
goto out;
|
||||
}
|
||||
first_call = 0;
|
||||
|
||||
if (nerd_generate_command(command, channel_list, channel_count, precision, period) < 0) {
|
||||
info("Failed to create configuration command\n");
|
||||
if (nerd_send_command (address, "STOP", 4) < 0)
|
||||
{
|
||||
if (first_call) {
|
||||
retval = -ENOTCONN;
|
||||
if(verb_count) info("Failed to send STOP command\n");
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//If we had a transmission in progress, send a command to resume from there
|
||||
char cmdbuf[10];
|
||||
sprintf (cmdbuf, "SETC%05hd", currentcount);
|
||||
retval = nerd_send_command (address, cmdbuf, strlen (cmdbuf));
|
||||
if (retval == -4)
|
||||
{
|
||||
info ("NerdJack was reset\n");
|
||||
//Assume we have not started yet, reset on this side.
|
||||
//If this routine is retried, start over
|
||||
printf ("# NerdJack was reset here\n");
|
||||
currentcount = 0;
|
||||
started = 0;
|
||||
wasreset = 1;
|
||||
goto tryagain;
|
||||
}
|
||||
else if (retval < 0)
|
||||
{
|
||||
info ("Failed to send SETC command\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
//The transmission has begun
|
||||
started = 1;
|
||||
|
||||
/* Open connection */
|
||||
fd_data = nerd_open (address, NERDJACK_DATA_PORT);
|
||||
if (fd_data < 0)
|
||||
{
|
||||
info ("Connect failed: %s:%d\n", address, NERDJACK_DATA_PORT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = nerd_data_stream
|
||||
(fd_data, channel_count, channel_list, precision, convert, lines,
|
||||
showmem, ¤tcount, period, wasreset);
|
||||
wasreset = 0;
|
||||
if (retval == -3)
|
||||
{
|
||||
retval = 0;
|
||||
}
|
||||
if (retval < 0)
|
||||
{
|
||||
info ("Failed to open data stream\n");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if (nerd_data_stream(fd_data, command, channel_count, channel_list, precision, convert, lines) < 0) {
|
||||
info("Failed to open data stream\n");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
info("Stream finished\n");
|
||||
info ("Stream finished\n");
|
||||
retval = 0;
|
||||
|
||||
out1:
|
||||
nerd_close_conn(fd_data);
|
||||
out:
|
||||
out1:
|
||||
nerd_close_conn (fd_data);
|
||||
out:
|
||||
//We've tried communicating, so this is not the first call anymore
|
||||
first_call = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
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 lines)
|
||||
{
|
||||
int retval = -EAGAIN;
|
||||
@@ -373,9 +604,10 @@ int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
@@ -383,78 +615,103 @@ int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
|
||||
first_call = 0;
|
||||
|
||||
/* Make sure nothing is left over from a previous stream */
|
||||
if (ue9_stream_stop(fd_cmd) == 0)
|
||||
verb("Stopped previous stream.\n");
|
||||
ue9_buffer_flush(fd_cmd);
|
||||
if (ue9_stream_stop (fd_cmd) == 0)
|
||||
verb ("Stopped previous stream.\n");
|
||||
ue9_buffer_flush (fd_cmd);
|
||||
|
||||
/* Open data connection */
|
||||
fd_data = ue9_open(address, UE9_DATA_PORT);
|
||||
if (fd_data < 0) {
|
||||
info("Connect failed: %s:%d\n", address, UE9_DATA_PORT);
|
||||
fd_data = ue9_open (address, UE9_DATA_PORT);
|
||||
if (fd_data < 0)
|
||||
{
|
||||
info ("Connect failed: %s:%d\n", address, UE9_DATA_PORT);
|
||||
goto out1;
|
||||
}
|
||||
|
||||
/* Get calibration */
|
||||
if (ue9_get_calibration(fd_cmd, &ci.calib) < 0) {
|
||||
info("Failed to get device calibration\n");
|
||||
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,
|
||||
if (ue9_streamconfig_simple (fd_cmd, channel_list, channel_count,
|
||||
scanconfig, scaninterval,
|
||||
UE9_BIPOLAR_GAIN1) < 0) {
|
||||
info("Failed to set stream configuration\n");
|
||||
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");
|
||||
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);
|
||||
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");
|
||||
info ("Stream finished\n");
|
||||
retval = 0;
|
||||
|
||||
out3:
|
||||
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:
|
||||
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
|
||||
data_callback (int channels, uint16_t * data, void *context)
|
||||
{
|
||||
int i;
|
||||
struct callbackInfo *ci = (struct callbackInfo *)context;
|
||||
struct callbackInfo *ci = (struct callbackInfo *) context;
|
||||
static int lines = 0;
|
||||
|
||||
columns_left = channels;
|
||||
for (i = 0; i < channels; i++) {
|
||||
if (ci->convert)
|
||||
printf("%lf", ue9_binary_to_analog(
|
||||
&ci->calib, UE9_BIPOLAR_GAIN1, 12,
|
||||
data[i]));
|
||||
else
|
||||
printf("%d", data[i]);
|
||||
for (i = 0; i < channels; i++)
|
||||
{
|
||||
switch (ci->convert)
|
||||
{
|
||||
case CONVERT_VOLTS:
|
||||
if (printf
|
||||
("%lf",
|
||||
ue9_binary_to_analog (&ci->calib, UE9_BIPOLAR_GAIN1, 12,
|
||||
data[i])) < 0)
|
||||
goto bad;
|
||||
break;
|
||||
case CONVERT_HEX:
|
||||
if (printf ("%04X", data[i]) < 0)
|
||||
goto bad;
|
||||
break;
|
||||
default:
|
||||
case CONVERT_DEC:
|
||||
if (printf ("%d", data[i]) < 0)
|
||||
goto bad;
|
||||
break;
|
||||
}
|
||||
columns_left--;
|
||||
if (i < (channels - 1)) {
|
||||
putchar(' ');
|
||||
} else {
|
||||
putchar('\n');
|
||||
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;
|
||||
@@ -462,4 +719,8 @@ int data_callback(int channels, uint16_t *data, void *context)
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
info ("Output error (disk full?)\n");
|
||||
return -3;
|
||||
}
|
||||
|
8
ethstream.h
Normal file
8
ethstream.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef ETHSTREAM_H
|
||||
#define ETHSTREAM_H
|
||||
|
||||
#define CONVERT_DEC 0
|
||||
#define CONVERT_VOLTS 1
|
||||
#define CONVERT_HEX 2
|
||||
|
||||
#endif
|
58
ljconfig.c
58
ljconfig.c
@@ -25,38 +25,41 @@
|
||||
#define UE9_COMMAND_PORT 52360
|
||||
|
||||
struct options opt[] = {
|
||||
{ 'a', "address", "string", "host/address of UE9 (192.168.1.209)" },
|
||||
{ 'h', "help", NULL, "this help" },
|
||||
{ 'v', "verbose", NULL, "be verbose" },
|
||||
{ 'V', "version", NULL, "show version number and exit" },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
{'a', "address", "string", "host/address of UE9 (192.168.1.209)"},
|
||||
{'h', "help", NULL, "this help"},
|
||||
{'v', "verbose", NULL, "be verbose"},
|
||||
{'V', "version", NULL, "show version number and exit"},
|
||||
{0, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int optind;
|
||||
char *optarg;
|
||||
char c;
|
||||
FILE *help = stderr;
|
||||
char *address = strdup(DEFAULT_HOST);
|
||||
char *address = strdup (DEFAULT_HOST);
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
/* Parse arguments */
|
||||
opt_init(&optind);
|
||||
while ((c = opt_parse(argc, argv, &optind, &optarg, opt)) != 0) {
|
||||
switch (c) {
|
||||
opt_init (&optind);
|
||||
while ((c = opt_parse (argc, argv, &optind, &optarg, opt)) != 0)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
free(address);
|
||||
address = strdup(optarg);
|
||||
free (address);
|
||||
address = strdup (optarg);
|
||||
break;
|
||||
case 'v':
|
||||
verb_count++;
|
||||
break;
|
||||
case 'V':
|
||||
printf("ljconfig " VERSION "\n");
|
||||
printf("Written by Jim Paris <jim@jtan.com>\n");
|
||||
printf("This program comes with no warranty and is "
|
||||
printf ("ljconfig " VERSION "\n");
|
||||
printf ("Written by Jim Paris <jim@jtan.com>\n");
|
||||
printf ("This program comes with no warranty and is "
|
||||
"provided under the GPLv2.\n");
|
||||
return 0;
|
||||
break;
|
||||
@@ -64,24 +67,26 @@ int main(int argc, char *argv[])
|
||||
help = stdout;
|
||||
default:
|
||||
printhelp:
|
||||
fprintf(help, "Usage: %s [options]\n", *argv);
|
||||
opt_help(opt, help);
|
||||
fprintf(help, "Displays/changes Labjack UE9 config.\n");
|
||||
fprintf (help, "Usage: %s [options]\n", *argv);
|
||||
opt_help (opt, help);
|
||||
fprintf (help, "Displays/changes Labjack UE9 config.\n");
|
||||
return (help == stdout) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(optind<argc) {
|
||||
info("Error: too many arguments (%s)\n\n", argv[optind]);
|
||||
if (optind < argc)
|
||||
{
|
||||
info ("Error: too many arguments (%s)\n\n", argv[optind]);
|
||||
goto printhelp;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
/* Open */
|
||||
fd = ue9_open(address, UE9_COMMAND_PORT);
|
||||
if (fd < 0) {
|
||||
info("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
|
||||
fd = ue9_open (address, UE9_COMMAND_PORT);
|
||||
if (fd < 0)
|
||||
{
|
||||
info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
|
||||
goto out0;
|
||||
}
|
||||
|
||||
@@ -89,10 +94,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
|
||||
ret = 0;
|
||||
out1:
|
||||
out1:
|
||||
/* Close */
|
||||
ue9_close(fd);
|
||||
out0:
|
||||
ue9_close (fd);
|
||||
out0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
67
ljtest.c
67
ljtest.c
@@ -16,52 +16,53 @@
|
||||
#include "ue9.h"
|
||||
#include "compat.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int fd_cmd;
|
||||
struct ue9Calibration calib;
|
||||
|
||||
verb_count = 2;
|
||||
|
||||
fd_cmd = ue9_open("192.168.1.209", 52360);
|
||||
if (fd_cmd < 0) {
|
||||
fprintf(stderr, "ue9_open: %s\n",
|
||||
compat_strerror(errno));
|
||||
fd_cmd = ue9_open ("192.168.1.209", 52360);
|
||||
if (fd_cmd < 0)
|
||||
{
|
||||
fprintf (stderr, "ue9_open: %s\n", compat_strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ue9_get_calibration(fd_cmd, &calib) < 0) {
|
||||
fprintf(stderr, "ue9_get_calibration: %s\n",
|
||||
compat_strerror(errno));
|
||||
if (ue9_get_calibration (fd_cmd, &calib) < 0)
|
||||
{
|
||||
fprintf (stderr, "ue9_get_calibration: %s\n", compat_strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("double unipolarSlope[0] = %lf\n", calib.unipolarSlope[0]);
|
||||
printf("double unipolarSlope[1] = %lf\n", calib.unipolarSlope[1]);
|
||||
printf("double unipolarSlope[2] = %lf\n", calib.unipolarSlope[2]);
|
||||
printf("double unipolarSlope[3] = %lf\n", calib.unipolarSlope[3]);
|
||||
printf("double unipolarOffset[0] = %lf\n", calib.unipolarOffset[0]);
|
||||
printf("double unipolarOffset[1] = %lf\n", calib.unipolarOffset[1]);
|
||||
printf("double unipolarOffset[2] = %lf\n", calib.unipolarOffset[2]);
|
||||
printf("double unipolarOffset[3] = %lf\n", calib.unipolarOffset[3]);
|
||||
printf("double bipolarSlope = %lf\n", calib.bipolarSlope);
|
||||
printf("double bipolarOffset = %lf\n", calib.bipolarOffset);
|
||||
printf("double DACSlope[0] = %lf\n", calib.DACSlope[0]);
|
||||
printf("double DACSlope[1] = %lf\n", calib.DACSlope[1]);
|
||||
printf("double DACOffset[0] = %lf\n", calib.DACOffset[0]);
|
||||
printf("double DACOffset[1] = %lf\n", calib.DACOffset[1]);
|
||||
printf("double tempSlope = %lf\n", calib.tempSlope);
|
||||
printf("double tempSlopeLow = %lf\n", calib.tempSlopeLow);
|
||||
printf("double calTemp = %lf\n", calib.calTemp);
|
||||
printf("double Vref = %lf\n", calib.Vref);
|
||||
printf("double VrefDiv2 = %lf\n", calib.VrefDiv2);
|
||||
printf("double VsSlope = %lf\n", calib.VsSlope);
|
||||
printf("double hiResUnipolarSlope = %lf\n", calib.hiResUnipolarSlope);
|
||||
printf("double hiResUnipolarOffset = %lf\n", calib.hiResUnipolarOffset);
|
||||
printf("double hiResBipolarSlope = %lf\n", calib.hiResBipolarSlope);
|
||||
printf("double hiResBipolarOffset = %lf\n", calib.hiResBipolarOffset);
|
||||
printf ("double unipolarSlope[0] = %lf\n", calib.unipolarSlope[0]);
|
||||
printf ("double unipolarSlope[1] = %lf\n", calib.unipolarSlope[1]);
|
||||
printf ("double unipolarSlope[2] = %lf\n", calib.unipolarSlope[2]);
|
||||
printf ("double unipolarSlope[3] = %lf\n", calib.unipolarSlope[3]);
|
||||
printf ("double unipolarOffset[0] = %lf\n", calib.unipolarOffset[0]);
|
||||
printf ("double unipolarOffset[1] = %lf\n", calib.unipolarOffset[1]);
|
||||
printf ("double unipolarOffset[2] = %lf\n", calib.unipolarOffset[2]);
|
||||
printf ("double unipolarOffset[3] = %lf\n", calib.unipolarOffset[3]);
|
||||
printf ("double bipolarSlope = %lf\n", calib.bipolarSlope);
|
||||
printf ("double bipolarOffset = %lf\n", calib.bipolarOffset);
|
||||
printf ("double DACSlope[0] = %lf\n", calib.DACSlope[0]);
|
||||
printf ("double DACSlope[1] = %lf\n", calib.DACSlope[1]);
|
||||
printf ("double DACOffset[0] = %lf\n", calib.DACOffset[0]);
|
||||
printf ("double DACOffset[1] = %lf\n", calib.DACOffset[1]);
|
||||
printf ("double tempSlope = %lf\n", calib.tempSlope);
|
||||
printf ("double tempSlopeLow = %lf\n", calib.tempSlopeLow);
|
||||
printf ("double calTemp = %lf\n", calib.calTemp);
|
||||
printf ("double Vref = %lf\n", calib.Vref);
|
||||
printf ("double VrefDiv2 = %lf\n", calib.VrefDiv2);
|
||||
printf ("double VsSlope = %lf\n", calib.VsSlope);
|
||||
printf ("double hiResUnipolarSlope = %lf\n", calib.hiResUnipolarSlope);
|
||||
printf ("double hiResUnipolarOffset = %lf\n", calib.hiResUnipolarOffset);
|
||||
printf ("double hiResBipolarSlope = %lf\n", calib.hiResBipolarSlope);
|
||||
printf ("double hiResBipolarOffset = %lf\n", calib.hiResBipolarOffset);
|
||||
|
||||
ue9_close(fd_cmd);
|
||||
ue9_close (fd_cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
746
nerdjack.c
746
nerdjack.c
@@ -13,7 +13,7 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "netutil.h"
|
||||
@@ -23,57 +23,242 @@
|
||||
#include "nerdjack.h"
|
||||
#include "util.h"
|
||||
#include "netutil.h"
|
||||
#include "ethstream.h"
|
||||
|
||||
#define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
|
||||
|
||||
#define NERD_HEADER_SIZE 8
|
||||
#define MAX_SOCKETS 32
|
||||
|
||||
typedef struct __attribute__ ((__packed__))
|
||||
{
|
||||
unsigned char headerone;
|
||||
unsigned char headertwo;
|
||||
unsigned short packetNumber;
|
||||
unsigned short adcused;
|
||||
unsigned short packetsready;
|
||||
signed short data[NERDJACK_NUM_SAMPLES];
|
||||
} dataPacket;
|
||||
|
||||
struct discovered_socket {
|
||||
int sock;
|
||||
uint32_t local_ip;
|
||||
uint32_t subnet_mask;
|
||||
};
|
||||
|
||||
struct discover_t {
|
||||
struct discovered_socket socks[MAX_SOCKETS];
|
||||
unsigned int sock_count;
|
||||
};
|
||||
|
||||
/* Choose the best ScanConfig and ScanInterval parameters for the
|
||||
desired scanrate. Returns -1 if no valid config found */
|
||||
int nerdjack_choose_scan(double desired_rate, double *actual_rate, int *period)
|
||||
int
|
||||
nerdjack_choose_scan (double desired_rate, double *actual_rate,
|
||||
unsigned long *period)
|
||||
{
|
||||
|
||||
*period = round((double) NERDJACK_CLOCK_RATE / desired_rate);
|
||||
* actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period;
|
||||
if(*actual_rate != desired_rate) {
|
||||
//The ffffe is because of a silicon bug. The last bit is unusable in all
|
||||
//devices so far. It is worked around on the chip, but giving it exactly
|
||||
//0xfffff would cause the workaround code to roll over.
|
||||
*period = floor ((double) NERDJACK_CLOCK_RATE / desired_rate);
|
||||
if (*period > 0x0ffffe)
|
||||
{
|
||||
info ("Cannot sample that slowly\n");
|
||||
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) 0x0ffffe;
|
||||
*period = 0x0ffffe;
|
||||
return -1;
|
||||
}
|
||||
//Period holds the period register for the NerdJack, so it needs to be right
|
||||
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period;
|
||||
if (*actual_rate != desired_rate)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nerdjack_detect(char * ipAddress) {
|
||||
int32_t sock, receivesock;
|
||||
/**
|
||||
* Create a discovered socket and add it to the socket list structure.
|
||||
* All sockets in the structure should be created, bound, and ready for broadcasting
|
||||
*/
|
||||
static int discovered_sock_create(struct discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)
|
||||
{
|
||||
if (ds->sock_count >= MAX_SOCKETS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create socket. */
|
||||
int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allow broadcast. */
|
||||
int sock_opt = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
|
||||
|
||||
/* Set nonblocking */
|
||||
if (soblock (sock, 0) < 0)
|
||||
{
|
||||
verb ("can't set nonblocking\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bind socket. */
|
||||
struct sockaddr_in sock_addr;
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_addr.s_addr = htonl(local_ip);
|
||||
sock_addr.sin_port = htons(0);
|
||||
if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write sock entry. */
|
||||
struct discovered_socket *dss = &ds->socks[ds->sock_count++];
|
||||
dss->sock = sock;
|
||||
dss->local_ip = local_ip;
|
||||
dss->subnet_mask = subnet_mask;
|
||||
|
||||
return 1;
|
||||
}
|
||||
/**
|
||||
* Enumerate all interfaces we can find and open sockets on each
|
||||
*/
|
||||
#if defined(USE_IPHLPAPI)
|
||||
static void enumerate_interfaces(struct discover_t *ds)
|
||||
{
|
||||
PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
|
||||
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||
|
||||
DWORD Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
|
||||
if (Ret != NO_ERROR) {
|
||||
free(pAdapterInfo);
|
||||
if (Ret != ERROR_BUFFER_OVERFLOW) {
|
||||
return;
|
||||
}
|
||||
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
|
||||
Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
|
||||
if (Ret != NO_ERROR) {
|
||||
free(pAdapterInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
|
||||
while (pAdapter) {
|
||||
IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList;
|
||||
while (pIPAddr) {
|
||||
uint32_t local_ip = ntohl(inet_addr(pIPAddr->IpAddress.String));
|
||||
uint32_t mask = ntohl(inet_addr(pIPAddr->IpMask.String));
|
||||
|
||||
if (local_ip == 0) {
|
||||
pIPAddr = pIPAddr->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
discovered_sock_create(ds, local_ip, mask);
|
||||
pIPAddr = pIPAddr->Next;
|
||||
}
|
||||
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
|
||||
free(pAdapterInfo);
|
||||
}
|
||||
|
||||
#else
|
||||
static void enumerate_interfaces(struct discover_t *ds) {
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct ifconf ifc;
|
||||
uint8_t buf[8192];
|
||||
ifc.ifc_len = sizeof(buf);
|
||||
ifc.ifc_buf = (char *)buf;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *ptr = (uint8_t *)ifc.ifc_req;
|
||||
uint8_t *end = (uint8_t *)&ifc.ifc_buf[ifc.ifc_len];
|
||||
|
||||
while (ptr <= end) {
|
||||
struct ifreq *ifr = (struct ifreq *)ptr;
|
||||
ptr += _SIZEOF_ADDR_IFREQ(*ifr);
|
||||
|
||||
if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
|
||||
continue;
|
||||
}
|
||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)&(ifr->ifr_addr);
|
||||
uint32_t local_ip = ntohl(addr_in->sin_addr.s_addr);
|
||||
if (local_ip == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct sockaddr_in *mask_in = (struct sockaddr_in *)&(ifr->ifr_addr);
|
||||
uint32_t mask = ntohl(mask_in->sin_addr.s_addr);
|
||||
|
||||
discovered_sock_create(ds, local_ip, mask);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* Close all sockets previously enumerated and free the struct
|
||||
*/
|
||||
static void destroy_socks(struct discover_t *ds)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < ds->sock_count; i++) {
|
||||
struct discovered_socket *dss = &ds->socks[i];
|
||||
close(dss->sock);
|
||||
}
|
||||
|
||||
free(ds);
|
||||
}
|
||||
|
||||
|
||||
/* Perform autodetection. Returns 0 on success, -1 on error
|
||||
* Sets ipAddress to the detected address
|
||||
*/
|
||||
int
|
||||
nerdjack_detect (char *ipAddress)
|
||||
{
|
||||
int32_t receivesock;
|
||||
struct sockaddr_in sa, receiveaddr, sFromAddr;
|
||||
int bytes_sent, buffer_length;
|
||||
int buffer_length;
|
||||
char buffer[200];
|
||||
char incomingData[10];
|
||||
unsigned int lFromLen;
|
||||
|
||||
sprintf(buffer, "TEST");
|
||||
buffer_length = strlen(buffer) + 1;
|
||||
sprintf (buffer, "TEST");
|
||||
buffer_length = strlen (buffer) + 1;
|
||||
|
||||
net_init();
|
||||
net_init ();
|
||||
|
||||
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
receivesock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
receivesock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
/* Set nonblocking */
|
||||
if (soblock(sock, 0) < 0) {
|
||||
verb("can't set nonblocking\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set nonblocking */
|
||||
if (soblock(receivesock, 0) < 0) {
|
||||
verb("can't set nonblocking\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(void *) &opt,sizeof(int));
|
||||
|
||||
if((-1 == sock) || (-1 == receivesock)) /* if socket failed to initialize, exit */
|
||||
if (soblock (receivesock, 0) < 0)
|
||||
{
|
||||
printf("Error Creating Socket\n");
|
||||
verb ("can't set nonblocking\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (-1 == receivesock) /* if socket failed to initialize, exit */
|
||||
{
|
||||
verb ("Error Creating Socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -82,282 +267,437 @@ int nerdjack_detect(char * ipAddress) {
|
||||
receiveaddr.sin_family = PF_INET;
|
||||
|
||||
//Setup ports to send on DATA and receive on RECEIVE
|
||||
receiveaddr.sin_port = htons(NERDJACK_UDP_RECEIVE_PORT);
|
||||
sa.sin_port = htons(NERDJACK_DATA_PORT);
|
||||
receiveaddr.sin_port = htons (NERDJACK_UDP_RECEIVE_PORT);
|
||||
sa.sin_port = htons (NERDJACK_DATA_PORT);
|
||||
|
||||
//Receive from any IP address, Will send to broadcast
|
||||
//Receive from any IP address
|
||||
receiveaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
sa.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
|
||||
bind(receivesock,(struct sockaddr*) &receiveaddr, sizeof(struct sockaddr_in));
|
||||
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) {
|
||||
printf("Error sending packet: %s\n", strerror(errno) );
|
||||
struct discover_t *ds = (struct discover_t *)calloc(1, sizeof(struct discover_t));
|
||||
if (!ds) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
lFromLen = sizeof(sFromAddr);
|
||||
|
||||
if(0 > recvfrom_timeout(receivesock, incomingData, sizeof(incomingData),0,(struct sockaddr *) &sFromAddr, &lFromLen,
|
||||
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT })) {
|
||||
|
||||
/* Create a routable broadcast socket. */
|
||||
if (!discovered_sock_create(ds, 0, 0)) {
|
||||
free(ds);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ipAddress = malloc(INET_ADDRSTRLEN);
|
||||
/* Detect & create local sockets. */
|
||||
enumerate_interfaces(ds);
|
||||
|
||||
/*
|
||||
* Send subnet broadcast using each local ip socket.
|
||||
* This will work with multiple separate 169.254.x.x interfaces.
|
||||
*/
|
||||
unsigned int i;
|
||||
for (i = 0; i < ds->sock_count; i++) {
|
||||
struct discovered_socket *dss = &ds->socks[i];
|
||||
uint32_t target_ip = dss->local_ip | ~dss->subnet_mask;
|
||||
sa.sin_addr.s_addr = htonl(target_ip);
|
||||
sendto (dss->sock, buffer, buffer_length, 0, (struct sockaddr *) &sa,
|
||||
sizeof (struct sockaddr_in));
|
||||
}
|
||||
|
||||
destroy_socks(ds);
|
||||
|
||||
lFromLen = sizeof (sFromAddr);
|
||||
|
||||
if (0 >
|
||||
recvfrom_timeout (receivesock, incomingData, sizeof (incomingData), 0,
|
||||
(struct sockaddr *) &sFromAddr, &lFromLen,
|
||||
&(struct timeval)
|
||||
{
|
||||
.tv_sec = NERDJACK_TIMEOUT}))
|
||||
{
|
||||
close(receivesock);
|
||||
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));
|
||||
strcpy (ipAddress, inet_ntoa (sFromAddr.sin_addr));
|
||||
|
||||
close(sock); /* close the socket */
|
||||
close(receivesock);
|
||||
close (receivesock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int numCopies;
|
||||
int * destlist;
|
||||
} deststruct;
|
||||
|
||||
int nerd_data_stream(int data_fd, char * command, int numChannels, int *channel_list, int precision, int convert, int lines)
|
||||
/* Send the given command to address. The command should be something
|
||||
* of the specified length. This expects the NerdJack to reply with OK
|
||||
* or NO
|
||||
*/
|
||||
int
|
||||
nerd_send_command (const char *address, void *command, int length)
|
||||
{
|
||||
unsigned char buf[NERDJACK_PACKET_SIZE];
|
||||
int ret, fd_command;
|
||||
char buf[3];
|
||||
fd_command = nerd_open (address, NERDJACK_COMMAND_PORT);
|
||||
if (fd_command < 0)
|
||||
{
|
||||
info ("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT);
|
||||
return -2;
|
||||
}
|
||||
|
||||
//int numGroups = NERDJACK_NUM_SAMPLES / numChannels;
|
||||
/* Send request */
|
||||
ret = send_all_timeout (fd_command, command, length, 0, &(struct timeval)
|
||||
{
|
||||
.tv_sec = NERDJACK_TIMEOUT});
|
||||
if (ret < 0 || ret != length)
|
||||
{
|
||||
verb ("short send %d\n", (int) ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
//int totalread = 0;
|
||||
int ret = 0;
|
||||
int alignment = 0;
|
||||
ret = recv_all_timeout (fd_command, buf, 3, 0, &(struct timeval)
|
||||
{
|
||||
.tv_sec = NERDJACK_TIMEOUT});
|
||||
|
||||
nerd_close_conn (fd_command);
|
||||
|
||||
if (ret < 0 || ret != 3)
|
||||
{
|
||||
verb ("Error receiving OK for command\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 != strcmp ("OK", buf))
|
||||
{
|
||||
verb ("Did not receive OK. Received %s\n", buf);
|
||||
return -4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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 wasreset)
|
||||
{
|
||||
//Variables that should persist across retries
|
||||
static dataPacket buf;
|
||||
static int linesleft = 0;
|
||||
static int linesdumped = 0;
|
||||
|
||||
//Variables essential to packet processing
|
||||
signed short datapoint = 0;
|
||||
signed short dataline[NERDJACK_CHANNELS];
|
||||
long double voltline[NERDJACK_CHANNELS];
|
||||
deststruct destination[NERDJACK_CHANNELS];
|
||||
int tempdestlist[NERDJACK_CHANNELS];
|
||||
unsigned short currentcount = 0;
|
||||
unsigned long memused = 0;
|
||||
int i;
|
||||
|
||||
int numChannelsSampled = channel_list[0] + 1;
|
||||
|
||||
//The number sampled will be the highest channel requested plus 1
|
||||
//(i.e. channel 0 requested means 1 sampled)
|
||||
for (i = 0; i < numChannels; i++)
|
||||
{
|
||||
if (channel_list[i] + 1 > numChannelsSampled)
|
||||
numChannelsSampled = channel_list[i] + 1;
|
||||
}
|
||||
|
||||
|
||||
double voltline[numChannels];
|
||||
|
||||
unsigned short dataline[numChannels];
|
||||
|
||||
unsigned short packetsready = 0;
|
||||
unsigned short adcused = 0;
|
||||
unsigned short tempshort = 0;
|
||||
int charsread = 0;
|
||||
int charsleft = 0;
|
||||
int additionalread = 0;
|
||||
int linesleft = lines;
|
||||
|
||||
int numgroups = 0;
|
||||
long double volts;
|
||||
int numgroupsProcessed = 0;
|
||||
double volts;
|
||||
|
||||
int channels_left = numChannels;
|
||||
int channelprocessing = 0;
|
||||
int currentalign = 0; //Index into sampled channels
|
||||
int i;
|
||||
int numDuplicates = 0;
|
||||
//The timeout should be the expected time plus 60 seconds
|
||||
//This permits slower speeds to work properly
|
||||
unsigned int expectedtimeout =
|
||||
(period * NERDJACK_NUM_SAMPLES / NERDJACK_CLOCK_RATE) + 60;
|
||||
|
||||
//Loop through channel_list until all channels recognized
|
||||
//start with channelprocessing = 0 and increment through channels.
|
||||
//If a channel is found in the list set it up appropriately.
|
||||
do {
|
||||
//numduplicates = 0;
|
||||
destination[currentalign].numCopies = 0;
|
||||
for(i = 0; i < numChannels; i++) {
|
||||
if(channelprocessing == channel_list[i]) {
|
||||
//destination[currentalign] = i;
|
||||
tempdestlist[destination[currentalign].numCopies] = i;
|
||||
if(destination[currentalign].numCopies > 0) {
|
||||
numDuplicates++;
|
||||
//Check to see if we're trying to resume
|
||||
//Don't blow away linesleft in that case
|
||||
if (lines != 0 && linesleft == 0)
|
||||
{
|
||||
linesleft = lines;
|
||||
}
|
||||
destination[currentalign].numCopies++;
|
||||
//currentalign++;
|
||||
channels_left--;
|
||||
//break;
|
||||
|
||||
//If there was a reset, we still need to dump a line because of faulty PDCA start
|
||||
if (wasreset)
|
||||
{
|
||||
linesdumped = 0;
|
||||
}
|
||||
|
||||
//If this is the first time called, warn the user if we're too fast
|
||||
if (linesdumped == 0)
|
||||
{
|
||||
if (period < (numChannelsSampled * 200 + 600))
|
||||
{
|
||||
info ("You are sampling close to the limit of NerdJack\n");
|
||||
info ("Sample fewer channels or sample slower\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(destination[currentalign].numCopies > 0) {
|
||||
destination[currentalign].destlist = malloc( destination[currentalign].numCopies * sizeof(int) );
|
||||
memcpy(destination[currentalign].destlist, tempdestlist, destination[currentalign].numCopies * sizeof(int));
|
||||
currentalign++;
|
||||
}
|
||||
channelprocessing++;
|
||||
} while(channels_left > 0);
|
||||
//Now destination structure array is set as well as numDuplicates.
|
||||
|
||||
int totalGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled;
|
||||
|
||||
int numChannelsSampled = numChannels - numDuplicates;
|
||||
int numGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled;
|
||||
|
||||
/* Send request */
|
||||
ret = send_all_timeout(data_fd, command, strlen(command), 0,
|
||||
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT });
|
||||
if (ret < 0 || ret != strlen(command)) {
|
||||
verb("short send %d\n", (int)ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Loop forever to grab data
|
||||
while((charsread = recv_all_timeout(data_fd,buf,NERDJACK_PACKET_SIZE,0,
|
||||
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }))){
|
||||
while ((charsread =
|
||||
recv_all_timeout (data_fd, &buf, NERDJACK_PACKET_SIZE, 0,
|
||||
&(struct timeval)
|
||||
{
|
||||
.tv_sec = expectedtimeout})))
|
||||
{
|
||||
|
||||
//We want a complete packet, so take the chars so far and keep waiting
|
||||
if(charsread != NERDJACK_PACKET_SIZE) {
|
||||
charsleft = NERDJACK_PACKET_SIZE - charsread;
|
||||
while(charsleft != 0){
|
||||
additionalread = recv_all_timeout(data_fd,buf+charsread,charsleft,0,
|
||||
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT });
|
||||
charsread = charsread + additionalread;
|
||||
charsleft = NERDJACK_PACKET_SIZE - charsread;
|
||||
}
|
||||
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[0] != 0xF0 || buf[1] != 0xAA) {
|
||||
printf("No Header info\n");
|
||||
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 = (buf[2] << 8) | buf[3];
|
||||
if(tempshort != currentcount ){
|
||||
printf("Count wrong. Expected %hd but got %hd\n", currentcount, tempshort);
|
||||
tempshort = ntohs (buf.packetNumber);
|
||||
if (tempshort != *currentcount)
|
||||
{
|
||||
info ("Count wrong. Expected %hd but got %hd\n", *currentcount,
|
||||
tempshort);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Increment number of packets received
|
||||
currentcount++;
|
||||
*currentcount = *currentcount + 1;
|
||||
|
||||
//Process the rest of the header and update the index value to be pointing after it
|
||||
index = 12;
|
||||
memused = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | (buf[7]);
|
||||
adcused = (buf[8] << 8) | (buf[9]);
|
||||
packetsready = (buf[10] << 8) | (buf[11]);
|
||||
alignment = 0;
|
||||
numgroups = 0;
|
||||
adcused = ntohs (buf.adcused);
|
||||
packetsready = ntohs (buf.packetsready);
|
||||
numgroupsProcessed = 0;
|
||||
|
||||
if (showmem)
|
||||
{
|
||||
printf ("%hd %hd\n", adcused, packetsready);
|
||||
continue;
|
||||
}
|
||||
|
||||
//While there is still more data in the packet, process it
|
||||
while(charsread > index) {
|
||||
datapoint = (buf[index] << 8 | buf[index+1]);
|
||||
if(convert) {
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
for(i = 0; i < destination[alignment].numCopies; i++) {
|
||||
dataline[destination[alignment].destlist[i]] = datapoint;
|
||||
}
|
||||
while (numgroupsProcessed < totalGroups)
|
||||
{
|
||||
//Poison the data structure
|
||||
switch (convert)
|
||||
{
|
||||
case CONVERT_VOLTS:
|
||||
memset (voltline, 0, numChannels * sizeof (double));
|
||||
break;
|
||||
default:
|
||||
case CONVERT_HEX:
|
||||
case CONVERT_DEC:
|
||||
memset (dataline, 0, numChannels * sizeof (unsigned char));
|
||||
}
|
||||
|
||||
//Each point is two bytes, so increment index and total bytes read
|
||||
index++;
|
||||
index++;
|
||||
alignment++;
|
||||
//totalread++;
|
||||
//Read in each group
|
||||
for (i = 0; i < numChannels; i++)
|
||||
{
|
||||
//Get the datapoint associated with the desired channel
|
||||
datapoint =
|
||||
ntohs (buf.
|
||||
data[channel_list[i] +
|
||||
numgroupsProcessed * numChannelsSampled]);
|
||||
|
||||
|
||||
|
||||
|
||||
//Since channel data is packed, we need to know when to insert a newline
|
||||
if(alignment == numChannelsSampled){
|
||||
if(convert) {
|
||||
for(i = 0; i < numChannels; i++) {
|
||||
printf("%Lf ",voltline[i]);
|
||||
//Place it into the line
|
||||
switch (convert)
|
||||
{
|
||||
case CONVERT_VOLTS:
|
||||
if (channel_list[i] <= 5)
|
||||
{
|
||||
volts =
|
||||
(double) (datapoint / 32767.0) *
|
||||
((precision & 0x01) ? 5.0 : 10.0);
|
||||
}
|
||||
} else {
|
||||
for(i = 0; i < numChannels; i++) {
|
||||
printf("%hd ",dataline[i]);
|
||||
else
|
||||
{
|
||||
volts =
|
||||
(double) (datapoint / 32767.0) *
|
||||
((precision & 0x02) ? 5.0 : 10.0);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
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) {
|
||||
voltline[i] = volts;
|
||||
break;
|
||||
default:
|
||||
case CONVERT_HEX:
|
||||
case CONVERT_DEC:
|
||||
dataline[i] = (unsigned short) (datapoint - INT16_MIN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//We want to dump the first line because it's usually spurious
|
||||
if (linesdumped != 0)
|
||||
{
|
||||
//Now print the group
|
||||
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;
|
||||
|
||||
//If we're counting lines, decrement them
|
||||
if (lines != 0)
|
||||
{
|
||||
linesleft--;
|
||||
if (linesleft == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
linesdumped = linesdumped + 1;
|
||||
}
|
||||
|
||||
//We've processed this group, so advance the counter
|
||||
numgroupsProcessed++;
|
||||
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
info ("Output error (disk full?)\n");
|
||||
return -3;
|
||||
|
||||
}
|
||||
|
||||
int nerd_open(const char *address,int port) {
|
||||
/* Open a connection to the NerdJack */
|
||||
int
|
||||
nerd_open (const char *address, int port)
|
||||
{
|
||||
|
||||
struct hostent *he;
|
||||
|
||||
net_init();
|
||||
net_init ();
|
||||
|
||||
int32_t i32SocketFD = socket(PF_INET, SOCK_STREAM, 0);
|
||||
int32_t i32SocketFD = socket (PF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if(-1 == i32SocketFD)
|
||||
if (-1 == i32SocketFD)
|
||||
{
|
||||
printf("cannot create socket");
|
||||
verb ("cannot create socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set nonblocking */
|
||||
if (soblock(i32SocketFD, 0) < 0) {
|
||||
verb("can't set nonblocking\n");
|
||||
if (soblock (i32SocketFD, 0) < 0)
|
||||
{
|
||||
verb ("can't set nonblocking\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in stSockAddr;
|
||||
memset(&stSockAddr, 0, sizeof(stSockAddr));
|
||||
memset (&stSockAddr, 0, sizeof (stSockAddr));
|
||||
|
||||
stSockAddr.sin_family = AF_INET;
|
||||
stSockAddr.sin_port = htons(port);
|
||||
stSockAddr.sin_port = htons (port);
|
||||
|
||||
he = gethostbyname(address);
|
||||
if (he == NULL) {
|
||||
verb("gethostbyname(\"%s\") failed\n", address);
|
||||
he = gethostbyname (address);
|
||||
if (he == NULL)
|
||||
{
|
||||
verb ("gethostbyname(\"%s\") failed\n", address);
|
||||
return -1;
|
||||
}
|
||||
stSockAddr.sin_addr = *((struct in_addr *) he->h_addr);
|
||||
|
||||
debug("Resolved %s -> %s\n", address, inet_ntoa(stSockAddr.sin_addr));
|
||||
debug ("Resolved %s -> %s\n", address, inet_ntoa (stSockAddr.sin_addr));
|
||||
|
||||
/* Connect */
|
||||
if (connect_timeout(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof(stSockAddr),
|
||||
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }) < 0) {
|
||||
verb("connection to %s:%d failed: %s\n",
|
||||
inet_ntoa(stSockAddr.sin_addr), port, compat_strerror(errno));
|
||||
if (connect_timeout
|
||||
(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof (stSockAddr),
|
||||
&(struct timeval)
|
||||
{
|
||||
.tv_sec = 3}) < 0)
|
||||
{
|
||||
verb ("connection to %s:%d failed: %s\n",
|
||||
inet_ntoa (stSockAddr.sin_addr), port, compat_strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return i32SocketFD;
|
||||
}
|
||||
|
||||
int nerd_generate_command(char * command, int * channel_list, int channel_count, int precision,
|
||||
unsigned short period) {
|
||||
//Generate an appropriate sample initiation command
|
||||
int
|
||||
nerd_generate_command (getPacket * command, int *channel_list,
|
||||
int channel_count, int precision, unsigned long period)
|
||||
{
|
||||
|
||||
int channelbit = 0;
|
||||
short channelbit = 0;
|
||||
int i;
|
||||
int highestchannel = 0;
|
||||
|
||||
for( i = 0; i < channel_count; i++) {
|
||||
channelbit = channelbit | (0x1 << channel_list[i]);
|
||||
for (i = 0; i < channel_count; i++)
|
||||
{
|
||||
if (channel_list[i] > highestchannel)
|
||||
{
|
||||
highestchannel = channel_list[i];
|
||||
}
|
||||
//channelbit = channelbit | (0x1 << channel_list[i]);
|
||||
}
|
||||
|
||||
sprintf(command,"GET%3.3X%d%5.5d", channelbit,precision,period);
|
||||
for (i = 0; i <= highestchannel; i++)
|
||||
{
|
||||
channelbit = channelbit | (0x01 << i);
|
||||
}
|
||||
|
||||
command->word[0] = 'G';
|
||||
command->word[1] = 'E';
|
||||
command->word[2] = 'T';
|
||||
command->word[3] = 'D';
|
||||
command->channelbit = htons (channelbit);
|
||||
command->precision = precision;
|
||||
command->period = htonl (period);
|
||||
command->prescaler = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int nerd_close_conn(int data_fd)
|
||||
int
|
||||
nerd_close_conn (int data_fd)
|
||||
{
|
||||
shutdown(data_fd, 2);
|
||||
close(data_fd);
|
||||
shutdown (data_fd, 2);
|
||||
close (data_fd);
|
||||
return 0;
|
||||
}
|
||||
|
37
nerdjack.h
37
nerdjack.h
@@ -16,29 +16,48 @@
|
||||
#include "netutil.h"
|
||||
|
||||
#define NERDJACK_CHANNELS 12
|
||||
#define NERDJACK_CLOCK_RATE 54000000
|
||||
#define NERDJACK_CLOCK_RATE 66000000
|
||||
#define NERDJACK_DATA_PORT 49155
|
||||
#define NERDJACK_UDP_RECEIVE_PORT 49156
|
||||
#define NERDJACK_COMMAND_PORT 49157
|
||||
|
||||
#define NERDJACK_PACKET_SIZE 1460
|
||||
#define NERDJACK_NUM_SAMPLES 724
|
||||
#define NERDJACK_NUM_SAMPLES 726
|
||||
|
||||
/* Packet structure used in message to start sampling on NerdJack */
|
||||
typedef struct __attribute__ ((__packed__))
|
||||
{
|
||||
char word[4];
|
||||
unsigned long period;
|
||||
unsigned short channelbit;
|
||||
unsigned char precision;
|
||||
unsigned char prescaler;
|
||||
} getPacket;
|
||||
|
||||
/* Open/close TCP/IP connection to the NerdJack */
|
||||
int nerd_open(const char *address,int port);
|
||||
int nerd_close_conn(int data_fd);
|
||||
int nerd_open (const char *address, int port);
|
||||
int nerd_close_conn (int data_fd);
|
||||
|
||||
/* Generate the command word for the NerdJack */
|
||||
int nerd_generate_command(char * command, int * channel_list, int channel_count, int precision,
|
||||
unsigned short period);
|
||||
int nerd_generate_command (getPacket * command, int *channel_list,
|
||||
int channel_count, int precision,
|
||||
unsigned long period);
|
||||
|
||||
/* Send given command to NerdJack */
|
||||
int nerd_send_command (const char *address, void *command, int length);
|
||||
|
||||
/* Stream data out of the NerdJack */
|
||||
int nerd_data_stream(int data_fd, char * command, int numChannels, int * channel_list, int precision, int convert, int lines);
|
||||
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 wasreset);
|
||||
|
||||
/* Detect the IP Address of the NerdJack and return in ipAddress */
|
||||
int nerdjack_detect(char * ipAddress);
|
||||
int nerdjack_detect (char *ipAddress);
|
||||
|
||||
/* Choose the best ScanConfig and ScanInterval parameters for the
|
||||
desired scanrate. Returns -1 if no valid config found */
|
||||
int nerdjack_choose_scan(double desired_rate, double *actual_rate, int *period);
|
||||
int nerdjack_choose_scan (double desired_rate, double *actual_rate,
|
||||
unsigned long *period);
|
||||
|
||||
#endif
|
||||
|
131
netutil.c
131
netutil.c
@@ -5,28 +5,31 @@
|
||||
#include <stdio.h>
|
||||
|
||||
/* Initialize networking */
|
||||
void net_init(void)
|
||||
void
|
||||
net_init (void)
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
WSADATA blah;
|
||||
WSAStartup(0x0101, &blah);
|
||||
WSAStartup (0x0101, &blah);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set socket blocking/nonblocking */
|
||||
int soblock(int socket, int blocking)
|
||||
int
|
||||
soblock (int socket, int blocking)
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
unsigned long arg = blocking ? 0 : 1;
|
||||
if (ioctlsocket(socket, FIONBIO, &arg) != 0)
|
||||
if (ioctlsocket (socket, FIONBIO, &arg) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
#else
|
||||
int sockopt;
|
||||
|
||||
/* Get flags */
|
||||
sockopt = fcntl(socket, F_GETFL);
|
||||
if (sockopt == -1) {
|
||||
sockopt = fcntl (socket, F_GETFL);
|
||||
if (sockopt == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -37,7 +40,7 @@ int soblock(int socket, int blocking)
|
||||
sockopt |= O_NONBLOCK;
|
||||
|
||||
/* Set flags */
|
||||
if (fcntl(socket, F_SETFL, sockopt) != 0)
|
||||
if (fcntl (socket, F_SETFL, sockopt) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
@@ -46,7 +49,8 @@ int soblock(int socket, int 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
|
||||
connect_timeout (int s, const struct sockaddr *serv_addr, socklen_t addrlen,
|
||||
struct timeval *timeout)
|
||||
{
|
||||
int ret;
|
||||
@@ -56,16 +60,17 @@ int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
|
||||
socklen_t optlen;
|
||||
|
||||
/* Start connect */
|
||||
ret = connect(s, serv_addr, addrlen);
|
||||
ret = connect (s, serv_addr, addrlen);
|
||||
|
||||
if (ret == 0) {
|
||||
if (ret == 0)
|
||||
{
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for immediate failure */
|
||||
#ifdef __WIN32__
|
||||
errno = WSAGetLastError();
|
||||
errno = WSAGetLastError ();
|
||||
if (ret < 0 && errno != WSAEWOULDBLOCK && errno != WSAEINVAL)
|
||||
return -1;
|
||||
#else
|
||||
@@ -74,27 +79,30 @@ int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
|
||||
#endif
|
||||
|
||||
/* In progress, wait for result. */
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(s, &writefds);
|
||||
FD_ZERO(&exceptfds);
|
||||
FD_SET(s, &exceptfds);
|
||||
ret = select(s + 1, NULL, &writefds, &exceptfds, timeout);
|
||||
if (ret < 0) {
|
||||
FD_ZERO (&writefds);
|
||||
FD_SET (s, &writefds);
|
||||
FD_ZERO (&exceptfds);
|
||||
FD_SET (s, &exceptfds);
|
||||
ret = select (s + 1, NULL, &writefds, &exceptfds, timeout);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Error */
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
if (ret == 0)
|
||||
{
|
||||
/* Timed out */
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check the socket state */
|
||||
optlen = sizeof(optval);
|
||||
if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen) != 0)
|
||||
optlen = sizeof (optval);
|
||||
if (getsockopt (s, SOL_SOCKET, SO_ERROR, (void *) &optval, &optlen) != 0)
|
||||
return -1;
|
||||
|
||||
if (optval != 0) {
|
||||
if (optval != 0)
|
||||
{
|
||||
/* Connection failed. */
|
||||
errno = optval;
|
||||
return -1;
|
||||
@@ -102,7 +110,8 @@ int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
|
||||
|
||||
/* On Windows, SO_ERROR sometimes shows no error but the connection
|
||||
still failed. Sigh. */
|
||||
if (FD_ISSET(s, &exceptfds) || !FD_ISSET(s, &writefds)) {
|
||||
if (FD_ISSET (s, &exceptfds) || !FD_ISSET (s, &writefds))
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
@@ -114,92 +123,104 @@ int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
|
||||
/* Like send(2), but with a timeout. Socket must be non-blocking.
|
||||
The timeout only applies if no data at all is sent -- this function
|
||||
may still send less than requested. */
|
||||
ssize_t send_timeout(int s, const void *buf, size_t len, int flags,
|
||||
struct timeval *timeout)
|
||||
ssize_t
|
||||
send_timeout (int s, const void *buf, size_t len, int flags,
|
||||
struct timeval * timeout)
|
||||
{
|
||||
fd_set writefds;
|
||||
int ret;
|
||||
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(s, &writefds);
|
||||
ret = select(s + 1, NULL, &writefds, NULL, timeout);
|
||||
if (ret == 0) {
|
||||
FD_ZERO (&writefds);
|
||||
FD_SET (s, &writefds);
|
||||
ret = select (s + 1, NULL, &writefds, NULL, timeout);
|
||||
if (ret == 0)
|
||||
{
|
||||
/* Timed out */
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
if (ret != 1) {
|
||||
if (ret != 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.
|
||||
The timeout only applies if no data at all is received -- this
|
||||
function may still return less than requested. */
|
||||
ssize_t recv_timeout(int s, void *buf, size_t len, int flags,
|
||||
struct timeval *timeout)
|
||||
ssize_t
|
||||
recv_timeout (int s, void *buf, size_t len, int flags,
|
||||
struct timeval * timeout)
|
||||
{
|
||||
fd_set readfds;
|
||||
int ret;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(s, &readfds);
|
||||
ret = select(s + 1, &readfds, NULL, NULL, timeout);
|
||||
if (ret == 0) {
|
||||
FD_ZERO (&readfds);
|
||||
FD_SET (s, &readfds);
|
||||
ret = select (s + 1, &readfds, NULL, NULL, timeout);
|
||||
if (ret == 0)
|
||||
{
|
||||
/* Timed out */
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
if (ret != 1) {
|
||||
if (ret != 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.
|
||||
The timeout only applies if no data at all is received -- this
|
||||
function may still return less than requested. */
|
||||
ssize_t recvfrom_timeout(int s, void *buf, size_t len, int flags, struct sockaddr *address, socklen_t *address_len,
|
||||
struct timeval *timeout)
|
||||
ssize_t
|
||||
recvfrom_timeout (int s, void *buf, size_t len, int flags,
|
||||
struct sockaddr * address, socklen_t * address_len,
|
||||
struct timeval * timeout)
|
||||
{
|
||||
fd_set readfds;
|
||||
int ret;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(s, &readfds);
|
||||
ret = select(s + 1, &readfds, NULL, NULL, timeout);
|
||||
if (ret == 0) {
|
||||
FD_ZERO (&readfds);
|
||||
FD_SET (s, &readfds);
|
||||
ret = select (s + 1, &readfds, NULL, NULL, timeout);
|
||||
if (ret == 0)
|
||||
{
|
||||
/* Timed out */
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
if (ret != 1) {
|
||||
if (ret != 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
|
||||
partial transfers. This is a stronger attempt to send all
|
||||
requested data. */
|
||||
ssize_t send_all_timeout(int s, const void *buf, size_t len, int flags,
|
||||
struct timeval *timeout)
|
||||
ssize_t
|
||||
send_all_timeout (int s, const void *buf, size_t len, int flags,
|
||||
struct timeval * timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
size_t left = len;
|
||||
ssize_t ret;
|
||||
|
||||
while (left > 0) {
|
||||
while (left > 0)
|
||||
{
|
||||
tv.tv_sec = timeout->tv_sec;
|
||||
tv.tv_usec = timeout->tv_usec;
|
||||
ret = send_timeout(s, buf, left, flags, &tv);
|
||||
ret = send_timeout (s, buf, left, flags, &tv);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -217,17 +238,19 @@ ssize_t send_all_timeout(int s, const void *buf, size_t len, int flags,
|
||||
/* Like recv_timeout, but retries (with the same timeout) in case of
|
||||
partial transfers. This is a stronger attempt to recv all
|
||||
requested data. */
|
||||
ssize_t recv_all_timeout(int s, void *buf, size_t len, int flags,
|
||||
struct timeval *timeout)
|
||||
ssize_t
|
||||
recv_all_timeout (int s, void *buf, size_t len, int flags,
|
||||
struct timeval * timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
size_t left = len;
|
||||
ssize_t ret;
|
||||
|
||||
while (left > 0) {
|
||||
while (left > 0)
|
||||
{
|
||||
tv.tv_sec = timeout->tv_sec;
|
||||
tv.tv_usec = timeout->tv_usec;
|
||||
ret = recv_timeout(s, buf, left, flags, &tv);
|
||||
ret = recv_timeout (s, buf, left, flags, &tv);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
27
netutil.h
27
netutil.h
@@ -11,35 +11,44 @@
|
||||
# define socklen_t int
|
||||
# define in_addr_t uint32_t
|
||||
# define in_port_t uint16_t
|
||||
# include <windows.h>
|
||||
# include <iphlpapi.h>
|
||||
# define USE_IPHLPAPI 1
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
# include <net/if.h>
|
||||
# include <sys/ioctl.h>
|
||||
#ifndef _SIZEOF_ADDR_IFREQ
|
||||
#define _SIZEOF_ADDR_IFREQ(x) sizeof(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Initialize networking */
|
||||
void net_init(void);
|
||||
void net_init (void);
|
||||
|
||||
/* Set socket blocking/nonblocking */
|
||||
int soblock(int socket, int blocking);
|
||||
int soblock (int socket, int blocking);
|
||||
|
||||
/* Like send(2), recv(2), connect(2), but with timeouts.
|
||||
Socket must be O_NONBLOCK. */
|
||||
int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
|
||||
int connect_timeout (int s, const struct sockaddr *serv_addr,
|
||||
socklen_t addrlen, struct timeval *timeout);
|
||||
ssize_t send_timeout (int s, const void *buf, size_t len, int flags,
|
||||
struct timeval *timeout);
|
||||
ssize_t send_timeout(int s, const void *buf, size_t len, int flags,
|
||||
ssize_t recv_timeout (int s, void *buf, size_t len, int flags,
|
||||
struct timeval *timeout);
|
||||
ssize_t recv_timeout(int s, void *buf, size_t len, int flags,
|
||||
struct timeval *timeout);
|
||||
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 sockaddr *address, socklen_t * address_len,
|
||||
struct timeval *timeout);
|
||||
|
||||
/* Like send_timeout and recv_timeout, but they retry (with the same timeout)
|
||||
in case of partial transfers, in order to try to transfer all data. */
|
||||
ssize_t send_all_timeout(int s, const void *buf, size_t len, int flags,
|
||||
ssize_t send_all_timeout (int s, const void *buf, size_t len, int flags,
|
||||
struct timeval *timeout);
|
||||
ssize_t recv_all_timeout(int s, void *buf, size_t len, int flags,
|
||||
ssize_t recv_all_timeout (int s, void *buf, size_t len, int flags,
|
||||
struct timeval *timeout);
|
||||
|
||||
#endif
|
||||
|
101
opt.c
101
opt.c
@@ -11,85 +11,98 @@
|
||||
#include <string.h>
|
||||
#include "opt.h"
|
||||
|
||||
void opt_init(int *optind) {
|
||||
*optind=0;
|
||||
void
|
||||
opt_init (int *optind)
|
||||
{
|
||||
*optind = 0;
|
||||
}
|
||||
|
||||
char opt_parse(int argc, char **argv, int *optind, char **optarg,
|
||||
struct options *opt) {
|
||||
char
|
||||
opt_parse (int argc, char **argv, int *optind, char **optarg,
|
||||
struct options *opt)
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
(*optind)++;
|
||||
if(*optind>=argc)
|
||||
if (*optind >= argc)
|
||||
return 0;
|
||||
|
||||
if(argv[*optind][0]=='-' &&
|
||||
argv[*optind][1]!='-' &&
|
||||
argv[*optind][1]!=0) {
|
||||
if (argv[*optind][0] == '-' &&
|
||||
argv[*optind][1] != '-' && argv[*optind][1] != 0)
|
||||
{
|
||||
/* Short option (or a bunch of 'em) */
|
||||
/* Save this and shift others over */
|
||||
c=argv[*optind][1];
|
||||
for(i=2;argv[*optind][i]!=0;i++)
|
||||
argv[*optind][i-1]=argv[*optind][i];
|
||||
argv[*optind][i-1]=0;
|
||||
if(argv[*optind][1]!=0)
|
||||
c = argv[*optind][1];
|
||||
for (i = 2; argv[*optind][i] != 0; i++)
|
||||
argv[*optind][i - 1] = argv[*optind][i];
|
||||
argv[*optind][i - 1] = 0;
|
||||
if (argv[*optind][1] != 0)
|
||||
(*optind)--;
|
||||
/* Now find it */
|
||||
for(i=0;opt[i].shortopt!=0;i++)
|
||||
if(opt[i].shortopt==c)
|
||||
for (i = 0; opt[i].shortopt != 0; i++)
|
||||
if (opt[i].shortopt == c)
|
||||
break;
|
||||
if(opt[i].shortopt==0) {
|
||||
fprintf(stderr,"Error: unknown option '-%c'\n",c);
|
||||
if (opt[i].shortopt == 0)
|
||||
{
|
||||
fprintf (stderr, "Error: unknown option '-%c'\n", c);
|
||||
return '?';
|
||||
}
|
||||
if(opt[i].arg==NULL)
|
||||
if (opt[i].arg == NULL)
|
||||
return c;
|
||||
(*optind)++;
|
||||
if(*optind>=argc || (argv[*optind][0]=='-' &&
|
||||
argv[*optind][1]!=0)) {
|
||||
fprintf(stderr,"Error: option '-%c' requires an "
|
||||
"argument\n",c);
|
||||
if (*optind >= argc || (argv[*optind][0] == '-' &&
|
||||
argv[*optind][1] != 0))
|
||||
{
|
||||
fprintf (stderr, "Error: option '-%c' requires an "
|
||||
"argument\n", c);
|
||||
return '?';
|
||||
}
|
||||
(*optarg)=argv[*optind];
|
||||
(*optarg) = argv[*optind];
|
||||
return c;
|
||||
} else if(argv[*optind][0]=='-' &&
|
||||
argv[*optind][1]=='-' &&
|
||||
argv[*optind][2]!=0) {
|
||||
}
|
||||
else if (argv[*optind][0] == '-' &&
|
||||
argv[*optind][1] == '-' && argv[*optind][2] != 0)
|
||||
{
|
||||
/* Long option */
|
||||
for(i=0;(c=opt[i].shortopt)!=0;i++)
|
||||
if(strcmp(opt[i].longopt,argv[*optind]+2)==0)
|
||||
for (i = 0; (c = opt[i].shortopt) != 0; i++)
|
||||
if (strcmp (opt[i].longopt, argv[*optind] + 2) == 0)
|
||||
break;
|
||||
if(opt[i].shortopt==0) {
|
||||
fprintf(stderr,"Error: unknown option '%s'\n",
|
||||
argv[*optind]);
|
||||
if (opt[i].shortopt == 0)
|
||||
{
|
||||
fprintf (stderr, "Error: unknown option '%s'\n", argv[*optind]);
|
||||
return '?';
|
||||
}
|
||||
if(opt[i].arg==NULL)
|
||||
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]);
|
||||
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];
|
||||
(*optarg) = argv[*optind];
|
||||
return c;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* End of options */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void opt_help(struct options *opt, FILE *out) {
|
||||
void
|
||||
opt_help (struct options *opt, FILE * out)
|
||||
{
|
||||
int i;
|
||||
int printed;
|
||||
|
||||
for(i=0;opt[i].shortopt!=0;i++) {
|
||||
fprintf(out," -%c, --%s%n",opt[i].shortopt,
|
||||
opt[i].longopt,&printed);
|
||||
fprintf(out," %-*s%s\n",30-printed,
|
||||
opt[i].arg?opt[i].arg:"",opt[i].help);
|
||||
for (i = 0; opt[i].shortopt != 0; i++)
|
||||
{
|
||||
fprintf (out, " -%c, --%s%n", opt[i].shortopt,
|
||||
opt[i].longopt, &printed);
|
||||
fprintf (out, " %-*s%s\n", 30 - printed,
|
||||
opt[i].arg ? opt[i].arg : "", opt[i].help);
|
||||
}
|
||||
}
|
||||
|
9
opt.h
9
opt.h
@@ -11,18 +11,19 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
struct options {
|
||||
struct options
|
||||
{
|
||||
char shortopt;
|
||||
char *longopt;
|
||||
char *arg;
|
||||
char *help;
|
||||
};
|
||||
|
||||
void opt_init(int *optind);
|
||||
void opt_init (int *optind);
|
||||
|
||||
char opt_parse(int argc, char **argv, int *optind, char **optarg,
|
||||
char opt_parse (int argc, char **argv, int *optind, char **optarg,
|
||||
struct options *opt);
|
||||
|
||||
void opt_help(struct options *opt, FILE *out);
|
||||
void opt_help (struct options *opt, FILE * out);
|
||||
|
||||
#endif
|
||||
|
504
ue9.c
504
ue9.c
@@ -28,13 +28,15 @@
|
||||
#define UE9_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
|
||||
|
||||
/* Fill checksums in data buffers, with "normal" checksum format */
|
||||
void ue9_checksum_normal(uint8_t *buffer, size_t len)
|
||||
void
|
||||
ue9_checksum_normal (uint8_t * buffer, size_t len)
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
|
||||
if (len < 1) {
|
||||
fprintf(stderr, "ue9_checksum_normal: len too short\n");
|
||||
exit(1);
|
||||
if (len < 1)
|
||||
{
|
||||
fprintf (stderr, "ue9_checksum_normal: len too short\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
while (--len >= 1)
|
||||
@@ -45,13 +47,15 @@ void ue9_checksum_normal(uint8_t *buffer, size_t len)
|
||||
}
|
||||
|
||||
/* Fill checksums in data buffers, with "extended" checksum format */
|
||||
void ue9_checksum_extended(uint8_t *buffer, size_t len)
|
||||
void
|
||||
ue9_checksum_extended (uint8_t * buffer, size_t len)
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
|
||||
if (len < 6) {
|
||||
fprintf(stderr, "ue9_checksum_extended: len too short\n");
|
||||
exit(1);
|
||||
if (len < 6)
|
||||
{
|
||||
fprintf (stderr, "ue9_checksum_extended: len too short\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* 16-bit extended checksum */
|
||||
@@ -61,27 +65,29 @@ void ue9_checksum_extended(uint8_t *buffer, size_t len)
|
||||
buffer[5] = (uint8_t) (sum >> 8);
|
||||
|
||||
/* 8-bit normal checksum over first 6 bytes */
|
||||
ue9_checksum_normal(buffer, 6);
|
||||
ue9_checksum_normal (buffer, 6);
|
||||
}
|
||||
|
||||
/* Verify checksums in data buffers, with "normal" checksum format. */
|
||||
int ue9_verify_normal(uint8_t *buffer, size_t len)
|
||||
int
|
||||
ue9_verify_normal (uint8_t * buffer, size_t len)
|
||||
{
|
||||
uint8_t saved, new;
|
||||
|
||||
if (len < 1) {
|
||||
fprintf(stderr, "ue9_verify_normal: len too short\n");
|
||||
exit(1);
|
||||
if (len < 1)
|
||||
{
|
||||
fprintf (stderr, "ue9_verify_normal: len too short\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
saved = buffer[0];
|
||||
ue9_checksum_normal(buffer, len);
|
||||
ue9_checksum_normal (buffer, len);
|
||||
new = buffer[0];
|
||||
buffer[0] = saved;
|
||||
|
||||
if (new != saved) {
|
||||
verb("got %02x, expected %02x\n",
|
||||
saved, new);
|
||||
if (new != saved)
|
||||
{
|
||||
verb ("got %02x, expected %02x\n", saved, new);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -89,19 +95,21 @@ int ue9_verify_normal(uint8_t *buffer, size_t len)
|
||||
}
|
||||
|
||||
/* Verify checksums in data buffers, with "extended" checksum format. */
|
||||
int ue9_verify_extended(uint8_t *buffer, size_t len)
|
||||
int
|
||||
ue9_verify_extended (uint8_t * buffer, size_t len)
|
||||
{
|
||||
uint8_t saved[3], new[3];
|
||||
|
||||
if (len < 6) {
|
||||
fprintf(stderr, "ue9_verify_extended: len too short\n");
|
||||
exit(1);
|
||||
if (len < 6)
|
||||
{
|
||||
fprintf (stderr, "ue9_verify_extended: len too short\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
saved[0] = buffer[0];
|
||||
saved[1] = buffer[4];
|
||||
saved[2] = buffer[5];
|
||||
ue9_checksum_extended(buffer, len);
|
||||
ue9_checksum_extended (buffer, len);
|
||||
new[0] = buffer[0];
|
||||
new[1] = buffer[4];
|
||||
new[2] = buffer[5];
|
||||
@@ -109,10 +117,9 @@ int ue9_verify_extended(uint8_t *buffer, size_t len)
|
||||
buffer[4] = saved[1];
|
||||
buffer[5] = saved[2];
|
||||
|
||||
if (saved[0] != new[0] ||
|
||||
saved[1] != new[1] ||
|
||||
saved[2] != new[2]) {
|
||||
verb("got %02x %02x %02x, expected %02x %02x %02x\n",
|
||||
if (saved[0] != new[0] || saved[1] != new[1] || saved[2] != new[2])
|
||||
{
|
||||
verb ("got %02x %02x %02x, expected %02x %02x %02x\n",
|
||||
saved[0], saved[1], saved[2], new[0], new[1], new[2]);
|
||||
return 0;
|
||||
}
|
||||
@@ -121,41 +128,54 @@ int ue9_verify_extended(uint8_t *buffer, size_t len)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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) {
|
||||
fprintf(stderr, "ue9_binary_to_analog: bad gain\n");
|
||||
exit(1);
|
||||
if (gain >= ARRAY_SIZE (uncal) || uncal[gain] == 0)
|
||||
{
|
||||
fprintf (stderr, "ue9_binary_to_analog: bad gain\n");
|
||||
exit (1);
|
||||
}
|
||||
return data * uncal[gain] / 65536.0;
|
||||
}
|
||||
|
||||
if (resolution < 18) {
|
||||
if (gain <= 3) {
|
||||
if (resolution < 18)
|
||||
{
|
||||
if (gain <= 3)
|
||||
{
|
||||
slope = calib->unipolarSlope[gain];
|
||||
offset = calib->unipolarOffset[gain];
|
||||
} else if (gain == 8) {
|
||||
}
|
||||
else if (gain == 8)
|
||||
{
|
||||
slope = calib->bipolarSlope;
|
||||
offset = calib->bipolarOffset;
|
||||
}
|
||||
} else {
|
||||
if (gain == 0) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gain == 0)
|
||||
{
|
||||
slope = calib->hiResUnipolarSlope;
|
||||
offset = calib->hiResUnipolarOffset;
|
||||
} else if (gain == 8) {
|
||||
}
|
||||
else if (gain == 8)
|
||||
{
|
||||
slope = calib->hiResBipolarSlope;
|
||||
offset = calib->hiResBipolarOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if (slope == 0) {
|
||||
fprintf(stderr, "ue9_binary_to_analog: bad gain\n");
|
||||
exit(1);
|
||||
if (slope == 0)
|
||||
{
|
||||
fprintf (stderr, "ue9_binary_to_analog: bad gain\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
return data * slope + offset;
|
||||
@@ -165,7 +185,8 @@ double ue9_binary_to_analog(struct ue9Calibration *calib,
|
||||
checksums on the outgoing packets, and verifies them on the
|
||||
incoming packets. Data in "out" is transmitted, data in "in" is
|
||||
received. */
|
||||
int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen)
|
||||
int
|
||||
ue9_command (int fd, uint8_t * out, uint8_t * in, int inlen)
|
||||
{
|
||||
int extended = 0, outlen;
|
||||
uint8_t saved_1, saved_3;
|
||||
@@ -175,19 +196,24 @@ int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen)
|
||||
extended = 1;
|
||||
|
||||
/* Figure out length of data payload, and fill checksums. */
|
||||
if (extended) {
|
||||
if (extended)
|
||||
{
|
||||
outlen = 6 + (out[2]) * 2;
|
||||
ue9_checksum_extended(out, outlen);
|
||||
} else {
|
||||
ue9_checksum_extended (out, outlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
outlen = 2 + (out[1] & 7) * 2;
|
||||
ue9_checksum_normal(out, outlen);
|
||||
ue9_checksum_normal (out, outlen);
|
||||
}
|
||||
|
||||
/* Send request */
|
||||
ret = send_all_timeout(fd, out, outlen, 0,
|
||||
& (struct timeval) { .tv_sec = UE9_TIMEOUT });
|
||||
if (ret < 0 || ret != outlen) {
|
||||
verb("short send %d\n", (int)ret);
|
||||
ret = send_all_timeout (fd, out, outlen, 0, &(struct timeval)
|
||||
{
|
||||
.tv_sec = UE9_TIMEOUT});
|
||||
if (ret < 0 || ret != outlen)
|
||||
{
|
||||
verb ("short send %d\n", (int) ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -198,26 +224,28 @@ int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen)
|
||||
saved_3 = out[3];
|
||||
|
||||
/* Receive result */
|
||||
ret = recv_all_timeout(fd, in, inlen, 0,
|
||||
& (struct timeval) { .tv_sec = UE9_TIMEOUT });
|
||||
if (ret < 0 || ret != inlen) {
|
||||
verb("short recv %d\n", (int)ret);
|
||||
ret = recv_all_timeout (fd, in, inlen, 0, &(struct timeval)
|
||||
{
|
||||
.tv_sec = UE9_TIMEOUT});
|
||||
if (ret < 0 || ret != inlen)
|
||||
{
|
||||
verb ("short recv %d\n", (int) ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Verify it */
|
||||
if ((in[1] & 0xF8) != (saved_1 & 0xF8))
|
||||
verb("returned command doesn't match\n");
|
||||
verb ("returned command doesn't match\n");
|
||||
else if (extended && (in[3] != saved_3))
|
||||
verb("extended command doesn't match\n");
|
||||
verb ("extended command doesn't match\n");
|
||||
else if (extended && (inlen != (6 + (in[2]) * 2)))
|
||||
verb("returned extended data is the wrong len\n");
|
||||
verb ("returned extended data is the wrong len\n");
|
||||
else if (!extended && (inlen != (2 + (in[1] & 7) * 2)))
|
||||
verb("returned data is the wrong len\n");
|
||||
else if (extended && !ue9_verify_extended(in, inlen))
|
||||
verb("extended checksum is invalid\n");
|
||||
else if (!ue9_verify_normal(in, extended ? 6 : inlen))
|
||||
verb("normal checksum is invalid\n");
|
||||
verb ("returned data is the wrong len\n");
|
||||
else if (extended && !ue9_verify_extended (in, inlen))
|
||||
verb ("extended checksum is invalid\n");
|
||||
else if (!ue9_verify_normal (in, extended ? 6 : inlen))
|
||||
verb ("normal checksum is invalid\n");
|
||||
else
|
||||
return 0; /* looks good */
|
||||
|
||||
@@ -226,13 +254,15 @@ int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen)
|
||||
|
||||
|
||||
/* Read a memory block from the device. Returns -1 on error. */
|
||||
int ue9_memory_read(int fd, int blocknum, uint8_t *buffer, int len)
|
||||
int
|
||||
ue9_memory_read (int fd, int blocknum, uint8_t * buffer, int len)
|
||||
{
|
||||
uint8_t sendbuf[8], recvbuf[136];
|
||||
|
||||
if (len != 128) {
|
||||
fprintf(stderr,"ue9_memory_read: buffer length must be 128\n");
|
||||
exit(1);
|
||||
if (len != 128)
|
||||
{
|
||||
fprintf (stderr, "ue9_memory_read: buffer length must be 128\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Request memory block */
|
||||
@@ -242,19 +272,21 @@ int ue9_memory_read(int fd, int blocknum, uint8_t *buffer, int len)
|
||||
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)
|
||||
{
|
||||
verb ("command failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Got it */
|
||||
memcpy(buffer, recvbuf + 8, len);
|
||||
memcpy (buffer, recvbuf + 8, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert 64-bit fixed point to double type */
|
||||
double ue9_fp64_to_double(uint8_t *data)
|
||||
double
|
||||
ue9_fp64_to_double (uint8_t * data)
|
||||
{
|
||||
int32_t a;
|
||||
uint32_t b;
|
||||
@@ -262,143 +294,160 @@ double ue9_fp64_to_double(uint8_t *data)
|
||||
a = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
|
||||
b = (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0];
|
||||
|
||||
return (double)a + (double)b / (double)4294967296.0L;
|
||||
return (double) a + (double) b / (double) 4294967296.0L;
|
||||
}
|
||||
|
||||
/* Retrieve calibration data from the device. Returns -1 on error. */
|
||||
int ue9_get_calibration(int fd, struct ue9Calibration *calib)
|
||||
int
|
||||
ue9_get_calibration (int fd, struct ue9Calibration *calib)
|
||||
{
|
||||
uint8_t buf[128];
|
||||
|
||||
/* Block 0 */
|
||||
if (ue9_memory_read(fd, 0, buf, 128) < 0) return -1;
|
||||
calib->unipolarSlope[0] = ue9_fp64_to_double(buf + 0);
|
||||
calib->unipolarOffset[0] = ue9_fp64_to_double(buf + 8);
|
||||
calib->unipolarSlope[1] = ue9_fp64_to_double(buf + 16);
|
||||
calib->unipolarOffset[1] = ue9_fp64_to_double(buf + 24);
|
||||
calib->unipolarSlope[2] = ue9_fp64_to_double(buf + 32);
|
||||
calib->unipolarOffset[2] = ue9_fp64_to_double(buf + 40);
|
||||
calib->unipolarSlope[3] = ue9_fp64_to_double(buf + 48);
|
||||
calib->unipolarOffset[3] = ue9_fp64_to_double(buf + 56);
|
||||
if (ue9_memory_read (fd, 0, buf, 128) < 0)
|
||||
return -1;
|
||||
calib->unipolarSlope[0] = ue9_fp64_to_double (buf + 0);
|
||||
calib->unipolarOffset[0] = ue9_fp64_to_double (buf + 8);
|
||||
calib->unipolarSlope[1] = ue9_fp64_to_double (buf + 16);
|
||||
calib->unipolarOffset[1] = ue9_fp64_to_double (buf + 24);
|
||||
calib->unipolarSlope[2] = ue9_fp64_to_double (buf + 32);
|
||||
calib->unipolarOffset[2] = ue9_fp64_to_double (buf + 40);
|
||||
calib->unipolarSlope[3] = ue9_fp64_to_double (buf + 48);
|
||||
calib->unipolarOffset[3] = ue9_fp64_to_double (buf + 56);
|
||||
|
||||
/* Block 1 */
|
||||
if (ue9_memory_read(fd, 1, buf, 128) < 0) return -1;
|
||||
calib->bipolarSlope = ue9_fp64_to_double(buf + 0);
|
||||
calib->bipolarOffset = ue9_fp64_to_double(buf + 8);
|
||||
if (ue9_memory_read (fd, 1, buf, 128) < 0)
|
||||
return -1;
|
||||
calib->bipolarSlope = ue9_fp64_to_double (buf + 0);
|
||||
calib->bipolarOffset = ue9_fp64_to_double (buf + 8);
|
||||
|
||||
/* Block 2 */
|
||||
if (ue9_memory_read(fd, 2, buf, 128) < 0) return -1;
|
||||
calib->DACSlope[0] = ue9_fp64_to_double(buf + 0);
|
||||
calib->DACOffset[0] = ue9_fp64_to_double(buf + 8);
|
||||
calib->DACSlope[1] = ue9_fp64_to_double(buf + 16);
|
||||
calib->DACOffset[1] = ue9_fp64_to_double(buf + 24);
|
||||
calib->tempSlope = ue9_fp64_to_double(buf + 32);
|
||||
calib->tempSlopeLow = ue9_fp64_to_double(buf + 48);
|
||||
calib->calTemp = ue9_fp64_to_double(buf + 64);
|
||||
calib->Vref = ue9_fp64_to_double(buf + 72);
|
||||
calib->VrefDiv2 = ue9_fp64_to_double(buf + 88);
|
||||
calib->VsSlope = ue9_fp64_to_double(buf + 96);
|
||||
if (ue9_memory_read (fd, 2, buf, 128) < 0)
|
||||
return -1;
|
||||
calib->DACSlope[0] = ue9_fp64_to_double (buf + 0);
|
||||
calib->DACOffset[0] = ue9_fp64_to_double (buf + 8);
|
||||
calib->DACSlope[1] = ue9_fp64_to_double (buf + 16);
|
||||
calib->DACOffset[1] = ue9_fp64_to_double (buf + 24);
|
||||
calib->tempSlope = ue9_fp64_to_double (buf + 32);
|
||||
calib->tempSlopeLow = ue9_fp64_to_double (buf + 48);
|
||||
calib->calTemp = ue9_fp64_to_double (buf + 64);
|
||||
calib->Vref = ue9_fp64_to_double (buf + 72);
|
||||
calib->VrefDiv2 = ue9_fp64_to_double (buf + 88);
|
||||
calib->VsSlope = ue9_fp64_to_double (buf + 96);
|
||||
|
||||
/* Block 3 */
|
||||
if (ue9_memory_read(fd, 3, buf, 128) < 0) return -1;
|
||||
calib->hiResUnipolarSlope = ue9_fp64_to_double(buf + 0);
|
||||
calib->hiResUnipolarOffset = ue9_fp64_to_double(buf + 8);
|
||||
if (ue9_memory_read (fd, 3, buf, 128) < 0)
|
||||
return -1;
|
||||
calib->hiResUnipolarSlope = ue9_fp64_to_double (buf + 0);
|
||||
calib->hiResUnipolarOffset = ue9_fp64_to_double (buf + 8);
|
||||
|
||||
/* Block 4 */
|
||||
if (ue9_memory_read(fd, 4, buf, 128) < 0) return -1;
|
||||
calib->hiResBipolarSlope = ue9_fp64_to_double(buf + 0);
|
||||
calib->hiResBipolarOffset = ue9_fp64_to_double(buf + 8);
|
||||
if (ue9_memory_read (fd, 4, buf, 128) < 0)
|
||||
return -1;
|
||||
calib->hiResBipolarSlope = ue9_fp64_to_double (buf + 0);
|
||||
calib->hiResBipolarOffset = ue9_fp64_to_double (buf + 8);
|
||||
|
||||
/* All done */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Retrieve comm config, returns -1 on error */
|
||||
int ue9_get_comm_config(int fd, struct ue9CommConfig *config)
|
||||
int
|
||||
ue9_get_comm_config (int fd, struct ue9CommConfig *config)
|
||||
{
|
||||
uint8_t sendbuf[18];
|
||||
uint8_t recvbuf[24];
|
||||
|
||||
memset(sendbuf, 0, sizeof(sendbuf));
|
||||
memset(config, 0, sizeof(struct ue9CommConfig));
|
||||
memset (sendbuf, 0, sizeof (sendbuf));
|
||||
memset (config, 0, sizeof (struct ue9CommConfig));
|
||||
|
||||
sendbuf[1] = 0xf8;
|
||||
sendbuf[2] = 0x09;
|
||||
sendbuf[3] = 0x08;
|
||||
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
|
||||
verb("command failed\n");
|
||||
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
|
||||
{
|
||||
verb ("command failed\n");
|
||||
return -1;
|
||||
}
|
||||
verb("todo\n");
|
||||
verb ("todo\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Retrieve control config, returns -1 on error */
|
||||
int ue9_get_control_config(int fd, struct ue9ControlConfig *config)
|
||||
int
|
||||
ue9_get_control_config (int fd, struct ue9ControlConfig *config)
|
||||
{
|
||||
uint8_t sendbuf[18];
|
||||
uint8_t recvbuf[24];
|
||||
|
||||
memset(sendbuf, 0, sizeof(sendbuf));
|
||||
memset(config, 0, sizeof(struct ue9ControlConfig));
|
||||
memset (sendbuf, 0, sizeof (sendbuf));
|
||||
memset (config, 0, sizeof (struct ue9ControlConfig));
|
||||
|
||||
sendbuf[1] = 0xf8;
|
||||
sendbuf[2] = 0x06;
|
||||
sendbuf[3] = 0x08;
|
||||
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
|
||||
verb("command failed\n");
|
||||
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
|
||||
{
|
||||
verb ("command failed\n");
|
||||
return -1;
|
||||
}
|
||||
verb("todo\n");
|
||||
verb ("todo\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open TCP/IP connection to the UE9 */
|
||||
int ue9_open(const char *host, int port)
|
||||
int
|
||||
ue9_open (const char *host, int port)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in address;
|
||||
struct hostent *he;
|
||||
int window_size = 128 * 1024;
|
||||
|
||||
net_init();
|
||||
net_init ();
|
||||
|
||||
/* Create socket */
|
||||
fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (fd < 0) {
|
||||
verb("socket returned %d\n", fd);
|
||||
fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (fd < 0)
|
||||
{
|
||||
verb ("socket returned %d\n", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set nonblocking */
|
||||
if (soblock(fd, 0) < 0) {
|
||||
verb("can't set nonblocking\n");
|
||||
if (soblock (fd, 0) < 0)
|
||||
{
|
||||
verb ("can't set nonblocking\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set initial window size hint to workaround LabJack firmware bug */
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *)&window_size,
|
||||
sizeof(window_size));
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&window_size,
|
||||
sizeof(window_size));
|
||||
setsockopt (fd, SOL_SOCKET, SO_SNDBUF, (void *) &window_size,
|
||||
sizeof (window_size));
|
||||
setsockopt (fd, SOL_SOCKET, SO_RCVBUF, (void *) &window_size,
|
||||
sizeof (window_size));
|
||||
|
||||
/* Resolve host */
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(port);
|
||||
he = gethostbyname(host);
|
||||
if (he == NULL) {
|
||||
verb("gethostbyname(\"%s\") failed\n", host);
|
||||
address.sin_port = htons (port);
|
||||
he = gethostbyname (host);
|
||||
if (he == NULL)
|
||||
{
|
||||
verb ("gethostbyname(\"%s\") failed\n", host);
|
||||
return -1;
|
||||
}
|
||||
address.sin_addr = *((struct in_addr *) he->h_addr);
|
||||
|
||||
debug("Resolved %s -> %s\n", host, inet_ntoa(address.sin_addr));
|
||||
debug ("Resolved %s -> %s\n", host, inet_ntoa (address.sin_addr));
|
||||
|
||||
/* Connect */
|
||||
if (connect_timeout(fd, (struct sockaddr *) &address, sizeof(address),
|
||||
& (struct timeval) { .tv_sec = UE9_TIMEOUT }) < 0) {
|
||||
verb("connection to %s:%d failed: %s\n",
|
||||
inet_ntoa(address.sin_addr), port, compat_strerror(errno));
|
||||
if (connect_timeout (fd, (struct sockaddr *) &address, sizeof (address),
|
||||
&(struct timeval)
|
||||
{
|
||||
.tv_sec = UE9_TIMEOUT}) < 0)
|
||||
{
|
||||
verb ("connection to %s:%d failed: %s\n",
|
||||
inet_ntoa (address.sin_addr), port, compat_strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -406,15 +455,17 @@ int ue9_open(const char *host, int port)
|
||||
}
|
||||
|
||||
/* Close connection to the UE9 */
|
||||
void ue9_close(int fd)
|
||||
void
|
||||
ue9_close (int fd)
|
||||
{
|
||||
/* does anyone actually call shutdown these days? */
|
||||
shutdown(fd, 2 /* SHUT_RDWR */);
|
||||
close(fd);
|
||||
shutdown (fd, 2 /* SHUT_RDWR */ );
|
||||
close (fd);
|
||||
}
|
||||
|
||||
/* Compute scanrate based on the provided values. */
|
||||
double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval)
|
||||
double
|
||||
ue9_compute_rate (uint8_t scanconfig, uint16_t scaninterval)
|
||||
{
|
||||
double clock;
|
||||
|
||||
@@ -422,11 +473,20 @@ double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval)
|
||||
a fixed rate, and not affected by the number of channels.
|
||||
Channels are scanned as quickly as possible. */
|
||||
|
||||
switch ((scanconfig >> 3) & 3) {
|
||||
case 0: clock = 4e6; break;
|
||||
case 1: clock = 48e6; break;
|
||||
case 2: clock = 750e3; break;
|
||||
case 3: clock = 24e6; break;
|
||||
switch ((scanconfig >> 3) & 3)
|
||||
{
|
||||
case 0:
|
||||
clock = 4e6;
|
||||
break;
|
||||
case 1:
|
||||
clock = 48e6;
|
||||
break;
|
||||
case 2:
|
||||
clock = 750e3;
|
||||
break;
|
||||
case 3:
|
||||
clock = 24e6;
|
||||
break;
|
||||
}
|
||||
|
||||
if (scanconfig & 0x2)
|
||||
@@ -440,39 +500,55 @@ double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval)
|
||||
|
||||
/* Choose the best ScanConfig and ScanInterval parameters for the
|
||||
desired scanrate. Returns -1 if no valid config found */
|
||||
int ue9_choose_scan(double desired_rate, double *actual_rate,
|
||||
uint8_t *scanconfig, uint16_t *scaninterval)
|
||||
int
|
||||
ue9_choose_scan (double desired_rate, double *actual_rate,
|
||||
uint8_t * scanconfig, uint16_t * scaninterval)
|
||||
{
|
||||
int i;
|
||||
struct { double clock; uint8_t config; } valid[] = {
|
||||
{ 48e6, 0x08 },
|
||||
{ 24e6, 0x18 },
|
||||
{ 4e6, 0x00 },
|
||||
{ 750e3, 0x10 },
|
||||
{ 48e6 / 256, 0x0a },
|
||||
{ 24e6 / 256, 0x1a },
|
||||
{ 4e6 / 256, 0x02 },
|
||||
{ 750e3 / 256, 0x12 },
|
||||
{ 0, 0 } };
|
||||
struct
|
||||
{
|
||||
double clock;
|
||||
uint8_t config;
|
||||
} valid[] =
|
||||
{
|
||||
{
|
||||
48e6, 0x08},
|
||||
{
|
||||
24e6, 0x18},
|
||||
{
|
||||
4e6, 0x00},
|
||||
{
|
||||
750e3, 0x10},
|
||||
{
|
||||
48e6 / 256, 0x0a},
|
||||
{
|
||||
24e6 / 256, 0x1a},
|
||||
{
|
||||
4e6 / 256, 0x02},
|
||||
{
|
||||
750e3 / 256, 0x12},
|
||||
{
|
||||
0, 0}};
|
||||
|
||||
/* Start with the fastest clock frequency. If the
|
||||
scaninterval would be too large, knock it down until it
|
||||
fits. */
|
||||
for (i = 0; valid[i].clock != 0; i++) {
|
||||
for (i = 0; valid[i].clock != 0; i++)
|
||||
{
|
||||
double interval = valid[i].clock / desired_rate;
|
||||
|
||||
debug("Considering clock %lf (interval %lf)\n",
|
||||
debug ("Considering clock %lf (interval %lf)\n",
|
||||
valid[i].clock, interval);
|
||||
|
||||
if (interval >= 0.5 && interval < 65535.5) {
|
||||
if (interval >= 0.5 && interval < 65535.5)
|
||||
{
|
||||
|
||||
*scaninterval = floor(interval + 0.5);
|
||||
*scaninterval = floor (interval + 0.5);
|
||||
|
||||
*scanconfig = valid[i].config;
|
||||
*actual_rate = ue9_compute_rate(
|
||||
*scanconfig, *scaninterval);
|
||||
*actual_rate = ue9_compute_rate (*scanconfig, *scaninterval);
|
||||
|
||||
debug("Config 0x%02x, desired %lf, actual %lf\n",
|
||||
debug ("Config 0x%02x, desired %lf, actual %lf\n",
|
||||
*scanconfig, desired_rate, *actual_rate);
|
||||
|
||||
return 0;
|
||||
@@ -483,58 +559,65 @@ int ue9_choose_scan(double desired_rate, double *actual_rate,
|
||||
}
|
||||
|
||||
/* Flush data buffers */
|
||||
void ue9_buffer_flush(int fd)
|
||||
void
|
||||
ue9_buffer_flush (int fd)
|
||||
{
|
||||
uint8_t sendbuf[2], recvbuf[2];
|
||||
|
||||
sendbuf[1] = 0x08; /* FlushBuffer */
|
||||
|
||||
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
|
||||
verb("command failed\n");
|
||||
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
|
||||
{
|
||||
verb ("command failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop stream. Returns < 0 on failure. */
|
||||
int ue9_stream_stop(int fd)
|
||||
int
|
||||
ue9_stream_stop (int fd)
|
||||
{
|
||||
uint8_t sendbuf[2], recvbuf[4];
|
||||
|
||||
sendbuf[1] = 0xB0;
|
||||
|
||||
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
|
||||
verb("command failed\n");
|
||||
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
|
||||
{
|
||||
verb ("command failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (recvbuf[2] == STREAM_NOT_RUNNING || recvbuf[2] == 0)
|
||||
return 0;
|
||||
|
||||
debug("error %s\n", ue9_error(recvbuf[2]));
|
||||
debug ("error %s\n", ue9_error (recvbuf[2]));
|
||||
return -recvbuf[2];
|
||||
}
|
||||
|
||||
/* Start stream. Returns < 0 on failure. */
|
||||
int ue9_stream_start(int fd)
|
||||
int
|
||||
ue9_stream_start (int fd)
|
||||
{
|
||||
uint8_t sendbuf[2], recvbuf[4];
|
||||
|
||||
sendbuf[1] = 0xA8;
|
||||
|
||||
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
|
||||
verb("command failed\n");
|
||||
if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
|
||||
{
|
||||
verb ("command failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (recvbuf[2] == 0)
|
||||
return 0;
|
||||
|
||||
debug("error %s\n", ue9_error(recvbuf[2]));
|
||||
debug ("error %s\n", ue9_error (recvbuf[2]));
|
||||
return -recvbuf[2];
|
||||
}
|
||||
|
||||
/* "Simple" stream configuration, assumes the channels are all
|
||||
configured with the same gain. */
|
||||
int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
|
||||
int
|
||||
ue9_streamconfig_simple (int fd, int *channel_list, int channel_count,
|
||||
uint8_t scanconfig, uint16_t scaninterval,
|
||||
uint8_t gain)
|
||||
{
|
||||
@@ -552,19 +635,22 @@ int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
|
||||
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 */
|
||||
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");
|
||||
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]));
|
||||
if (buf[6] != 0)
|
||||
{
|
||||
verb ("returned error %s\n", ue9_error (buf[6]));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -573,7 +659,8 @@ int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
|
||||
|
||||
/* 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,
|
||||
int
|
||||
ue9_stream_data (int fd, int channels,
|
||||
ue9_stream_cb_t callback, void *context)
|
||||
{
|
||||
int ret;
|
||||
@@ -583,68 +670,77 @@ int ue9_stream_data(int fd, int channels,
|
||||
int i;
|
||||
uint16_t data[channels];
|
||||
|
||||
for (;;) {
|
||||
for (;;)
|
||||
{
|
||||
/* Receive data */
|
||||
ret = recv_all_timeout(fd, buf, 46, 0, & (struct timeval)
|
||||
{ .tv_sec = UE9_TIMEOUT });
|
||||
ret = recv_all_timeout (fd, buf, 46, 0, &(struct timeval)
|
||||
{
|
||||
.tv_sec = UE9_TIMEOUT});
|
||||
|
||||
/* Verify packet format */
|
||||
if (ret != 46) {
|
||||
verb("short recv %d\n", (int)ret);
|
||||
if (ret != 46)
|
||||
{
|
||||
verb ("short recv %d\n", (int) ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ue9_verify_extended(buf, 46) ||
|
||||
!ue9_verify_normal(buf, 6)) {
|
||||
verb("bad checksum\n");
|
||||
if (!ue9_verify_extended (buf, 46) || !ue9_verify_normal (buf, 6))
|
||||
{
|
||||
verb ("bad checksum\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (buf[1] != 0xF9 || buf[2] != 0x14 || buf[3] != 0xC0) {
|
||||
verb("bad command bytes\n");
|
||||
if (buf[1] != 0xF9 || buf[2] != 0x14 || buf[3] != 0xC0)
|
||||
{
|
||||
verb ("bad command bytes\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (buf[11] != 0) {
|
||||
verb("stream error: %s\n", ue9_error(buf[11]));
|
||||
if (buf[11] != 0)
|
||||
{
|
||||
verb ("stream error: %s\n", ue9_error (buf[11]));
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* Check for dropped packets. */
|
||||
if (buf[10] != packet) {
|
||||
verb("expected packet %d, but received packet %d\n",
|
||||
if (buf[10] != packet)
|
||||
{
|
||||
verb ("expected packet %d, but received packet %d\n",
|
||||
packet, buf[10]);
|
||||
return -5;
|
||||
}
|
||||
packet++;
|
||||
|
||||
/* Check comm processor backlog (up to 512 kB) */
|
||||
if (buf[45] & 0x80) {
|
||||
verb("buffer overflow in CommBacklog, aborting\n");
|
||||
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",
|
||||
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");
|
||||
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]);
|
||||
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);
|
||||
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) {
|
||||
if ((*callback) (channels, data, context) < 0)
|
||||
{
|
||||
/* We're done */
|
||||
return 0;
|
||||
}
|
||||
|
53
ue9.h
53
ue9.h
@@ -16,7 +16,8 @@
|
||||
#include "netutil.h"
|
||||
|
||||
/* Calibration data */
|
||||
struct ue9Calibration {
|
||||
struct ue9Calibration
|
||||
{
|
||||
double unipolarSlope[4];
|
||||
double unipolarOffset[4];
|
||||
double bipolarSlope;
|
||||
@@ -36,7 +37,8 @@ struct ue9Calibration {
|
||||
};
|
||||
|
||||
/* Comm config */
|
||||
struct ue9CommConfig {
|
||||
struct ue9CommConfig
|
||||
{
|
||||
uint8_t local_id;
|
||||
uint8_t power_level;
|
||||
in_addr_t address;
|
||||
@@ -52,7 +54,8 @@ struct ue9CommConfig {
|
||||
};
|
||||
|
||||
/* Control config */
|
||||
struct ue9ControlConfig {
|
||||
struct ue9ControlConfig
|
||||
{
|
||||
uint8_t power_level;
|
||||
uint8_t reset_source;
|
||||
double control_fw_version;
|
||||
@@ -77,65 +80,65 @@ struct ue9ControlConfig {
|
||||
#define UE9_CHANNELS 14
|
||||
|
||||
/* Fill checksums in data buffers */
|
||||
void ue9_checksum_normal(uint8_t *buffer, size_t len);
|
||||
void ue9_checksum_extended(uint8_t *buffer, size_t len);
|
||||
void ue9_checksum_normal (uint8_t * buffer, size_t len);
|
||||
void ue9_checksum_extended (uint8_t * buffer, size_t len);
|
||||
|
||||
/* Verify checksums in data buffers. Returns 0 on error. */
|
||||
int ue9_verify_normal(uint8_t *buffer, size_t len);
|
||||
int ue9_verify_extended(uint8_t *buffer, size_t len);
|
||||
int ue9_verify_normal (uint8_t * buffer, size_t len);
|
||||
int ue9_verify_extended (uint8_t * buffer, size_t len);
|
||||
|
||||
/* Open/close TCP/IP connection to the UE9 */
|
||||
int ue9_open(const char *host, int port);
|
||||
void ue9_close(int fd);
|
||||
int ue9_open (const char *host, int port);
|
||||
void ue9_close (int fd);
|
||||
|
||||
/* Read a memory block from the device. Returns -1 on error. */
|
||||
int ue9_memory_read(int fd, int blocknum, uint8_t *buffer, int len);
|
||||
int ue9_memory_read (int fd, int blocknum, uint8_t * buffer, int len);
|
||||
|
||||
/* Convert 64-bit fixed point to double type */
|
||||
double ue9_fp64_to_double(uint8_t *data);
|
||||
double ue9_fp64_to_double (uint8_t * data);
|
||||
|
||||
/* Retrieve calibration data or configuration from the device */
|
||||
int ue9_get_calibration(int fd, struct ue9Calibration *calib);
|
||||
int ue9_get_comm_config(int fd, struct ue9CommConfig *config);
|
||||
int ue9_get_control_config(int fd, struct ue9ControlConfig *config);
|
||||
int ue9_get_calibration (int fd, struct ue9Calibration *calib);
|
||||
int ue9_get_comm_config (int fd, struct ue9CommConfig *config);
|
||||
int ue9_get_control_config (int fd, struct ue9ControlConfig *config);
|
||||
|
||||
/* Data conversion. If calib is NULL, use uncalibrated conversions. */
|
||||
double ue9_binary_to_analog(struct ue9Calibration *calib,
|
||||
double ue9_binary_to_analog (struct ue9Calibration *calib,
|
||||
uint8_t gain, uint8_t resolution, uint16_t data);
|
||||
|
||||
/* Compute scanrate based on the provided values. */
|
||||
double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval);
|
||||
double ue9_compute_rate (uint8_t scanconfig, uint16_t scaninterval);
|
||||
|
||||
/* Choose the best ScanConfig and ScanInterval parameters for the
|
||||
desired scanrate. Returns 0 if nothing can be chosen. */
|
||||
int ue9_choose_scan(double desired_rate, double *actual_rate,
|
||||
uint8_t *scanconfig, uint16_t *scaninterval);
|
||||
int ue9_choose_scan (double desired_rate, double *actual_rate,
|
||||
uint8_t * scanconfig, uint16_t * scaninterval);
|
||||
|
||||
/* Flush data buffers */
|
||||
void ue9_buffer_flush(int fd);
|
||||
void ue9_buffer_flush (int fd);
|
||||
|
||||
/* Stop stream. Returns < 0 on failure. */
|
||||
int ue9_stream_stop(int fd);
|
||||
int ue9_stream_stop (int fd);
|
||||
|
||||
/* Start stream. Returns < 0 on failure. */
|
||||
int ue9_stream_start(int fd);
|
||||
int ue9_stream_start (int fd);
|
||||
|
||||
/* Execute a command on the UE9. Returns -1 on error. Fills the
|
||||
checksums on the outgoing packets, and verifies them on the
|
||||
incoming packets. Data in "out" is transmitted, data in "in" is
|
||||
received. */
|
||||
int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen);
|
||||
int ue9_command (int fd, uint8_t * out, uint8_t * in, int inlen);
|
||||
|
||||
/* "Simple" stream configuration, assumes the channels are all
|
||||
configured with the same gain. */
|
||||
int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
|
||||
int ue9_streamconfig_simple (int fd, int *channel_list, int channel_count,
|
||||
uint8_t scanconfig, uint16_t scaninterval,
|
||||
uint8_t gain);
|
||||
|
||||
/* Stream data and pass it to the data callback. If callback returns
|
||||
negative, stops reading and returns 0. Returns < 0 on error. */
|
||||
typedef int (*ue9_stream_cb_t)(int channels, uint16_t *data, void *context);
|
||||
int ue9_stream_data(int fd, int channels,
|
||||
typedef int (*ue9_stream_cb_t) (int channels, uint16_t * data, void *context);
|
||||
int ue9_stream_data (int fd, int channels,
|
||||
ue9_stream_cb_t callback, void *context);
|
||||
|
||||
#endif
|
||||
|
@@ -42,9 +42,10 @@ const char *ue9_error_text[] = {
|
||||
[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)";
|
||||
else
|
||||
return ue9_error_text[errorcode];
|
||||
|
@@ -44,6 +44,6 @@
|
||||
|
||||
extern const char *ue9_error_text[];
|
||||
|
||||
const char *ue9_error(int errorcode);
|
||||
const char *ue9_error (int errorcode);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user