35 Commits

Author SHA1 Message Date
zacharyc
ec1ae04a5b Bumped version number and finished fixing up Windows autodetect support.
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7454 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-17 17:06:26 +00:00
zacharyc
67163dc1a2 Added Windows stub support for autodetection.
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7453 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-17 16:14:36 +00:00
zacharyc
a29bf180ab Implemented Jim's hdhomerun autodetect for POSIX. Works great.
Windows testing next.


git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7452 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-17 15:57:42 +00:00
zacharyc
4cccb783f0 Fixed up "range" argument
Took Jim's suggestions about addressing and device options
Made autodetection a better fallback.


git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7450 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-16 23:12:15 +00:00
nilm
5e7f4ac97e Increased timeout to at least 1 minute
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7433 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-14 15:49:53 +00:00
zacharyc
a57c0c22c2 Massive cleanup and refactoring of data_stream function.
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7431 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-11 17:35:54 +00:00
zacharyc
2e3f2f4b23 Made ethstream reset a little easier.
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7426 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-10 20:35:36 +00:00
zacharyc
4592b6a75b Changed nerdjack limits
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7423 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-10 17:17:39 +00:00
nilm
d1447e2af8 Changed clock again
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7421 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-10 15:58:33 +00:00
nilm
b9130788f2 Fixed annoying bug with NerdJack header
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7419 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-09 22:00:15 +00:00
nilm
ed150ead35 Changed around packet structure
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7416 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-08 15:37:07 +00:00
nilm
519a0c2e29 Made changes to ethstream to work with new clock
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7415 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-07 15:38:19 +00:00
zacharyc
190fd3f3a7 Reverted clock change.
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7406 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-03 17:44:57 +00:00
zacharyc
9c174d12b0 Forgot a carriage return
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7404 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-03 17:04:29 +00:00
zacharyc
b1e049eed0 Changed clock rate of NerdJack and added error checking to packets
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7403 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-04-03 17:03:00 +00:00
zacharyc
d461365275 Added better error recovery code.
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7314 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-19 22:19:05 +00:00
zacharyc
a4eede145b Added limits to issue warnings about high sample rates
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7303 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-18 22:36:31 +00:00
zacharyc
6562c0b787 Fixed bug when output pipe is closed without a KILL signal
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7301 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-18 17:27:46 +00:00
zacharyc
7f79ec8ff3 Ran indent on code to fix inconsistent style.
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7298 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-18 15:23:10 +00:00
zacharyc
1dd09ea52d Made timeouts more reasonable for small sample rates.
Fixed error in period calculation's interaction with the PWM bug


git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7297 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-18 15:20:41 +00:00
zacharyc
ded6c7e5f4 Removed silicon workaround
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7289 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-17 21:32:50 +00:00
zacharyc
f2d6566051 Packet reordering shifted PC side.
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7287 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-17 21:07:18 +00:00
zacharyc
357e808986 Introduced usage of full 20 bits of PWM period counter
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7286 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-17 20:25:49 +00:00
zacharyc
0ed2935deb Better command structure using hton, ntoh, and friends
Altered command structure to support full 20 bit period


git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7282 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-13 20:33:52 +00:00
zacharyc
1a2ed51d0c Added one second sleep in code to let nerdjack recover from previous run
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7274 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-12 21:50:37 +00:00
zacharyc
679b4ef64f Fixed a few bugs to increase reliability and drop first line.
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7262 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-09 21:36:59 +00:00
zacharyc
770a83b8f7 Fixed bug in precision argument for ethstream
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7260 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-09 18:12:09 +00:00
zacharyc
627a1bf22b Slight bit of code cleanup. More to come
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7254 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-06 17:20:49 +00:00
zacharyc
43c8e19c67 Basic resume functionality working
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7250 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-05 21:43:25 +00:00
zacharyc
4aab606162 Fixed up rate determination and added memory test routine for NerdJack
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7235 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-03-02 16:35:54 +00:00
zacharyc
c81d372d23 Made commands fixed width
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7220 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-02-24 14:50:11 +00:00
zacharyc
407a91c764 Merged Jim's changes to ljstream. This now should respect disk full errors
and allow hex output


git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7214 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-02-23 15:47:55 +00:00
zacharyc
1d760e033b Updated ethstream to have separate Command and Data ports for NerdJack
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7212 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-02-23 14:39:26 +00:00
zacharyc
57cfac2bec Changed output format so that numbers are between 0 and 65536 instead of
signed output. This matches LabJack behavior


git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7141 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-02-02 20:09:01 +00:00
zacharyc
5b731f3e7e Now ethstream falls back from Labjack to Nerdjack
git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7140 ddd99763-3ecb-0310-9145-efcb8ce7c51f
2009-02-02 18:29:05 +00:00
21 changed files with 2528 additions and 1722 deletions

View File

@@ -21,7 +21,7 @@ BINPATH = ${PREFIX}/bin
WINCC = i386-mingw32-gcc WINCC = i386-mingw32-gcc
WINCFLAGS += $(CFLAGS) WINCFLAGS += $(CFLAGS)
WINLDFLAGS += $(LDFLAGS) -lws2_32 -s WINLDFLAGS += $(LDFLAGS) -lws2_32 -liphlpapi -s
# Targets # Targets

View File

@@ -1 +1 @@
1.0 1.1

View File

@@ -3,43 +3,70 @@
#include "compat.h" #include "compat.h"
#include <windows.h> #include <windows.h>
unsigned int sleep(unsigned int seconds) unsigned int
sleep (unsigned int seconds)
{ {
Sleep (seconds * 1000); Sleep (seconds * 1000);
return 0; return 0;
} }
static struct { static struct
{
int num; int num;
char *msg; char *msg;
} win32_error[] = { } win32_error[] =
{
/* Errors that we might vaguely expect to see */ /* Errors that we might vaguely expect to see */
{ WSAEINTR, "Winsock: Interrupted system call" }, {
{ WSAEBADF, "Winsock: Bad file number" }, WSAEINTR, "Winsock: Interrupted system call"},
{ WSAEFAULT, "Winsock: Bad address" }, {
{ WSAEINVAL, "Winsock: Invalid argument" }, WSAEBADF, "Winsock: Bad file number"},
{ WSAEMFILE, "Winsock: Too many open files" }, {
{ WSAEWOULDBLOCK, "Winsock: Operation would block" }, WSAEFAULT, "Winsock: Bad address"},
{ WSAEINPROGRESS, "Winsock: Operation now in progress" }, {
{ WSAEALREADY, "Winsock: Operation already in progress" }, WSAEINVAL, "Winsock: Invalid argument"},
{ WSAENOTSOCK, "Winsock: Socket operation on nonsocket" }, {
{ WSAEADDRINUSE, "Winsock: Address already in use" }, WSAEMFILE, "Winsock: Too many open files"},
{ WSAEADDRNOTAVAIL, "Winsock: Cannot assign requested address" }, {
{ WSAENETDOWN, "Winsock: Network is down" }, WSAEWOULDBLOCK, "Winsock: Operation would block"},
{ WSAENETUNREACH, "Winsock: Network is unreachable" }, {
{ WSAENETRESET, "Winsock: Network dropped connection on reset" }, WSAEINPROGRESS, "Winsock: Operation now in progress"},
{ WSAECONNABORTED, "Winsock: Software caused connection abort" }, {
{ WSAECONNRESET, "Winsock: Connection reset by peer" }, WSAEALREADY, "Winsock: Operation already in progress"},
{ WSAETIMEDOUT, "Winsock: Connection timed out" }, {
{ WSAECONNREFUSED, "Winsock: Connection refused" }, WSAENOTSOCK, "Winsock: Socket operation on nonsocket"},
{ WSAEHOSTDOWN, "Winsock: Host is down" }, {
{ WSAEHOSTUNREACH, "Winsock: No route to host" }, WSAEADDRINUSE, "Winsock: Address already in use"},
{ WSAVERNOTSUPPORTED, "Winsock: Unsupported Winsock version" }, {
{ ETIMEDOUT, "Connection timed out" }, WSAEADDRNOTAVAIL, "Winsock: Cannot assign requested address"},
{ ENOTCONN, "Not connected" }, {
{ -1, NULL }, WSAENETDOWN, "Winsock: Network is down"},
}; {
char *compat_strerror(int errnum) WSAENETUNREACH, "Winsock: Network is unreachable"},
{
WSAENETRESET, "Winsock: Network dropped connection on reset"},
{
WSAECONNABORTED, "Winsock: Software caused connection abort"},
{
WSAECONNRESET, "Winsock: Connection reset by peer"},
{
WSAETIMEDOUT, "Winsock: Connection timed out"},
{
WSAECONNREFUSED, "Winsock: Connection refused"},
{
WSAEHOSTDOWN, "Winsock: Host is down"},
{
WSAEHOSTUNREACH, "Winsock: No route to host"},
{
WSAVERNOTSUPPORTED, "Winsock: Unsupported Winsock version"},
{
ETIMEDOUT, "Connection timed out"},
{
ENOTCONN, "Not connected"},
{
-1, NULL},};
char *
compat_strerror (int errnum)
{ {
int i; int i;
static char buf[128]; static char buf[128];
@@ -47,7 +74,8 @@ char *compat_strerror(int errnum)
for (i = 0; win32_error[i].num != -1; i++) for (i = 0; win32_error[i].num != -1; i++)
if (errnum == win32_error[i].num) if (errnum == win32_error[i].num)
return win32_error[i].msg; return win32_error[i].msg;
if (errnum >= 10000) { if (errnum >= 10000)
{
sprintf (buf, "Winsock: unknown error %d\n", errnum); sprintf (buf, "Winsock: unknown error %d\n", errnum);
return buf; return buf;
} }
@@ -80,4 +108,3 @@ char *compat_strerror(int errnum)
} }
*/ */
#endif #endif

View File

@@ -4,7 +4,8 @@
int verb_count = 0; int verb_count = 0;
int func_fprintf(const char *func, FILE *stream, const char *format, ...) int
func_fprintf (const char *func, FILE * stream, const char *format, ...)
{ {
va_list ap; va_list ap;
int ret; int ret;
@@ -15,4 +16,3 @@ int func_fprintf(const char *func, FILE *stream, const char *format, ...)
va_end (ap); va_end (ap);
return ret; return ret;
} }

View File

@@ -29,28 +29,35 @@
#include "opt.h" #include "opt.h"
#include "version.h" #include "version.h"
#include "compat.h" #include "compat.h"
#include "ethstream.h"
#define DEFAULT_HOST "192.168.1.209" #define DEFAULT_HOST "192.168.1.209"
#define UE9_COMMAND_PORT 52360 #define UE9_COMMAND_PORT 52360
#define UE9_DATA_PORT 52361 #define UE9_DATA_PORT 52361
struct callbackInfo {
struct callbackInfo
{
struct ue9Calibration calib; struct ue9Calibration calib;
int convert; int convert;
int maxlines; int maxlines;
}; };
struct options opt[] = { struct options opt[] = {
{ 'a', "address", "string", "host/address of UE9 (192.168.1.209)" }, {'a', "address", "string", "host/address of device (192.168.1.209)"},
{'n', "numchannels", "n", "sample the first N ADC channels (2)"}, {'n', "numchannels", "n", "sample the first N ADC channels (2)"},
{ 'N', "nerdjack", NULL, "Use NerdJack device instead" }, {'N', "nerdjack", NULL, "Force NerdJack device"},
{'L', "labjack",NULL,"Force LabJack device"},
{'d', "detect", NULL, "Detect NerdJack IP address"}, {'d', "detect", NULL, "Detect NerdJack IP address"},
{ 'p', "precision", "0-3", "Set precision on NerdJack (0 - max range, 1 - max precision)"}, {'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"}, {'C', "channels", "a,b,c", "sample channels a, b, and c"},
{'r', "rate", "hz", "sample each channel at this rate (8000.0)"}, {'r', "rate", "hz", "sample each channel at this rate (8000.0)"},
{'o', "oneshot", NULL, "don't retry in case of errors"}, {'o', "oneshot", NULL, "don't retry in case of errors"},
{'f', "forceretry", NULL, "retry no matter what happens"}, {'f', "forceretry", NULL, "retry no matter what happens"},
{ 'c', "convert", NULL, "display output in volts" }, {'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"}, {'l', "lines", "num", "if set, output this many lines and quit"},
{'h', "help", NULL, "this help"}, {'h', "help", NULL, "this help"},
{'v', "verbose", NULL, "be verbose"}, {'v', "verbose", NULL, "be verbose"},
@@ -59,22 +66,27 @@ struct options opt[] = {
}; };
int doStream (const char *address, uint8_t scanconfig, uint16_t scaninterval, int doStream (const char *address, uint8_t scanconfig, uint16_t scaninterval,
int *channel_list, int channel_count, int convert, int maxlines); int *channel_list, int channel_count, int convert,
int nerdDoStream(const char *address, int *channel_list, int channel_count, int precision, int maxlines);
unsigned 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 data_callback (int channels, uint16_t * data, void *context); int data_callback (int channels, uint16_t * data, void *context);
int columns_left = 0; int columns_left = 0;
void handle_sig(int sig) void
handle_sig (int sig)
{
while (columns_left--)
{ {
while (columns_left--) {
printf (" 0"); printf (" 0");
} }
fflush (stdout); fflush (stdout);
exit (0); exit (0);
} }
int main(int argc, char *argv[]) int
main (int argc, char *argv[])
{ {
int optind; int optind;
char *optarg, *endp; char *optarg, *endp;
@@ -87,7 +99,8 @@ int main(int argc, char *argv[])
double actual_rate; double actual_rate;
int oneshot = 0; int oneshot = 0;
int forceretry = 0; int forceretry = 0;
int convert = 0; int convert = CONVERT_DEC;
int showmem = 0;
uint8_t scanconfig; uint8_t scanconfig;
uint16_t scaninterval; uint16_t scaninterval;
#if UE9_CHANNELS > NERDJACK_CHANNELS #if UE9_CHANNELS > NERDJACK_CHANNELS
@@ -97,22 +110,29 @@ int main(int argc, char *argv[])
#endif #endif
int channel_count = 0; int channel_count = 0;
int nerdjack = 0; int nerdjack = 0;
int labjack = 0;
int detect = 0; int detect = 0;
int precision = 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 */ /* Parse arguments */
opt_init (&optind); opt_init (&optind);
while ((c = opt_parse(argc, argv, &optind, &optarg, opt)) != 0) { while ((c = opt_parse (argc, argv, &optind, &optarg, opt)) != 0)
switch (c) { {
switch (c)
{
case 'a': case 'a':
free (address); free (address);
address = strdup (optarg); address = strdup (optarg);
addressSpecified = 1;
break; break;
case 'n': case 'n':
channel_count = 0; channel_count = 0;
tmp = strtol (optarg, &endp, 0); tmp = strtol (optarg, &endp, 0);
if (*endp || tmp < 1 || tmp > UE9_CHANNELS) { if (*endp || tmp < 1 || tmp > UE9_CHANNELS)
{
info ("bad number of channels: %s\n", optarg); info ("bad number of channels: %s\n", optarg);
goto printhelp; goto printhelp;
} }
@@ -121,48 +141,84 @@ int main(int argc, char *argv[])
break; break;
case 'C': case 'C':
channel_count = 0; channel_count = 0;
do { do
{
tmp = strtol (optarg, &endp, 0); tmp = strtol (optarg, &endp, 0);
if (*endp != '\0' && *endp != ',') { if (*endp != '\0' && *endp != ',')
//|| tmp < 0 || tmp >= UE9_CHANNELS) { {
info ("bad channel number: %s\n", optarg); info ("bad channel number: %s\n", optarg);
goto printhelp; goto printhelp;
} }
//We do not want to overflow channel_list, so we need the check here //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 //LabJack or a NerdJack
#if UE9_CHANNELS > NERDJACK_CHANNELS #if UE9_CHANNELS > NERDJACK_CHANNELS
if (channel_count >= UE9_CHANNELS) { if (channel_count >= UE9_CHANNELS)
{
#else #else
if (channel_count >= NERDJACK_CHANNELS) { if (channel_count >= NERDJACK_CHANNELS)
{
#endif #endif
info ("error: too many channels specified\n"); info ("error: too many channels specified\n");
goto printhelp; goto printhelp;
} }
channel_list[channel_count++] = tmp; channel_list[channel_count++] = tmp;
optarg = endp + 1; optarg = endp + 1;
} while (*endp); }
while (*endp);
break; break;
case 'r': case 'r':
desired_rate = strtod (optarg, &endp); desired_rate = strtod (optarg, &endp);
if(*endp || desired_rate <= 0) { if (*endp || desired_rate <= 0)
{
info ("bad rate: %s\n", optarg); info ("bad rate: %s\n", optarg);
goto printhelp; goto printhelp;
} }
break; break;
case 'l': case 'l':
lines = strtol (optarg, &endp, 0); lines = strtol (optarg, &endp, 0);
if (*endp || lines <= 0) { if (*endp || lines <= 0)
{
info ("bad number of lines: %s\n", optarg); info ("bad number of lines: %s\n", optarg);
goto printhelp; goto printhelp;
} }
break; break;
case 'p': case 'R':
precision++; 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; break;
case 'N': case 'N':
nerdjack++; nerdjack++;
break; break;
case 'L':
labjack++;
break;
case 'd': case 'd':
detect++; detect++;
break; break;
@@ -173,14 +229,30 @@ int main(int argc, char *argv[])
forceretry++; forceretry++;
break; break;
case 'c': case 'c':
convert++; if (convert != 0)
{
info ("specify only one conversion type\n");
goto printhelp;
}
convert = CONVERT_VOLTS;
break; break;
case 'H':
if (convert != 0)
{
info ("specify only one conversion type\n");
goto printhelp;
}
convert = CONVERT_HEX;
break;
case 'm':
showmem++;
case 'v': case 'v':
verb_count++; verb_count++;
break; break;
case 'V': case 'V':
printf("ljstream " VERSION "\n"); printf ("etherstream " VERSION "\n");
printf ("Written by Jim Paris <jim@jtan.com>\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 " printf ("This program comes with no warranty and is "
"provided under the GPLv2.\n"); "provided under the GPLv2.\n");
return 0; return 0;
@@ -197,24 +269,67 @@ int main(int argc, char *argv[])
} }
} }
if (nerdjack) { if (detect && labjack) {
if (channel_count > NERDJACK_CHANNELS) { info("The LabJack does not support autodetection\n");
goto printhelp;
}
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"); info ("Too many channels for NerdJack\n");
goto printhelp; goto printhelp;
} }
for (i = 0; i < channel_count; i++) { 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 (channel_list[i] >= NERDJACK_CHANNELS)
{
info ("Channel is out of NerdJack range: %d\n",
channel_list[i]);
goto printhelp; goto printhelp;
} }
} }
} else { }
if (channel_count > UE9_CHANNELS) { else
{
if (channel_count > UE9_CHANNELS)
{
info ("Too many channels for LabJack\n"); info ("Too many channels for LabJack\n");
goto printhelp; goto printhelp;
} }
for (i = 0; i < channel_count; i++) { for (i = 0; i < channel_count; i++)
if (channel_list[i] >= UE9_CHANNELS) { {
if (channel_list[i] >= UE9_CHANNELS)
{
info ("Channel is out of LabJack range: %d\n", channel_list[i]); info ("Channel is out of LabJack range: %d\n", channel_list[i]);
goto printhelp; goto printhelp;
} }
@@ -223,23 +338,27 @@ int main(int argc, char *argv[])
if (optind < argc) { if (optind < argc)
{
info ("error: too many arguments (%s)\n\n", argv[optind]); info ("error: too many arguments (%s)\n\n", argv[optind]);
goto printhelp; goto printhelp;
} }
if (forceretry && oneshot) { if (forceretry && oneshot)
{
info ("forceretry and oneshot options are mutually exclusive\n"); info ("forceretry and oneshot options are mutually exclusive\n");
goto printhelp; goto printhelp;
} }
/* Two channels if none specified */ /* Two channels if none specified */
if (channel_count == 0) { if (channel_count == 0)
{
channel_list[channel_count++] = 0; channel_list[channel_count++] = 0;
channel_list[channel_count++] = 1; channel_list[channel_count++] = 1;
} }
if (verb_count) { if (verb_count)
{
info ("Scanning channels:"); info ("Scanning channels:");
for (i = 0; i < channel_count; i++) for (i = 0; i < channel_count; i++)
info (" AIN%d", channel_list[i]); info (" AIN%d", channel_list[i]);
@@ -247,53 +366,71 @@ int main(int argc, char *argv[])
} }
/* Figure out actual rate. */ /* Figure out actual rate. */
if (nerdjack) { if (donerdjack)
if (nerdjack_choose_scan(desired_rate, &actual_rate, &period) < 0) { {
if (nerdjack_choose_scan (desired_rate, &actual_rate, &period) < 0)
{
info ("error: can't achieve requested scan rate (%lf Hz)\n", info ("error: can't achieve requested scan rate (%lf Hz)\n",
desired_rate); desired_rate);
return 1;
} }
} else { }
else
{
if (ue9_choose_scan (desired_rate, &actual_rate, if (ue9_choose_scan (desired_rate, &actual_rate,
&scanconfig, &scaninterval) < 0) { &scanconfig, &scaninterval) < 0)
{
info ("error: can't achieve requested scan rate (%lf Hz)\n", info ("error: can't achieve requested scan rate (%lf Hz)\n",
desired_rate); desired_rate);
return 1;
} }
} }
if ((desired_rate != actual_rate) || verb_count) if ((desired_rate != actual_rate) || verb_count)
{
info ("Actual scanrate is %lf Hz\n", actual_rate); info ("Actual scanrate is %lf Hz\n", actual_rate);
info ("Period is %ld\n", period);
}
if (verb_count && lines) {
if (verb_count && lines)
{
info ("Stopping capture after %d lines\n", lines); info ("Stopping capture after %d lines\n", lines);
} }
signal (SIGINT, handle_sig); signal (SIGINT, handle_sig);
signal (SIGTERM, handle_sig); signal (SIGTERM, handle_sig);
if (detect) { if (detect)
{
info ("Autodetecting NerdJack address\n"); info ("Autodetecting NerdJack address\n");
free (address); free (address);
if(nerdjack_detect(address) < 0) { if (nerdjack_detect (address) < 0)
{
info ("Error with autodetection\n"); info ("Error with autodetection\n");
} else { goto printhelp;
}
else
{
info ("Found NerdJack at address: %s\n", address); info ("Found NerdJack at address: %s\n", address);
} }
} }
for (;;) { for (;;)
{
int ret; int ret;
if(nerdjack) { if (donerdjack)
ret = nerdDoStream(address, channel_list, channel_count, precision, period, convert, lines); {
ret =
nerdDoStream (address, channel_list, channel_count, precision,
period, convert, lines, showmem);
verb ("nerdDoStream returned %d\n", ret); verb ("nerdDoStream returned %d\n", ret);
} else { }
else
{
ret = doStream (address, scanconfig, scaninterval, ret = doStream (address, scanconfig, scaninterval,
channel_list, channel_count, convert, channel_list, channel_count, convert, lines);
lines);
verb ("doStream returned %d\n", ret); verb ("doStream returned %d\n", ret);
} }
if (oneshot) if (oneshot)
@@ -302,16 +439,44 @@ int main(int argc, char *argv[])
if (ret == 0) if (ret == 0)
break; break;
if (ret == -ENOTCONN && !forceretry) { //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"); info ("Initial connection failed, giving up\n");
break; break;
} }
if (ret == -EAGAIN || ret == -ENOTCONN) { if (ret == -EAGAIN || ret == -ENOTCONN)
{
/* Some transient error. Wait a tiny bit, then retry */ /* Some transient error. Wait a tiny bit, then retry */
info ("Retrying in 5 secs.\n"); info ("Retrying in 5 secs.\n");
sleep (5); sleep (5);
} else { }
else
{
info ("Retrying now.\n"); info ("Retrying now.\n");
} }
} }
@@ -321,31 +486,94 @@ int main(int argc, char *argv[])
return 0; return 0;
} }
int nerdDoStream(const char *address, int *channel_list, int channel_count, int precision, int
unsigned short period, int convert, int lines) 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 retval = -EAGAIN;
int fd_data; int fd_data;
static int first_call = 1; 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 //If this is the first time, set up acquisition
first attempt, return a different error code so we give up. */ //Otherwise try to resume the previous one
fd_data = nerd_open(address, NERDJACK_DATA_PORT); if (started == 0)
if (fd_data < 0) { {
info("Connect failed: %s:%d\n", address, NERDJACK_DATA_PORT); if (nerd_generate_command
if (first_call) (&command, channel_list, channel_count, precision, period) < 0)
retval = -ENOTCONN; {
info ("Failed to create configuration command\n");
goto out; goto out;
} }
first_call = 0;
if (nerd_generate_command(command, channel_list, channel_count, precision, period) < 0) { if (nerd_send_command (address, "STOP", 4) < 0)
info("Failed to create configuration command\n"); {
goto out1; 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_data_stream(fd_data, command, channel_count, channel_list, precision, convert, lines) < 0) { 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, &currentcount, period, wasreset);
wasreset = 0;
if (retval == -3)
{
retval = 0;
}
if (retval < 0)
{
info ("Failed to open data stream\n"); info ("Failed to open data stream\n");
goto out1; goto out1;
} }
@@ -356,10 +584,13 @@ int nerdDoStream(const char *address, int *channel_list, int channel_count, int
out1: out1:
nerd_close_conn (fd_data); nerd_close_conn (fd_data);
out: out:
//We've tried communicating, so this is not the first call anymore
first_call = 0;
return retval; 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 *channel_list, int channel_count, int convert, int lines)
{ {
int retval = -EAGAIN; int retval = -EAGAIN;
@@ -374,7 +605,8 @@ int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
/* Open command connection. If this fails, and this is the /* Open command connection. If this fails, and this is the
first attempt, return a different error code so we give up. */ first attempt, return a different error code so we give up. */
fd_cmd = ue9_open (address, UE9_COMMAND_PORT); fd_cmd = ue9_open (address, UE9_COMMAND_PORT);
if (fd_cmd < 0) { if (fd_cmd < 0)
{
info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT); info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
if (first_call) if (first_call)
retval = -ENOTCONN; retval = -ENOTCONN;
@@ -389,13 +621,15 @@ int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
/* Open data connection */ /* Open data connection */
fd_data = ue9_open (address, UE9_DATA_PORT); fd_data = ue9_open (address, UE9_DATA_PORT);
if (fd_data < 0) { if (fd_data < 0)
{
info ("Connect failed: %s:%d\n", address, UE9_DATA_PORT); info ("Connect failed: %s:%d\n", address, UE9_DATA_PORT);
goto out1; goto out1;
} }
/* Get calibration */ /* Get calibration */
if (ue9_get_calibration(fd_cmd, &ci.calib) < 0) { if (ue9_get_calibration (fd_cmd, &ci.calib) < 0)
{
info ("Failed to get device calibration\n"); info ("Failed to get device calibration\n");
goto out2; goto out2;
} }
@@ -403,20 +637,23 @@ int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
/* Set stream configuration */ /* 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, scanconfig, scaninterval,
UE9_BIPOLAR_GAIN1) < 0) { UE9_BIPOLAR_GAIN1) < 0)
{
info ("Failed to set stream configuration\n"); info ("Failed to set stream configuration\n");
goto out2; goto out2;
} }
/* Start stream */ /* Start stream */
if (ue9_stream_start(fd_cmd) < 0) { if (ue9_stream_start (fd_cmd) < 0)
{
info ("Failed to start stream\n"); info ("Failed to start stream\n");
goto out2; goto out2;
} }
/* Stream data */ /* Stream data */
ret = ue9_stream_data (fd_data, channel_count, data_callback, (void *) &ci); ret = ue9_stream_data (fd_data, channel_count, data_callback, (void *) &ci);
if (ret < 0) { if (ret < 0)
{
info ("Data stream failed with error %d\n", ret); info ("Data stream failed with error %d\n", ret);
goto out3; goto out3;
} }
@@ -436,25 +673,45 @@ int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
return retval; return retval;
} }
int data_callback(int channels, uint16_t *data, void *context) int
data_callback (int channels, uint16_t * data, void *context)
{ {
int i; int i;
struct callbackInfo *ci = (struct callbackInfo *) context; struct callbackInfo *ci = (struct callbackInfo *) context;
static int lines = 0; static int lines = 0;
columns_left = channels; columns_left = channels;
for (i = 0; i < channels; i++) { for (i = 0; i < channels; i++)
if (ci->convert) {
printf("%lf", ue9_binary_to_analog( switch (ci->convert)
&ci->calib, UE9_BIPOLAR_GAIN1, 12, {
data[i])); case CONVERT_VOLTS:
else if (printf
printf("%d", data[i]); ("%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--; columns_left--;
if (i < (channels - 1)) { if (i < (channels - 1))
putchar(' '); {
} else { if (ci->convert != CONVERT_HEX && putchar (' ') < 0)
putchar('\n'); goto bad;
}
else
{
if (putchar ('\n') < 0)
goto bad;
lines++; lines++;
if (ci->maxlines && lines >= ci->maxlines) if (ci->maxlines && lines >= ci->maxlines)
return -1; return -1;
@@ -462,4 +719,8 @@ int data_callback(int channels, uint16_t *data, void *context)
} }
return 0; return 0;
bad:
info ("Output error (disk full?)\n");
return -3;
} }

8
ethstream.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef ETHSTREAM_H
#define ETHSTREAM_H
#define CONVERT_DEC 0
#define CONVERT_VOLTS 1
#define CONVERT_HEX 2
#endif

View File

@@ -32,7 +32,8 @@ struct options opt[] = {
{0, NULL, NULL, NULL} {0, NULL, NULL, NULL}
}; };
int main(int argc, char *argv[]) int
main (int argc, char *argv[])
{ {
int optind; int optind;
char *optarg; char *optarg;
@@ -44,8 +45,10 @@ int main(int argc, char *argv[])
/* Parse arguments */ /* Parse arguments */
opt_init (&optind); opt_init (&optind);
while ((c = opt_parse(argc, argv, &optind, &optarg, opt)) != 0) { while ((c = opt_parse (argc, argv, &optind, &optarg, opt)) != 0)
switch (c) { {
switch (c)
{
case 'a': case 'a':
free (address); free (address);
address = strdup (optarg); address = strdup (optarg);
@@ -71,7 +74,8 @@ int main(int argc, char *argv[])
} }
} }
if(optind<argc) { if (optind < argc)
{
info ("Error: too many arguments (%s)\n\n", argv[optind]); info ("Error: too many arguments (%s)\n\n", argv[optind]);
goto printhelp; goto printhelp;
} }
@@ -80,7 +84,8 @@ int main(int argc, char *argv[])
/* Open */ /* Open */
fd = ue9_open (address, UE9_COMMAND_PORT); fd = ue9_open (address, UE9_COMMAND_PORT);
if (fd < 0) { if (fd < 0)
{
info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT); info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
goto out0; goto out0;
} }
@@ -95,4 +100,3 @@ int main(int argc, char *argv[])
out0: out0:
return ret; return ret;
} }

View File

@@ -16,7 +16,8 @@
#include "ue9.h" #include "ue9.h"
#include "compat.h" #include "compat.h"
int main(int argc, char *argv[]) int
main (int argc, char *argv[])
{ {
int fd_cmd; int fd_cmd;
struct ue9Calibration calib; struct ue9Calibration calib;
@@ -24,15 +25,15 @@ int main(int argc, char *argv[])
verb_count = 2; verb_count = 2;
fd_cmd = ue9_open ("192.168.1.209", 52360); fd_cmd = ue9_open ("192.168.1.209", 52360);
if (fd_cmd < 0) { if (fd_cmd < 0)
fprintf(stderr, "ue9_open: %s\n", {
compat_strerror(errno)); fprintf (stderr, "ue9_open: %s\n", compat_strerror (errno));
return 1; return 1;
} }
if (ue9_get_calibration(fd_cmd, &calib) < 0) { if (ue9_get_calibration (fd_cmd, &calib) < 0)
fprintf(stderr, "ue9_get_calibration: %s\n", {
compat_strerror(errno)); fprintf (stderr, "ue9_get_calibration: %s\n", compat_strerror (errno));
return 1; return 1;
} }

View File

@@ -13,7 +13,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/types.h>
#include <math.h> #include <math.h>
#include "netutil.h" #include "netutil.h"
@@ -23,26 +23,221 @@
#include "nerdjack.h" #include "nerdjack.h"
#include "util.h" #include "util.h"
#include "netutil.h" #include "netutil.h"
#include "ethstream.h"
#define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */ #define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
#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 /* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns -1 if no valid config found */ desired scanrate. Returns -1 if no valid config found */
int nerdjack_choose_scan(double desired_rate, double *actual_rate, int *period) int
nerdjack_choose_scan (double desired_rate, double *actual_rate,
unsigned long *period)
{ {
//The ffffe is because of a silicon bug. The last bit is unusable in all
*period = round((double) NERDJACK_CLOCK_RATE / desired_rate); //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; *actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period;
if(*actual_rate != desired_rate) { if (*actual_rate != desired_rate)
{
return -1; return -1;
} }
return 0; 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; struct sockaddr_in sa, receiveaddr, sFromAddr;
int bytes_sent, buffer_length; int buffer_length;
char buffer[200]; char buffer[200];
char incomingData[10]; char incomingData[10];
unsigned int lFromLen; unsigned int lFromLen;
@@ -52,28 +247,18 @@ int nerdjack_detect(char * ipAddress) {
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 */ /* Set nonblocking */
if (soblock(sock, 0) < 0) { if (soblock (receivesock, 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 */
{ {
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; return -1;
} }
@@ -85,23 +270,51 @@ int nerdjack_detect(char * ipAddress) {
receiveaddr.sin_port = htons (NERDJACK_UDP_RECEIVE_PORT); receiveaddr.sin_port = htons (NERDJACK_UDP_RECEIVE_PORT);
sa.sin_port = htons (NERDJACK_DATA_PORT); sa.sin_port = htons (NERDJACK_DATA_PORT);
//Receive from any IP address, Will send to broadcast //Receive from any IP address
receiveaddr.sin_addr.s_addr = INADDR_ANY; 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) ); struct discover_t *ds = (struct discover_t *)calloc(1, sizeof(struct discover_t));
if(bytes_sent < 0) { if (!ds) {
printf("Error sending packet: %s\n", strerror(errno) );
return -1; return -1;
} }
/* Create a routable broadcast socket. */
if (!discovered_sock_create(ds, 0, 0)) {
free(ds);
return -1;
}
/* 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); lFromLen = sizeof (sFromAddr);
if(0 > recvfrom_timeout(receivesock, incomingData, sizeof(incomingData),0,(struct sockaddr *) &sFromAddr, &lFromLen, if (0 >
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT })) { recvfrom_timeout (receivesock, incomingData, sizeof (incomingData), 0,
(struct sockaddr *) &sFromAddr, &lFromLen,
&(struct timeval)
{
.tv_sec = NERDJACK_TIMEOUT}))
{
close(receivesock);
return -1; return -1;
} }
@@ -110,190 +323,289 @@ int nerdjack_detect(char * ipAddress) {
//It isn't ipv6 friendly, but inet_ntop isn't on Windows... //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; return 0;
} }
typedef struct { /* Send the given command to address. The command should be something
int numCopies; * of the specified length. This expects the NerdJack to reply with OK
int * destlist; * or NO
} deststruct; */
int
int nerd_data_stream(int data_fd, char * command, int numChannels, int *channel_list, int precision, int convert, int lines) nerd_send_command (const char *address, void *command, int length)
{ {
unsigned char buf[NERDJACK_PACKET_SIZE]; int ret, fd_command;
char buf[3];
//int numGroups = NERDJACK_NUM_SAMPLES / numChannels; fd_command = nerd_open (address, NERDJACK_COMMAND_PORT);
if (fd_command < 0)
int index = 0; {
//int totalread = 0; info ("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT);
int ret = 0; return -2;
int alignment = 0;
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;
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 channels_left = numChannels;
int channelprocessing = 0;
int currentalign = 0; //Index into sampled channels
int i;
int numDuplicates = 0;
//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++;
} }
destination[currentalign].numCopies++;
//currentalign++;
channels_left--;
//break;
}
}
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);
int numChannelsSampled = numChannels - numDuplicates;
int numGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled;
/* Send request */ /* Send request */
ret = send_all_timeout(data_fd, command, strlen(command), 0, ret = send_all_timeout (fd_command, command, length, 0, &(struct timeval)
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }); {
if (ret < 0 || ret != strlen(command)) { .tv_sec = NERDJACK_TIMEOUT});
if (ret < 0 || ret != length)
{
verb ("short send %d\n", (int) ret); verb ("short send %d\n", (int) ret);
return -1; return -1;
} }
//Loop forever to grab data ret = recv_all_timeout (fd_command, buf, 3, 0, &(struct timeval)
while((charsread = recv_all_timeout(data_fd,buf,NERDJACK_PACKET_SIZE,0, {
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }))){ .tv_sec = NERDJACK_TIMEOUT});
//We want a complete packet, so take the chars so far and keep waiting nerd_close_conn (fd_command);
if(charsread != NERDJACK_PACKET_SIZE) {
charsleft = NERDJACK_PACKET_SIZE - charsread; if (ret < 0 || ret != 3)
while(charsleft != 0){ {
additionalread = recv_all_timeout(data_fd,buf+charsread,charsleft,0, verb ("Error receiving OK for command\n");
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }); return -1;
charsread = charsread + additionalread;
charsleft = NERDJACK_PACKET_SIZE - charsread;
} }
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;
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 numgroupsProcessed = 0;
double volts;
//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;
//Check to see if we're trying to resume
//Don't blow away linesleft in that case
if (lines != 0 && linesleft == 0)
{
linesleft = lines;
}
//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");
}
}
//Now destination structure array is set as well as numDuplicates.
int totalGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled;
//Loop forever to grab data
while ((charsread =
recv_all_timeout (data_fd, &buf, NERDJACK_PACKET_SIZE, 0,
&(struct timeval)
{
.tv_sec = expectedtimeout})))
{
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 //First check the header info
if(buf[0] != 0xF0 || buf[1] != 0xAA) { if (buf.headerone != 0xF0 || buf.headertwo != 0xAA)
printf("No Header info\n"); {
info ("No Header info\n");
return -1; return -1;
} }
//Check counter info to make sure not out of order //Check counter info to make sure not out of order
tempshort = (buf[2] << 8) | buf[3]; tempshort = ntohs (buf.packetNumber);
if(tempshort != currentcount ){ if (tempshort != *currentcount)
printf("Count wrong. Expected %hd but got %hd\n", currentcount, tempshort); {
info ("Count wrong. Expected %hd but got %hd\n", *currentcount,
tempshort);
return -1; return -1;
} }
//Increment number of packets received //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 adcused = ntohs (buf.adcused);
index = 12; packetsready = ntohs (buf.packetsready);
memused = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | (buf[7]); numgroupsProcessed = 0;
adcused = (buf[8] << 8) | (buf[9]);
packetsready = (buf[10] << 8) | (buf[11]); if (showmem)
alignment = 0; {
numgroups = 0; printf ("%hd %hd\n", adcused, packetsready);
continue;
}
//While there is still more data in the packet, process it //While there is still more data in the packet, process it
while(charsread > index) { while (numgroupsProcessed < totalGroups)
datapoint = (buf[index] << 8 | buf[index+1]); {
if(convert) { //Poison the data structure
if(alignment <= 5) { switch (convert)
volts = (long double) ( datapoint / 32767.0 ) * ((precision & 0x01) ? 5.0 : 10.0); {
} else { case CONVERT_VOLTS:
volts = (long double) (datapoint / 32767.0 ) * ((precision & 0x02) ? 5.0 : 10.0); memset (voltline, 0, numChannels * sizeof (double));
} break;
for(i = 0; i < destination[alignment].numCopies; i++) { default:
voltline[destination[alignment].destlist[i]] = volts; case CONVERT_HEX:
} case CONVERT_DEC:
} else { memset (dataline, 0, numChannels * sizeof (unsigned char));
for(i = 0; i < destination[alignment].numCopies; i++) {
dataline[destination[alignment].destlist[i]] = datapoint;
}
} }
//Each point is two bytes, so increment index and total bytes read //Read in each group
index++; for (i = 0; i < numChannels; i++)
index++; {
alignment++; //Get the datapoint associated with the desired channel
//totalread++; datapoint =
ntohs (buf.
data[channel_list[i] +
numgroupsProcessed * numChannelsSampled]);
//Place it into the line
switch (convert)
{
//Since channel data is packed, we need to know when to insert a newline case CONVERT_VOLTS:
if(alignment == numChannelsSampled){ if (channel_list[i] <= 5)
if(convert) { {
for(i = 0; i < numChannels; i++) { volts =
printf("%Lf ",voltline[i]); (double) (datapoint / 32767.0) *
((precision & 0x01) ? 5.0 : 10.0);
} }
} else { else
for(i = 0; i < numChannels; i++) { {
printf("%hd ",dataline[i]); volts =
(double) (datapoint / 32767.0) *
((precision & 0x02) ? 5.0 : 10.0);
} }
} voltline[i] = volts;
printf("\n"); break;
alignment = 0; default:
numgroups++; case CONVERT_HEX:
if(lines != 0) { case CONVERT_DEC:
linesleft--; dataline[i] = (unsigned short) (datapoint - INT16_MIN);
if(linesleft == 0) {
return 0;
}
}
//If numgroups so far is equal to the numGroups in a packet, this packet is done
if(numgroups == numGroups) {
break; break;
} }
} }
//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; 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; struct hostent *he;
@@ -303,12 +615,13 @@ int nerd_open(const char *address,int port) {
if (-1 == i32SocketFD) if (-1 == i32SocketFD)
{ {
printf("cannot create socket"); verb ("cannot create socket");
return -1; return -1;
} }
/* Set nonblocking */ /* Set nonblocking */
if (soblock(i32SocketFD, 0) < 0) { if (soblock (i32SocketFD, 0) < 0)
{
verb ("can't set nonblocking\n"); verb ("can't set nonblocking\n");
return -1; return -1;
} }
@@ -320,7 +633,8 @@ int nerd_open(const char *address,int port) {
stSockAddr.sin_port = htons (port); stSockAddr.sin_port = htons (port);
he = gethostbyname (address); he = gethostbyname (address);
if (he == NULL) { if (he == NULL)
{
verb ("gethostbyname(\"%s\") failed\n", address); verb ("gethostbyname(\"%s\") failed\n", address);
return -1; return -1;
} }
@@ -329,8 +643,12 @@ int nerd_open(const char *address,int port) {
debug ("Resolved %s -> %s\n", address, inet_ntoa (stSockAddr.sin_addr)); debug ("Resolved %s -> %s\n", address, inet_ntoa (stSockAddr.sin_addr));
/* Connect */ /* Connect */
if (connect_timeout(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof(stSockAddr), if (connect_timeout
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }) < 0) { (i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof (stSockAddr),
&(struct timeval)
{
.tv_sec = 3}) < 0)
{
verb ("connection to %s:%d failed: %s\n", verb ("connection to %s:%d failed: %s\n",
inet_ntoa (stSockAddr.sin_addr), port, compat_strerror (errno)); inet_ntoa (stSockAddr.sin_addr), port, compat_strerror (errno));
return -1; return -1;
@@ -339,23 +657,45 @@ int nerd_open(const char *address,int port) {
return i32SocketFD; return i32SocketFD;
} }
int nerd_generate_command(char * command, int * channel_list, int channel_count, int precision, //Generate an appropriate sample initiation command
unsigned short period) { 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 i;
int highestchannel = 0;
for( i = 0; i < channel_count; i++) { for (i = 0; i < channel_count; i++)
channelbit = channelbit | (0x1 << channel_list[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; return 0;
} }
int nerd_close_conn(int data_fd) int
nerd_close_conn (int data_fd)
{ {
shutdown (data_fd, 2); shutdown (data_fd, 2);
close (data_fd); close (data_fd);

View File

@@ -16,29 +16,48 @@
#include "netutil.h" #include "netutil.h"
#define NERDJACK_CHANNELS 12 #define NERDJACK_CHANNELS 12
#define NERDJACK_CLOCK_RATE 54000000 #define NERDJACK_CLOCK_RATE 66000000
#define NERDJACK_DATA_PORT 49155 #define NERDJACK_DATA_PORT 49155
#define NERDJACK_UDP_RECEIVE_PORT 49156 #define NERDJACK_UDP_RECEIVE_PORT 49156
#define NERDJACK_COMMAND_PORT 49157
#define NERDJACK_PACKET_SIZE 1460 #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 */ /* Open/close TCP/IP connection to the NerdJack */
int nerd_open (const char *address, int port); int nerd_open (const char *address, int port);
int nerd_close_conn (int data_fd); int nerd_close_conn (int data_fd);
/* Generate the command word for the NerdJack */ /* Generate the command word for the NerdJack */
int nerd_generate_command(char * command, int * channel_list, int channel_count, int precision, int nerd_generate_command (getPacket * command, int *channel_list,
unsigned short period); 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 */ /* 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 */ /* Detect the IP Address of the NerdJack and return in ipAddress */
int nerdjack_detect (char *ipAddress); int nerdjack_detect (char *ipAddress);
/* Choose the best ScanConfig and ScanInterval parameters for the /* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns -1 if no valid config found */ desired scanrate. Returns -1 if no valid config found */
int nerdjack_choose_scan(double desired_rate, double *actual_rate, int *period); int nerdjack_choose_scan (double desired_rate, double *actual_rate,
unsigned long *period);
#endif #endif

View File

@@ -5,7 +5,8 @@
#include <stdio.h> #include <stdio.h>
/* Initialize networking */ /* Initialize networking */
void net_init(void) void
net_init (void)
{ {
#ifdef __WIN32__ #ifdef __WIN32__
WSADATA blah; WSADATA blah;
@@ -14,7 +15,8 @@ void net_init(void)
} }
/* Set socket blocking/nonblocking */ /* Set socket blocking/nonblocking */
int soblock(int socket, int blocking) int
soblock (int socket, int blocking)
{ {
#ifdef __WIN32__ #ifdef __WIN32__
unsigned long arg = blocking ? 0 : 1; unsigned long arg = blocking ? 0 : 1;
@@ -26,7 +28,8 @@ int soblock(int socket, int blocking)
/* Get flags */ /* Get flags */
sockopt = fcntl (socket, F_GETFL); sockopt = fcntl (socket, F_GETFL);
if (sockopt == -1) { if (sockopt == -1)
{
return -1; return -1;
} }
@@ -46,7 +49,8 @@ int soblock(int socket, int blocking)
/* Like connect(2), but with a timeout. Socket must be non-blocking. */ /* Like connect(2), but with a timeout. Socket must be non-blocking. */
int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen, int
connect_timeout (int s, const struct sockaddr *serv_addr, socklen_t addrlen,
struct timeval *timeout) struct timeval *timeout)
{ {
int ret; int ret;
@@ -58,7 +62,8 @@ int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
/* Start connect */ /* Start connect */
ret = connect (s, serv_addr, addrlen); ret = connect (s, serv_addr, addrlen);
if (ret == 0) { if (ret == 0)
{
/* Success */ /* Success */
return 0; return 0;
} }
@@ -79,11 +84,13 @@ int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
FD_ZERO (&exceptfds); FD_ZERO (&exceptfds);
FD_SET (s, &exceptfds); FD_SET (s, &exceptfds);
ret = select (s + 1, NULL, &writefds, &exceptfds, timeout); ret = select (s + 1, NULL, &writefds, &exceptfds, timeout);
if (ret < 0) { if (ret < 0)
{
/* Error */ /* Error */
return -1; return -1;
} }
if (ret == 0) { if (ret == 0)
{
/* Timed out */ /* Timed out */
errno = ETIMEDOUT; errno = ETIMEDOUT;
return -1; return -1;
@@ -94,7 +101,8 @@ int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
if (getsockopt (s, SOL_SOCKET, SO_ERROR, (void *) &optval, &optlen) != 0) if (getsockopt (s, SOL_SOCKET, SO_ERROR, (void *) &optval, &optlen) != 0)
return -1; return -1;
if (optval != 0) { if (optval != 0)
{
/* Connection failed. */ /* Connection failed. */
errno = optval; errno = optval;
return -1; 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 /* On Windows, SO_ERROR sometimes shows no error but the connection
still failed. Sigh. */ still failed. Sigh. */
if (FD_ISSET(s, &exceptfds) || !FD_ISSET(s, &writefds)) { if (FD_ISSET (s, &exceptfds) || !FD_ISSET (s, &writefds))
{
errno = EIO; errno = EIO;
return -1; return -1;
} }
@@ -114,7 +123,8 @@ 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. /* Like send(2), but with a timeout. Socket must be non-blocking.
The timeout only applies if no data at all is sent -- this function The timeout only applies if no data at all is sent -- this function
may still send less than requested. */ may still send less than requested. */
ssize_t send_timeout(int s, const void *buf, size_t len, int flags, ssize_t
send_timeout (int s, const void *buf, size_t len, int flags,
struct timeval * timeout) struct timeval * timeout)
{ {
fd_set writefds; fd_set writefds;
@@ -123,12 +133,14 @@ ssize_t send_timeout(int s, const void *buf, size_t len, int flags,
FD_ZERO (&writefds); FD_ZERO (&writefds);
FD_SET (s, &writefds); FD_SET (s, &writefds);
ret = select (s + 1, NULL, &writefds, NULL, timeout); ret = select (s + 1, NULL, &writefds, NULL, timeout);
if (ret == 0) { if (ret == 0)
{
/* Timed out */ /* Timed out */
errno = ETIMEDOUT; errno = ETIMEDOUT;
return -1; return -1;
} }
if (ret != 1) { if (ret != 1)
{
/* Error */ /* Error */
return -1; return -1;
} }
@@ -139,7 +151,8 @@ ssize_t send_timeout(int s, const void *buf, size_t len, int flags,
/* Like recv(2), but with a timeout. Socket must be non-blocking. /* Like recv(2), but with a timeout. Socket must be non-blocking.
The timeout only applies if no data at all is received -- this The timeout only applies if no data at all is received -- this
function may still return less than requested. */ function may still return less than requested. */
ssize_t recv_timeout(int s, void *buf, size_t len, int flags, ssize_t
recv_timeout (int s, void *buf, size_t len, int flags,
struct timeval * timeout) struct timeval * timeout)
{ {
fd_set readfds; fd_set readfds;
@@ -148,12 +161,14 @@ ssize_t recv_timeout(int s, void *buf, size_t len, int flags,
FD_ZERO (&readfds); FD_ZERO (&readfds);
FD_SET (s, &readfds); FD_SET (s, &readfds);
ret = select (s + 1, &readfds, NULL, NULL, timeout); ret = select (s + 1, &readfds, NULL, NULL, timeout);
if (ret == 0) { if (ret == 0)
{
/* Timed out */ /* Timed out */
errno = ETIMEDOUT; errno = ETIMEDOUT;
return -1; return -1;
} }
if (ret != 1) { if (ret != 1)
{
/* Error */ /* Error */
return -1; return -1;
} }
@@ -164,7 +179,9 @@ ssize_t recv_timeout(int s, void *buf, size_t len, int flags,
/* Like recvfrom(2), but with a timeout. Socket must be non-blocking. /* Like recvfrom(2), but with a timeout. Socket must be non-blocking.
The timeout only applies if no data at all is received -- this The timeout only applies if no data at all is received -- this
function may still return less than requested. */ function may still return less than requested. */
ssize_t recvfrom_timeout(int s, void *buf, size_t len, int flags, struct sockaddr *address, socklen_t *address_len, ssize_t
recvfrom_timeout (int s, void *buf, size_t len, int flags,
struct sockaddr * address, socklen_t * address_len,
struct timeval * timeout) struct timeval * timeout)
{ {
fd_set readfds; fd_set readfds;
@@ -173,12 +190,14 @@ ssize_t recvfrom_timeout(int s, void *buf, size_t len, int flags, struct sockadd
FD_ZERO (&readfds); FD_ZERO (&readfds);
FD_SET (s, &readfds); FD_SET (s, &readfds);
ret = select (s + 1, &readfds, NULL, NULL, timeout); ret = select (s + 1, &readfds, NULL, NULL, timeout);
if (ret == 0) { if (ret == 0)
{
/* Timed out */ /* Timed out */
errno = ETIMEDOUT; errno = ETIMEDOUT;
return -1; return -1;
} }
if (ret != 1) { if (ret != 1)
{
/* Error */ /* Error */
return -1; return -1;
} }
@@ -189,14 +208,16 @@ ssize_t recvfrom_timeout(int s, void *buf, size_t len, int flags, struct sockadd
/* Like send_timeout, but retries (with the same timeout) in case of /* Like send_timeout, but retries (with the same timeout) in case of
partial transfers. This is a stronger attempt to send all partial transfers. This is a stronger attempt to send all
requested data. */ requested data. */
ssize_t send_all_timeout(int s, const void *buf, size_t len, int flags, ssize_t
send_all_timeout (int s, const void *buf, size_t len, int flags,
struct timeval * timeout) struct timeval * timeout)
{ {
struct timeval tv; struct timeval tv;
size_t left = len; size_t left = len;
ssize_t ret; ssize_t ret;
while (left > 0) { while (left > 0)
{
tv.tv_sec = timeout->tv_sec; tv.tv_sec = timeout->tv_sec;
tv.tv_usec = timeout->tv_usec; tv.tv_usec = timeout->tv_usec;
ret = send_timeout (s, buf, left, flags, &tv); ret = send_timeout (s, buf, left, flags, &tv);
@@ -217,14 +238,16 @@ 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 /* Like recv_timeout, but retries (with the same timeout) in case of
partial transfers. This is a stronger attempt to recv all partial transfers. This is a stronger attempt to recv all
requested data. */ requested data. */
ssize_t recv_all_timeout(int s, void *buf, size_t len, int flags, ssize_t
recv_all_timeout (int s, void *buf, size_t len, int flags,
struct timeval * timeout) struct timeval * timeout)
{ {
struct timeval tv; struct timeval tv;
size_t left = len; size_t left = len;
ssize_t ret; ssize_t ret;
while (left > 0) { while (left > 0)
{
tv.tv_sec = timeout->tv_sec; tv.tv_sec = timeout->tv_sec;
tv.tv_usec = timeout->tv_usec; tv.tv_usec = timeout->tv_usec;
ret = recv_timeout (s, buf, left, flags, &tv); ret = recv_timeout (s, buf, left, flags, &tv);

View File

@@ -11,11 +11,19 @@
# define socklen_t int # define socklen_t int
# define in_addr_t uint32_t # define in_addr_t uint32_t
# define in_port_t uint16_t # define in_port_t uint16_t
# include <windows.h>
# include <iphlpapi.h>
# define USE_IPHLPAPI 1
#else #else
# include <sys/socket.h> # include <sys/socket.h>
# include <netinet/in.h> # include <netinet/in.h>
# include <arpa/inet.h> # include <arpa/inet.h>
# include <netdb.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 #endif
/* Initialize networking */ /* Initialize networking */
@@ -26,13 +34,14 @@ int soblock(int socket, int blocking);
/* Like send(2), recv(2), connect(2), but with timeouts. /* Like send(2), recv(2), connect(2), but with timeouts.
Socket must be O_NONBLOCK. */ Socket must be O_NONBLOCK. */
int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen, int connect_timeout (int s, const struct sockaddr *serv_addr,
struct timeval *timeout); socklen_t addrlen, struct timeval *timeout);
ssize_t send_timeout (int s, const void *buf, size_t len, int flags, ssize_t send_timeout (int s, const void *buf, size_t len, int flags,
struct timeval *timeout); struct timeval *timeout);
ssize_t recv_timeout (int s, void *buf, size_t len, int flags, ssize_t recv_timeout (int s, void *buf, size_t len, int flags,
struct timeval *timeout); struct timeval *timeout);
ssize_t recvfrom_timeout(int s, void *buf, size_t len, int flags, struct sockaddr *address, socklen_t *address_len, ssize_t recvfrom_timeout (int s, void *buf, size_t len, int flags,
struct sockaddr *address, socklen_t * address_len,
struct timeval *timeout); struct timeval *timeout);
/* Like send_timeout and recv_timeout, but they retry (with the same timeout) /* Like send_timeout and recv_timeout, but they retry (with the same timeout)

47
opt.c
View File

@@ -11,12 +11,16 @@
#include <string.h> #include <string.h>
#include "opt.h" #include "opt.h"
void opt_init(int *optind) { void
opt_init (int *optind)
{
*optind = 0; *optind = 0;
} }
char opt_parse(int argc, char **argv, int *optind, char **optarg, char
struct options *opt) { opt_parse (int argc, char **argv, int *optind, char **optarg,
struct options *opt)
{
char c; char c;
int i; int i;
(*optind)++; (*optind)++;
@@ -24,8 +28,8 @@ char opt_parse(int argc, char **argv, int *optind, char **optarg,
return 0; return 0;
if (argv[*optind][0] == '-' && if (argv[*optind][0] == '-' &&
argv[*optind][1]!='-' && argv[*optind][1] != '-' && argv[*optind][1] != 0)
argv[*optind][1]!=0) { {
/* Short option (or a bunch of 'em) */ /* Short option (or a bunch of 'em) */
/* Save this and shift others over */ /* Save this and shift others over */
c = argv[*optind][1]; c = argv[*optind][1];
@@ -38,7 +42,8 @@ char opt_parse(int argc, char **argv, int *optind, char **optarg,
for (i = 0; opt[i].shortopt != 0; i++) for (i = 0; opt[i].shortopt != 0; i++)
if (opt[i].shortopt == c) if (opt[i].shortopt == c)
break; break;
if(opt[i].shortopt==0) { if (opt[i].shortopt == 0)
{
fprintf (stderr, "Error: unknown option '-%c'\n", c); fprintf (stderr, "Error: unknown option '-%c'\n", c);
return '?'; return '?';
} }
@@ -46,47 +51,55 @@ char opt_parse(int argc, char **argv, int *optind, char **optarg,
return c; return c;
(*optind)++; (*optind)++;
if (*optind >= argc || (argv[*optind][0] == '-' && if (*optind >= argc || (argv[*optind][0] == '-' &&
argv[*optind][1]!=0)) { argv[*optind][1] != 0))
{
fprintf (stderr, "Error: option '-%c' requires an " fprintf (stderr, "Error: option '-%c' requires an "
"argument\n", c); "argument\n", c);
return '?'; return '?';
} }
(*optarg) = argv[*optind]; (*optarg) = argv[*optind];
return c; return c;
} else if(argv[*optind][0]=='-' && }
argv[*optind][1]=='-' && else if (argv[*optind][0] == '-' &&
argv[*optind][2]!=0) { argv[*optind][1] == '-' && argv[*optind][2] != 0)
{
/* Long option */ /* Long option */
for (i = 0; (c = opt[i].shortopt) != 0; i++) for (i = 0; (c = opt[i].shortopt) != 0; i++)
if (strcmp (opt[i].longopt, argv[*optind] + 2) == 0) if (strcmp (opt[i].longopt, argv[*optind] + 2) == 0)
break; break;
if(opt[i].shortopt==0) { if (opt[i].shortopt == 0)
fprintf(stderr,"Error: unknown option '%s'\n", {
argv[*optind]); fprintf (stderr, "Error: unknown option '%s'\n", argv[*optind]);
return '?'; return '?';
} }
if (opt[i].arg == NULL) if (opt[i].arg == NULL)
return c; return c;
(*optind)++; (*optind)++;
if (*optind >= argc || (argv[*optind][0] == '-' && if (*optind >= argc || (argv[*optind][0] == '-' &&
argv[*optind][1]!=0)) { argv[*optind][1] != 0))
{
fprintf (stderr, "Error: option '%s' requires an " fprintf (stderr, "Error: option '%s' requires an "
"argument\n", argv[*optind - 1]); "argument\n", argv[*optind - 1]);
return '?'; return '?';
} }
(*optarg) = argv[*optind]; (*optarg) = argv[*optind];
return c; return c;
} else { }
else
{
/* End of options */ /* End of options */
return 0; return 0;
} }
} }
void opt_help(struct options *opt, FILE *out) { void
opt_help (struct options *opt, FILE * out)
{
int i; int i;
int printed; int printed;
for(i=0;opt[i].shortopt!=0;i++) { for (i = 0; opt[i].shortopt != 0; i++)
{
fprintf (out, " -%c, --%s%n", opt[i].shortopt, fprintf (out, " -%c, --%s%n", opt[i].shortopt,
opt[i].longopt, &printed); opt[i].longopt, &printed);
fprintf (out, " %-*s%s\n", 30 - printed, fprintf (out, " %-*s%s\n", 30 - printed,

3
opt.h
View File

@@ -11,7 +11,8 @@
#include <stdlib.h> #include <stdlib.h>
struct options { struct options
{
char shortopt; char shortopt;
char *longopt; char *longopt;
char *arg; char *arg;

294
ue9.c
View File

@@ -28,11 +28,13 @@
#define UE9_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */ #define UE9_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
/* Fill checksums in data buffers, with "normal" checksum format */ /* Fill checksums in data buffers, with "normal" checksum format */
void ue9_checksum_normal(uint8_t *buffer, size_t len) void
ue9_checksum_normal (uint8_t * buffer, size_t len)
{ {
uint16_t sum = 0; uint16_t sum = 0;
if (len < 1) { if (len < 1)
{
fprintf (stderr, "ue9_checksum_normal: len too short\n"); fprintf (stderr, "ue9_checksum_normal: len too short\n");
exit (1); exit (1);
} }
@@ -45,11 +47,13 @@ void ue9_checksum_normal(uint8_t *buffer, size_t len)
} }
/* Fill checksums in data buffers, with "extended" checksum format */ /* Fill checksums in data buffers, with "extended" checksum format */
void ue9_checksum_extended(uint8_t *buffer, size_t len) void
ue9_checksum_extended (uint8_t * buffer, size_t len)
{ {
uint16_t sum = 0; uint16_t sum = 0;
if (len < 6) { if (len < 6)
{
fprintf (stderr, "ue9_checksum_extended: len too short\n"); fprintf (stderr, "ue9_checksum_extended: len too short\n");
exit (1); exit (1);
} }
@@ -65,11 +69,13 @@ void ue9_checksum_extended(uint8_t *buffer, size_t len)
} }
/* Verify checksums in data buffers, with "normal" checksum format. */ /* Verify checksums in data buffers, with "normal" checksum format. */
int ue9_verify_normal(uint8_t *buffer, size_t len) int
ue9_verify_normal (uint8_t * buffer, size_t len)
{ {
uint8_t saved, new; uint8_t saved, new;
if (len < 1) { if (len < 1)
{
fprintf (stderr, "ue9_verify_normal: len too short\n"); fprintf (stderr, "ue9_verify_normal: len too short\n");
exit (1); exit (1);
} }
@@ -79,9 +85,9 @@ int ue9_verify_normal(uint8_t *buffer, size_t len)
new = buffer[0]; new = buffer[0];
buffer[0] = saved; buffer[0] = saved;
if (new != saved) { if (new != saved)
verb("got %02x, expected %02x\n", {
saved, new); verb ("got %02x, expected %02x\n", saved, new);
return 0; return 0;
} }
@@ -89,11 +95,13 @@ int ue9_verify_normal(uint8_t *buffer, size_t len)
} }
/* Verify checksums in data buffers, with "extended" checksum format. */ /* Verify checksums in data buffers, with "extended" checksum format. */
int ue9_verify_extended(uint8_t *buffer, size_t len) int
ue9_verify_extended (uint8_t * buffer, size_t len)
{ {
uint8_t saved[3], new[3]; uint8_t saved[3], new[3];
if (len < 6) { if (len < 6)
{
fprintf (stderr, "ue9_verify_extended: len too short\n"); fprintf (stderr, "ue9_verify_extended: len too short\n");
exit (1); exit (1);
} }
@@ -109,9 +117,8 @@ int ue9_verify_extended(uint8_t *buffer, size_t len)
buffer[4] = saved[1]; buffer[4] = saved[1];
buffer[5] = saved[2]; buffer[5] = saved[2];
if (saved[0] != new[0] || if (saved[0] != new[0] || saved[1] != new[1] || saved[2] != new[2])
saved[1] != new[1] || {
saved[2] != new[2]) {
verb ("got %02x %02x %02x, expected %02x %02x %02x\n", verb ("got %02x %02x %02x, expected %02x %02x %02x\n",
saved[0], saved[1], saved[2], new[0], new[1], new[2]); saved[0], saved[1], saved[2], new[0], new[1], new[2]);
return 0; return 0;
@@ -121,39 +128,52 @@ int ue9_verify_extended(uint8_t *buffer, size_t len)
} }
/* Data conversion. If calib is NULL, use uncalibrated conversions. */ /* Data conversion. If calib is NULL, use uncalibrated conversions. */
double ue9_binary_to_analog(struct ue9Calibration *calib, double
ue9_binary_to_analog (struct ue9Calibration *calib,
uint8_t gain, uint8_t resolution, uint16_t data) uint8_t gain, uint8_t resolution, uint16_t data)
{ {
double slope = 0, offset; double slope = 0, offset;
if (calib == NULL) { if (calib == NULL)
{
double uncal[9] = { 5.08, 2.54, 1.27, 0.63, 0, 0, 0, 0, 10.25 }; 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) { if (gain >= ARRAY_SIZE (uncal) || uncal[gain] == 0)
{
fprintf (stderr, "ue9_binary_to_analog: bad gain\n"); fprintf (stderr, "ue9_binary_to_analog: bad gain\n");
exit (1); exit (1);
} }
return data * uncal[gain] / 65536.0; return data * uncal[gain] / 65536.0;
} }
if (resolution < 18) { if (resolution < 18)
if (gain <= 3) { {
if (gain <= 3)
{
slope = calib->unipolarSlope[gain]; slope = calib->unipolarSlope[gain];
offset = calib->unipolarOffset[gain]; offset = calib->unipolarOffset[gain];
} else if (gain == 8) { }
else if (gain == 8)
{
slope = calib->bipolarSlope; slope = calib->bipolarSlope;
offset = calib->bipolarOffset; offset = calib->bipolarOffset;
} }
} else { }
if (gain == 0) { else
{
if (gain == 0)
{
slope = calib->hiResUnipolarSlope; slope = calib->hiResUnipolarSlope;
offset = calib->hiResUnipolarOffset; offset = calib->hiResUnipolarOffset;
} else if (gain == 8) { }
else if (gain == 8)
{
slope = calib->hiResBipolarSlope; slope = calib->hiResBipolarSlope;
offset = calib->hiResBipolarOffset; offset = calib->hiResBipolarOffset;
} }
} }
if (slope == 0) { if (slope == 0)
{
fprintf (stderr, "ue9_binary_to_analog: bad gain\n"); fprintf (stderr, "ue9_binary_to_analog: bad gain\n");
exit (1); exit (1);
} }
@@ -165,7 +185,8 @@ double ue9_binary_to_analog(struct ue9Calibration *calib,
checksums on the outgoing packets, and verifies them on the checksums on the outgoing packets, and verifies them on the
incoming packets. Data in "out" is transmitted, data in "in" is incoming packets. Data in "out" is transmitted, data in "in" is
received. */ received. */
int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen) int
ue9_command (int fd, uint8_t * out, uint8_t * in, int inlen)
{ {
int extended = 0, outlen; int extended = 0, outlen;
uint8_t saved_1, saved_3; uint8_t saved_1, saved_3;
@@ -175,18 +196,23 @@ int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen)
extended = 1; extended = 1;
/* Figure out length of data payload, and fill checksums. */ /* Figure out length of data payload, and fill checksums. */
if (extended) { if (extended)
{
outlen = 6 + (out[2]) * 2; outlen = 6 + (out[2]) * 2;
ue9_checksum_extended (out, outlen); ue9_checksum_extended (out, outlen);
} else { }
else
{
outlen = 2 + (out[1] & 7) * 2; outlen = 2 + (out[1] & 7) * 2;
ue9_checksum_normal (out, outlen); ue9_checksum_normal (out, outlen);
} }
/* Send request */ /* Send request */
ret = send_all_timeout(fd, out, outlen, 0, ret = send_all_timeout (fd, out, outlen, 0, &(struct timeval)
& (struct timeval) { .tv_sec = UE9_TIMEOUT }); {
if (ret < 0 || ret != outlen) { .tv_sec = UE9_TIMEOUT});
if (ret < 0 || ret != outlen)
{
verb ("short send %d\n", (int) ret); verb ("short send %d\n", (int) ret);
return -1; return -1;
} }
@@ -198,9 +224,11 @@ int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen)
saved_3 = out[3]; saved_3 = out[3];
/* Receive result */ /* Receive result */
ret = recv_all_timeout(fd, in, inlen, 0, ret = recv_all_timeout (fd, in, inlen, 0, &(struct timeval)
& (struct timeval) { .tv_sec = UE9_TIMEOUT }); {
if (ret < 0 || ret != inlen) { .tv_sec = UE9_TIMEOUT});
if (ret < 0 || ret != inlen)
{
verb ("short recv %d\n", (int) ret); verb ("short recv %d\n", (int) ret);
return -1; return -1;
} }
@@ -226,11 +254,13 @@ int ue9_command(int fd, uint8_t *out, uint8_t *in, int inlen)
/* Read a memory block from the device. Returns -1 on error. */ /* Read a memory block from the device. Returns -1 on error. */
int ue9_memory_read(int fd, int blocknum, uint8_t *buffer, int len) int
ue9_memory_read (int fd, int blocknum, uint8_t * buffer, int len)
{ {
uint8_t sendbuf[8], recvbuf[136]; uint8_t sendbuf[8], recvbuf[136];
if (len != 128) { if (len != 128)
{
fprintf (stderr, "ue9_memory_read: buffer length must be 128\n"); fprintf (stderr, "ue9_memory_read: buffer length must be 128\n");
exit (1); exit (1);
} }
@@ -242,7 +272,8 @@ int ue9_memory_read(int fd, int blocknum, uint8_t *buffer, int len)
sendbuf[6] = 0x00; sendbuf[6] = 0x00;
sendbuf[7] = blocknum; sendbuf[7] = blocknum;
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) { if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n"); verb ("command failed\n");
return -1; return -1;
} }
@@ -254,7 +285,8 @@ int ue9_memory_read(int fd, int blocknum, uint8_t *buffer, int len)
} }
/* Convert 64-bit fixed point to double type */ /* Convert 64-bit fixed point to double type */
double ue9_fp64_to_double(uint8_t *data) double
ue9_fp64_to_double (uint8_t * data)
{ {
int32_t a; int32_t a;
uint32_t b; uint32_t b;
@@ -266,12 +298,14 @@ double ue9_fp64_to_double(uint8_t *data)
} }
/* Retrieve calibration data from the device. Returns -1 on error. */ /* Retrieve calibration data from the device. Returns -1 on error. */
int ue9_get_calibration(int fd, struct ue9Calibration *calib) int
ue9_get_calibration (int fd, struct ue9Calibration *calib)
{ {
uint8_t buf[128]; uint8_t buf[128];
/* Block 0 */ /* Block 0 */
if (ue9_memory_read(fd, 0, buf, 128) < 0) return -1; if (ue9_memory_read (fd, 0, buf, 128) < 0)
return -1;
calib->unipolarSlope[0] = ue9_fp64_to_double (buf + 0); calib->unipolarSlope[0] = ue9_fp64_to_double (buf + 0);
calib->unipolarOffset[0] = ue9_fp64_to_double (buf + 8); calib->unipolarOffset[0] = ue9_fp64_to_double (buf + 8);
calib->unipolarSlope[1] = ue9_fp64_to_double (buf + 16); calib->unipolarSlope[1] = ue9_fp64_to_double (buf + 16);
@@ -282,12 +316,14 @@ int ue9_get_calibration(int fd, struct ue9Calibration *calib)
calib->unipolarOffset[3] = ue9_fp64_to_double (buf + 56); calib->unipolarOffset[3] = ue9_fp64_to_double (buf + 56);
/* Block 1 */ /* Block 1 */
if (ue9_memory_read(fd, 1, buf, 128) < 0) return -1; if (ue9_memory_read (fd, 1, buf, 128) < 0)
return -1;
calib->bipolarSlope = ue9_fp64_to_double (buf + 0); calib->bipolarSlope = ue9_fp64_to_double (buf + 0);
calib->bipolarOffset = ue9_fp64_to_double (buf + 8); calib->bipolarOffset = ue9_fp64_to_double (buf + 8);
/* Block 2 */ /* Block 2 */
if (ue9_memory_read(fd, 2, buf, 128) < 0) return -1; if (ue9_memory_read (fd, 2, buf, 128) < 0)
return -1;
calib->DACSlope[0] = ue9_fp64_to_double (buf + 0); calib->DACSlope[0] = ue9_fp64_to_double (buf + 0);
calib->DACOffset[0] = ue9_fp64_to_double (buf + 8); calib->DACOffset[0] = ue9_fp64_to_double (buf + 8);
calib->DACSlope[1] = ue9_fp64_to_double (buf + 16); calib->DACSlope[1] = ue9_fp64_to_double (buf + 16);
@@ -300,12 +336,14 @@ int ue9_get_calibration(int fd, struct ue9Calibration *calib)
calib->VsSlope = ue9_fp64_to_double (buf + 96); calib->VsSlope = ue9_fp64_to_double (buf + 96);
/* Block 3 */ /* Block 3 */
if (ue9_memory_read(fd, 3, buf, 128) < 0) return -1; if (ue9_memory_read (fd, 3, buf, 128) < 0)
return -1;
calib->hiResUnipolarSlope = ue9_fp64_to_double (buf + 0); calib->hiResUnipolarSlope = ue9_fp64_to_double (buf + 0);
calib->hiResUnipolarOffset = ue9_fp64_to_double (buf + 8); calib->hiResUnipolarOffset = ue9_fp64_to_double (buf + 8);
/* Block 4 */ /* Block 4 */
if (ue9_memory_read(fd, 4, buf, 128) < 0) return -1; if (ue9_memory_read (fd, 4, buf, 128) < 0)
return -1;
calib->hiResBipolarSlope = ue9_fp64_to_double (buf + 0); calib->hiResBipolarSlope = ue9_fp64_to_double (buf + 0);
calib->hiResBipolarOffset = ue9_fp64_to_double (buf + 8); calib->hiResBipolarOffset = ue9_fp64_to_double (buf + 8);
@@ -314,7 +352,8 @@ int ue9_get_calibration(int fd, struct ue9Calibration *calib)
} }
/* Retrieve comm config, returns -1 on error */ /* Retrieve comm config, returns -1 on error */
int ue9_get_comm_config(int fd, struct ue9CommConfig *config) int
ue9_get_comm_config (int fd, struct ue9CommConfig *config)
{ {
uint8_t sendbuf[18]; uint8_t sendbuf[18];
uint8_t recvbuf[24]; uint8_t recvbuf[24];
@@ -325,7 +364,8 @@ int ue9_get_comm_config(int fd, struct ue9CommConfig *config)
sendbuf[1] = 0xf8; sendbuf[1] = 0xf8;
sendbuf[2] = 0x09; sendbuf[2] = 0x09;
sendbuf[3] = 0x08; sendbuf[3] = 0x08;
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) { if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n"); verb ("command failed\n");
return -1; return -1;
} }
@@ -334,7 +374,8 @@ int ue9_get_comm_config(int fd, struct ue9CommConfig *config)
} }
/* Retrieve control config, returns -1 on error */ /* Retrieve control config, returns -1 on error */
int ue9_get_control_config(int fd, struct ue9ControlConfig *config) int
ue9_get_control_config (int fd, struct ue9ControlConfig *config)
{ {
uint8_t sendbuf[18]; uint8_t sendbuf[18];
uint8_t recvbuf[24]; uint8_t recvbuf[24];
@@ -345,7 +386,8 @@ int ue9_get_control_config(int fd, struct ue9ControlConfig *config)
sendbuf[1] = 0xf8; sendbuf[1] = 0xf8;
sendbuf[2] = 0x06; sendbuf[2] = 0x06;
sendbuf[3] = 0x08; sendbuf[3] = 0x08;
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) { if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n"); verb ("command failed\n");
return -1; return -1;
} }
@@ -354,7 +396,8 @@ int ue9_get_control_config(int fd, struct ue9ControlConfig *config)
} }
/* Open TCP/IP connection to the UE9 */ /* Open TCP/IP connection to the UE9 */
int ue9_open(const char *host, int port) int
ue9_open (const char *host, int port)
{ {
int fd; int fd;
struct sockaddr_in address; struct sockaddr_in address;
@@ -365,13 +408,15 @@ int ue9_open(const char *host, int port)
/* Create socket */ /* Create socket */
fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0) { if (fd < 0)
{
verb ("socket returned %d\n", fd); verb ("socket returned %d\n", fd);
return -1; return -1;
} }
/* Set nonblocking */ /* Set nonblocking */
if (soblock(fd, 0) < 0) { if (soblock (fd, 0) < 0)
{
verb ("can't set nonblocking\n"); verb ("can't set nonblocking\n");
return -1; return -1;
} }
@@ -386,7 +431,8 @@ int ue9_open(const char *host, int port)
address.sin_family = AF_INET; address.sin_family = AF_INET;
address.sin_port = htons (port); address.sin_port = htons (port);
he = gethostbyname (host); he = gethostbyname (host);
if (he == NULL) { if (he == NULL)
{
verb ("gethostbyname(\"%s\") failed\n", host); verb ("gethostbyname(\"%s\") failed\n", host);
return -1; return -1;
} }
@@ -396,7 +442,10 @@ int ue9_open(const char *host, int port)
/* Connect */ /* Connect */
if (connect_timeout (fd, (struct sockaddr *) &address, sizeof (address), if (connect_timeout (fd, (struct sockaddr *) &address, sizeof (address),
& (struct timeval) { .tv_sec = UE9_TIMEOUT }) < 0) { &(struct timeval)
{
.tv_sec = UE9_TIMEOUT}) < 0)
{
verb ("connection to %s:%d failed: %s\n", verb ("connection to %s:%d failed: %s\n",
inet_ntoa (address.sin_addr), port, compat_strerror (errno)); inet_ntoa (address.sin_addr), port, compat_strerror (errno));
return -1; return -1;
@@ -406,7 +455,8 @@ int ue9_open(const char *host, int port)
} }
/* Close connection to the UE9 */ /* Close connection to the UE9 */
void ue9_close(int fd) void
ue9_close (int fd)
{ {
/* does anyone actually call shutdown these days? */ /* does anyone actually call shutdown these days? */
shutdown (fd, 2 /* SHUT_RDWR */ ); shutdown (fd, 2 /* SHUT_RDWR */ );
@@ -414,7 +464,8 @@ void ue9_close(int fd)
} }
/* Compute scanrate based on the provided values. */ /* Compute scanrate based on the provided values. */
double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval) double
ue9_compute_rate (uint8_t scanconfig, uint16_t scaninterval)
{ {
double clock; double clock;
@@ -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. a fixed rate, and not affected by the number of channels.
Channels are scanned as quickly as possible. */ Channels are scanned as quickly as possible. */
switch ((scanconfig >> 3) & 3) { switch ((scanconfig >> 3) & 3)
case 0: clock = 4e6; break; {
case 1: clock = 48e6; break; case 0:
case 2: clock = 750e3; break; clock = 4e6;
case 3: clock = 24e6; break; break;
case 1:
clock = 48e6;
break;
case 2:
clock = 750e3;
break;
case 3:
clock = 24e6;
break;
} }
if (scanconfig & 0x2) if (scanconfig & 0x2)
@@ -440,37 +500,53 @@ double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval)
/* Choose the best ScanConfig and ScanInterval parameters for the /* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns -1 if no valid config found */ desired scanrate. Returns -1 if no valid config found */
int ue9_choose_scan(double desired_rate, double *actual_rate, int
ue9_choose_scan (double desired_rate, double *actual_rate,
uint8_t * scanconfig, uint16_t * scaninterval) uint8_t * scanconfig, uint16_t * scaninterval)
{ {
int i; int i;
struct { double clock; uint8_t config; } valid[] = { struct
{ 48e6, 0x08 }, {
{ 24e6, 0x18 }, double clock;
{ 4e6, 0x00 }, uint8_t config;
{ 750e3, 0x10 }, } valid[] =
{ 48e6 / 256, 0x0a }, {
{ 24e6 / 256, 0x1a }, {
{ 4e6 / 256, 0x02 }, 48e6, 0x08},
{ 750e3 / 256, 0x12 }, {
{ 0, 0 } }; 24e6, 0x18},
{
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 /* Start with the fastest clock frequency. If the
scaninterval would be too large, knock it down until it scaninterval would be too large, knock it down until it
fits. */ fits. */
for (i = 0; valid[i].clock != 0; i++) { for (i = 0; valid[i].clock != 0; i++)
{
double interval = valid[i].clock / desired_rate; 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); 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; *scanconfig = valid[i].config;
*actual_rate = ue9_compute_rate( *actual_rate = ue9_compute_rate (*scanconfig, *scaninterval);
*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); *scanconfig, desired_rate, *actual_rate);
@@ -483,25 +559,29 @@ int ue9_choose_scan(double desired_rate, double *actual_rate,
} }
/* Flush data buffers */ /* Flush data buffers */
void ue9_buffer_flush(int fd) void
ue9_buffer_flush (int fd)
{ {
uint8_t sendbuf[2], recvbuf[2]; uint8_t sendbuf[2], recvbuf[2];
sendbuf[1] = 0x08; /* FlushBuffer */ sendbuf[1] = 0x08; /* FlushBuffer */
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) { if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n"); verb ("command failed\n");
} }
} }
/* Stop stream. Returns < 0 on failure. */ /* Stop stream. Returns < 0 on failure. */
int ue9_stream_stop(int fd) int
ue9_stream_stop (int fd)
{ {
uint8_t sendbuf[2], recvbuf[4]; uint8_t sendbuf[2], recvbuf[4];
sendbuf[1] = 0xB0; sendbuf[1] = 0xB0;
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) { if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n"); verb ("command failed\n");
return -1; return -1;
} }
@@ -514,13 +594,15 @@ int ue9_stream_stop(int fd)
} }
/* Start stream. Returns < 0 on failure. */ /* Start stream. Returns < 0 on failure. */
int ue9_stream_start(int fd) int
ue9_stream_start (int fd)
{ {
uint8_t sendbuf[2], recvbuf[4]; uint8_t sendbuf[2], recvbuf[4];
sendbuf[1] = 0xA8; sendbuf[1] = 0xA8;
if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) { if (ue9_command (fd, sendbuf, recvbuf, sizeof (recvbuf)) < 0)
{
verb ("command failed\n"); verb ("command failed\n");
return -1; return -1;
} }
@@ -534,7 +616,8 @@ int ue9_stream_start(int fd)
/* "Simple" stream configuration, assumes the channels are all /* "Simple" stream configuration, assumes the channels are all
configured with the same gain. */ configured with the same gain. */
int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count, int
ue9_streamconfig_simple (int fd, int *channel_list, int channel_count,
uint8_t scanconfig, uint16_t scaninterval, uint8_t scanconfig, uint16_t scaninterval,
uint8_t gain) uint8_t gain)
{ {
@@ -552,18 +635,21 @@ int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
buf[10] = scaninterval & 0xff; buf[10] = scaninterval & 0xff;
buf[11] = scaninterval >> 8; buf[11] = scaninterval >> 8;
for (i = 0; i < channel_count; i++) { for (i = 0; i < channel_count; i++)
{
buf[12 + 2 * i] = channel_list[i]; /* Channel number */ buf[12 + 2 * i] = channel_list[i]; /* Channel number */
buf[13 + 2 * i] = gain; /* Gain/bipolar setup */ buf[13 + 2 * i] = gain; /* Gain/bipolar setup */
} }
/* Send StreamConfig */ /* Send StreamConfig */
if (ue9_command(fd, buf, buf, 8) < 0) { if (ue9_command (fd, buf, buf, 8) < 0)
{
debug ("command failed\n"); debug ("command failed\n");
return -1; return -1;
} }
if (buf[6] != 0) { if (buf[6] != 0)
{
verb ("returned error %s\n", ue9_error (buf[6])); verb ("returned error %s\n", ue9_error (buf[6]));
return -1; 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 /* Stream data and pass it to the data callback. If callback returns
negative, stops reading and returns 0. Returns < 0 on error. */ negative, stops reading and returns 0. Returns < 0 on error. */
int ue9_stream_data(int fd, int channels, int
ue9_stream_data (int fd, int channels,
ue9_stream_cb_t callback, void *context) ue9_stream_cb_t callback, void *context)
{ {
int ret; int ret;
@@ -583,35 +670,41 @@ int ue9_stream_data(int fd, int channels,
int i; int i;
uint16_t data[channels]; uint16_t data[channels];
for (;;) { for (;;)
{
/* Receive data */ /* Receive data */
ret = recv_all_timeout (fd, buf, 46, 0, &(struct timeval) ret = recv_all_timeout (fd, buf, 46, 0, &(struct timeval)
{ .tv_sec = UE9_TIMEOUT }); {
.tv_sec = UE9_TIMEOUT});
/* Verify packet format */ /* Verify packet format */
if (ret != 46) { if (ret != 46)
{
verb ("short recv %d\n", (int) ret); verb ("short recv %d\n", (int) ret);
return -1; return -1;
} }
if (!ue9_verify_extended(buf, 46) || if (!ue9_verify_extended (buf, 46) || !ue9_verify_normal (buf, 6))
!ue9_verify_normal(buf, 6)) { {
verb ("bad checksum\n"); verb ("bad checksum\n");
return -2; return -2;
} }
if (buf[1] != 0xF9 || buf[2] != 0x14 || buf[3] != 0xC0) { if (buf[1] != 0xF9 || buf[2] != 0x14 || buf[3] != 0xC0)
{
verb ("bad command bytes\n"); verb ("bad command bytes\n");
return -3; return -3;
} }
if (buf[11] != 0) { if (buf[11] != 0)
{
verb ("stream error: %s\n", ue9_error (buf[11])); verb ("stream error: %s\n", ue9_error (buf[11]));
return -4; return -4;
} }
/* Check for dropped packets. */ /* Check for dropped packets. */
if (buf[10] != packet) { if (buf[10] != packet)
{
verb ("expected packet %d, but received packet %d\n", verb ("expected packet %d, but received packet %d\n",
packet, buf[10]); packet, buf[10]);
return -5; return -5;
@@ -619,7 +712,8 @@ int ue9_stream_data(int fd, int channels,
packet++; packet++;
/* Check comm processor backlog (up to 512 kB) */ /* Check comm processor backlog (up to 512 kB) */
if (buf[45] & 0x80) { if (buf[45] & 0x80)
{
verb ("buffer overflow in CommBacklog, aborting\n"); verb ("buffer overflow in CommBacklog, aborting\n");
return -6; return -6;
} }
@@ -628,23 +722,25 @@ int ue9_stream_data(int fd, int channels,
(buf[45] & 0x7f) * 4096); (buf[45] & 0x7f) * 4096);
/* Check control processor backlog (up to 256 bytes). */ /* Check control processor backlog (up to 256 bytes). */
if (buf[44] == 255) { if (buf[44] == 255)
{
verb ("ControlBacklog is maxed out, aborting\n"); verb ("ControlBacklog is maxed out, aborting\n");
return -7; return -7;
} }
if (buf[44] > 224) if (buf[44] > 224)
debug("warning: ControlBacklog is high (%d bytes)\n", debug ("warning: ControlBacklog is high (%d bytes)\n", buf[44]);
buf[44]);
/* Read samples from the buffer */ /* Read samples from the buffer */
for (i = 12; i <= 42; i += 2) { for (i = 12; i <= 42; i += 2)
{
data[channel++] = buf[i] + (buf[i + 1] << 8); data[channel++] = buf[i] + (buf[i + 1] << 8);
if (channel < channels) if (channel < channels)
continue; continue;
/* Received a full scan, send to callback */ /* Received a full scan, send to callback */
channel = 0; channel = 0;
if ((*callback)(channels, data, context) < 0) { if ((*callback) (channels, data, context) < 0)
{
/* We're done */ /* We're done */
return 0; return 0;
} }

9
ue9.h
View File

@@ -16,7 +16,8 @@
#include "netutil.h" #include "netutil.h"
/* Calibration data */ /* Calibration data */
struct ue9Calibration { struct ue9Calibration
{
double unipolarSlope[4]; double unipolarSlope[4];
double unipolarOffset[4]; double unipolarOffset[4];
double bipolarSlope; double bipolarSlope;
@@ -36,7 +37,8 @@ struct ue9Calibration {
}; };
/* Comm config */ /* Comm config */
struct ue9CommConfig { struct ue9CommConfig
{
uint8_t local_id; uint8_t local_id;
uint8_t power_level; uint8_t power_level;
in_addr_t address; in_addr_t address;
@@ -52,7 +54,8 @@ struct ue9CommConfig {
}; };
/* Control config */ /* Control config */
struct ue9ControlConfig { struct ue9ControlConfig
{
uint8_t power_level; uint8_t power_level;
uint8_t reset_source; uint8_t reset_source;
double control_fw_version; double control_fw_version;

View File

@@ -42,7 +42,8 @@ const char *ue9_error_text[] = {
[PLL_NOT_LOCKED] = "PLL_NOT_LOCKED" [PLL_NOT_LOCKED] = "PLL_NOT_LOCKED"
}; };
const char *ue9_error(int errorcode) const char *
ue9_error (int errorcode)
{ {
if (errorcode > ARRAY_SIZE (ue9_error_text)) if (errorcode > ARRAY_SIZE (ue9_error_text))
return "(invalid errorcode)"; return "(invalid errorcode)";

View File

@@ -1,2 +1,2 @@
/* This file was automatically generated. */ /* This file was automatically generated. */
#define VERSION "1.0 (2009-01-21)" #define VERSION "1.1 (2009-04-17)"