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
WINCFLAGS += $(CFLAGS)
WINLDFLAGS += $(LDFLAGS) -lws2_32 -s
WINLDFLAGS += $(LDFLAGS) -lws2_32 -liphlpapi -s
# Targets

View File

@@ -1 +1 @@
1.0
1.1

View File

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

View File

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

View File

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

8
ethstream.h Normal file
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}
};
int main(int argc, char *argv[])
int
main (int argc, char *argv[])
{
int optind;
char *optarg;
@@ -44,8 +45,10 @@ int main(int argc, char *argv[])
/* Parse arguments */
opt_init (&optind);
while ((c = opt_parse(argc, argv, &optind, &optarg, opt)) != 0) {
switch (c) {
while ((c = opt_parse (argc, argv, &optind, &optarg, opt)) != 0)
{
switch (c)
{
case 'a':
free (address);
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]);
goto printhelp;
}
@@ -80,7 +84,8 @@ int main(int argc, char *argv[])
/* Open */
fd = ue9_open (address, UE9_COMMAND_PORT);
if (fd < 0) {
if (fd < 0)
{
info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
goto out0;
}
@@ -95,4 +100,3 @@ int main(int argc, char *argv[])
out0:
return ret;
}

View File

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

View File

@@ -13,7 +13,7 @@
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <math.h>
#include "netutil.h"
@@ -23,26 +23,221 @@
#include "nerdjack.h"
#include "util.h"
#include "netutil.h"
#include "ethstream.h"
#define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
#define NERD_HEADER_SIZE 8
#define MAX_SOCKETS 32
typedef struct __attribute__ ((__packed__))
{
unsigned char headerone;
unsigned char headertwo;
unsigned short packetNumber;
unsigned short adcused;
unsigned short packetsready;
signed short data[NERDJACK_NUM_SAMPLES];
} dataPacket;
struct discovered_socket {
int sock;
uint32_t local_ip;
uint32_t subnet_mask;
};
struct discover_t {
struct discovered_socket socks[MAX_SOCKETS];
unsigned int sock_count;
};
/* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns -1 if no valid config found */
int nerdjack_choose_scan(double desired_rate, double *actual_rate, int *period)
int
nerdjack_choose_scan (double desired_rate, double *actual_rate,
unsigned long *period)
{
*period = round((double) NERDJACK_CLOCK_RATE / desired_rate);
//The ffffe is because of a silicon bug. The last bit is unusable in all
//devices so far. It is worked around on the chip, but giving it exactly
//0xfffff would cause the workaround code to roll over.
*period = floor ((double) NERDJACK_CLOCK_RATE / desired_rate);
if (*period > 0x0ffffe)
{
info ("Cannot sample that slowly\n");
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) 0x0ffffe;
*period = 0x0ffffe;
return -1;
}
//Period holds the period register for the NerdJack, so it needs to be right
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period;
if(*actual_rate != desired_rate) {
if (*actual_rate != desired_rate)
{
return -1;
}
return 0;
}
int nerdjack_detect(char * ipAddress) {
int32_t sock, receivesock;
/**
* Create a discovered socket and add it to the socket list structure.
* All sockets in the structure should be created, bound, and ready for broadcasting
*/
static int discovered_sock_create(struct discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)
{
if (ds->sock_count >= MAX_SOCKETS) {
return 0;
}
/* Create socket. */
int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
return 0;
}
/* Allow broadcast. */
int sock_opt = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
/* Set nonblocking */
if (soblock (sock, 0) < 0)
{
verb ("can't set nonblocking\n");
return 0;
}
/* Bind socket. */
struct sockaddr_in sock_addr;
memset(&sock_addr, 0, sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = htonl(local_ip);
sock_addr.sin_port = htons(0);
if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
close(sock);
return 0;
}
/* Write sock entry. */
struct discovered_socket *dss = &ds->socks[ds->sock_count++];
dss->sock = sock;
dss->local_ip = local_ip;
dss->subnet_mask = subnet_mask;
return 1;
}
/**
* Enumerate all interfaces we can find and open sockets on each
*/
#if defined(USE_IPHLPAPI)
static void enumerate_interfaces(struct discover_t *ds)
{
PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
DWORD Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
if (Ret != NO_ERROR) {
free(pAdapterInfo);
if (Ret != ERROR_BUFFER_OVERFLOW) {
return;
}
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
if (Ret != NO_ERROR) {
free(pAdapterInfo);
return;
}
}
PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
while (pAdapter) {
IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList;
while (pIPAddr) {
uint32_t local_ip = ntohl(inet_addr(pIPAddr->IpAddress.String));
uint32_t mask = ntohl(inet_addr(pIPAddr->IpMask.String));
if (local_ip == 0) {
pIPAddr = pIPAddr->Next;
continue;
}
discovered_sock_create(ds, local_ip, mask);
pIPAddr = pIPAddr->Next;
}
pAdapter = pAdapter->Next;
}
free(pAdapterInfo);
}
#else
static void enumerate_interfaces(struct discover_t *ds) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) {
return;
}
struct ifconf ifc;
uint8_t buf[8192];
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = (char *)buf;
memset(buf, 0, sizeof(buf));
if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
close(fd);
return;
}
uint8_t *ptr = (uint8_t *)ifc.ifc_req;
uint8_t *end = (uint8_t *)&ifc.ifc_buf[ifc.ifc_len];
while (ptr <= end) {
struct ifreq *ifr = (struct ifreq *)ptr;
ptr += _SIZEOF_ADDR_IFREQ(*ifr);
if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
continue;
}
struct sockaddr_in *addr_in = (struct sockaddr_in *)&(ifr->ifr_addr);
uint32_t local_ip = ntohl(addr_in->sin_addr.s_addr);
if (local_ip == 0) {
continue;
}
if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
continue;
}
struct sockaddr_in *mask_in = (struct sockaddr_in *)&(ifr->ifr_addr);
uint32_t mask = ntohl(mask_in->sin_addr.s_addr);
discovered_sock_create(ds, local_ip, mask);
}
}
#endif
/**
* Close all sockets previously enumerated and free the struct
*/
static void destroy_socks(struct discover_t *ds)
{
unsigned int i;
for (i = 0; i < ds->sock_count; i++) {
struct discovered_socket *dss = &ds->socks[i];
close(dss->sock);
}
free(ds);
}
/* Perform autodetection. Returns 0 on success, -1 on error
* Sets ipAddress to the detected address
*/
int
nerdjack_detect (char *ipAddress)
{
int32_t receivesock;
struct sockaddr_in sa, receiveaddr, sFromAddr;
int bytes_sent, buffer_length;
int buffer_length;
char buffer[200];
char incomingData[10];
unsigned int lFromLen;
@@ -52,28 +247,18 @@ int nerdjack_detect(char * ipAddress) {
net_init ();
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
receivesock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
/* Set nonblocking */
if (soblock(sock, 0) < 0) {
verb("can't set nonblocking\n");
return -1;
}
/* Set nonblocking */
if (soblock(receivesock, 0) < 0) {
verb("can't set nonblocking\n");
return -1;
}
int opt = 1;
setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(void *) &opt,sizeof(int));
if((-1 == sock) || (-1 == receivesock)) /* if socket failed to initialize, exit */
if (soblock (receivesock, 0) < 0)
{
printf("Error Creating Socket\n");
verb ("can't set nonblocking\n");
return -1;
}
if (-1 == receivesock) /* if socket failed to initialize, exit */
{
verb ("Error Creating Socket\n");
return -1;
}
@@ -85,23 +270,51 @@ int nerdjack_detect(char * ipAddress) {
receiveaddr.sin_port = htons (NERDJACK_UDP_RECEIVE_PORT);
sa.sin_port = htons (NERDJACK_DATA_PORT);
//Receive from any IP address, Will send to broadcast
//Receive from any IP address
receiveaddr.sin_addr.s_addr = INADDR_ANY;
sa.sin_addr.s_addr = INADDR_BROADCAST;
bind(receivesock,(struct sockaddr*) &receiveaddr, sizeof(struct sockaddr_in));
bind (receivesock, (struct sockaddr *) &receiveaddr,
sizeof (struct sockaddr_in));
bytes_sent = sendto(sock, buffer, buffer_length, 0,(struct sockaddr*) &sa, sizeof(struct sockaddr_in) );
if(bytes_sent < 0) {
printf("Error sending packet: %s\n", strerror(errno) );
struct discover_t *ds = (struct discover_t *)calloc(1, sizeof(struct discover_t));
if (!ds) {
return -1;
}
/* 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);
if(0 > recvfrom_timeout(receivesock, incomingData, sizeof(incomingData),0,(struct sockaddr *) &sFromAddr, &lFromLen,
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT })) {
if (0 >
recvfrom_timeout (receivesock, incomingData, sizeof (incomingData), 0,
(struct sockaddr *) &sFromAddr, &lFromLen,
&(struct timeval)
{
.tv_sec = NERDJACK_TIMEOUT}))
{
close(receivesock);
return -1;
}
@@ -110,190 +323,289 @@ int nerdjack_detect(char * ipAddress) {
//It isn't ipv6 friendly, but inet_ntop isn't on Windows...
strcpy (ipAddress, inet_ntoa (sFromAddr.sin_addr));
close(sock); /* close the socket */
close (receivesock);
return 0;
}
typedef struct {
int numCopies;
int * destlist;
} deststruct;
int nerd_data_stream(int data_fd, char * command, int numChannels, int *channel_list, int precision, int convert, int lines)
/* Send the given command to address. The command should be something
* of the specified length. This expects the NerdJack to reply with OK
* or NO
*/
int
nerd_send_command (const char *address, void *command, int length)
{
unsigned char buf[NERDJACK_PACKET_SIZE];
//int numGroups = NERDJACK_NUM_SAMPLES / numChannels;
int index = 0;
//int totalread = 0;
int ret = 0;
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++;
int ret, fd_command;
char buf[3];
fd_command = nerd_open (address, NERDJACK_COMMAND_PORT);
if (fd_command < 0)
{
info ("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT);
return -2;
}
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 */
ret = send_all_timeout(data_fd, command, strlen(command), 0,
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT });
if (ret < 0 || ret != strlen(command)) {
ret = send_all_timeout (fd_command, command, length, 0, &(struct timeval)
{
.tv_sec = NERDJACK_TIMEOUT});
if (ret < 0 || ret != length)
{
verb ("short send %d\n", (int) ret);
return -1;
}
//Loop forever to grab data
while((charsread = recv_all_timeout(data_fd,buf,NERDJACK_PACKET_SIZE,0,
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }))){
ret = recv_all_timeout (fd_command, buf, 3, 0, &(struct timeval)
{
.tv_sec = NERDJACK_TIMEOUT});
//We want a complete packet, so take the chars so far and keep waiting
if(charsread != NERDJACK_PACKET_SIZE) {
charsleft = NERDJACK_PACKET_SIZE - charsread;
while(charsleft != 0){
additionalread = recv_all_timeout(data_fd,buf+charsread,charsleft,0,
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT });
charsread = charsread + additionalread;
charsleft = NERDJACK_PACKET_SIZE - charsread;
nerd_close_conn (fd_command);
if (ret < 0 || ret != 3)
{
verb ("Error receiving OK for command\n");
return -1;
}
if (0 != strcmp ("OK", buf))
{
verb ("Did not receive OK. Received %s\n", buf);
return -4;
}
return 0;
}
int
nerd_data_stream (int data_fd, int numChannels, int *channel_list,
int precision, int convert, int lines, int showmem,
unsigned short *currentcount, unsigned int period,
int wasreset)
{
//Variables that should persist across retries
static dataPacket buf;
static int linesleft = 0;
static int linesdumped = 0;
//Variables essential to packet processing
signed short datapoint = 0;
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
if(buf[0] != 0xF0 || buf[1] != 0xAA) {
printf("No Header info\n");
if (buf.headerone != 0xF0 || buf.headertwo != 0xAA)
{
info ("No Header info\n");
return -1;
}
//Check counter info to make sure not out of order
tempshort = (buf[2] << 8) | buf[3];
if(tempshort != currentcount ){
printf("Count wrong. Expected %hd but got %hd\n", currentcount, tempshort);
tempshort = ntohs (buf.packetNumber);
if (tempshort != *currentcount)
{
info ("Count wrong. Expected %hd but got %hd\n", *currentcount,
tempshort);
return -1;
}
//Increment number of packets received
currentcount++;
*currentcount = *currentcount + 1;
//Process the rest of the header and update the index value to be pointing after it
index = 12;
memused = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | (buf[7]);
adcused = (buf[8] << 8) | (buf[9]);
packetsready = (buf[10] << 8) | (buf[11]);
alignment = 0;
numgroups = 0;
adcused = ntohs (buf.adcused);
packetsready = ntohs (buf.packetsready);
numgroupsProcessed = 0;
if (showmem)
{
printf ("%hd %hd\n", adcused, packetsready);
continue;
}
//While there is still more data in the packet, process it
while(charsread > index) {
datapoint = (buf[index] << 8 | buf[index+1]);
if(convert) {
if(alignment <= 5) {
volts = (long double) ( datapoint / 32767.0 ) * ((precision & 0x01) ? 5.0 : 10.0);
} else {
volts = (long double) (datapoint / 32767.0 ) * ((precision & 0x02) ? 5.0 : 10.0);
}
for(i = 0; i < destination[alignment].numCopies; i++) {
voltline[destination[alignment].destlist[i]] = volts;
}
} else {
for(i = 0; i < destination[alignment].numCopies; i++) {
dataline[destination[alignment].destlist[i]] = datapoint;
}
while (numgroupsProcessed < totalGroups)
{
//Poison the data structure
switch (convert)
{
case CONVERT_VOLTS:
memset (voltline, 0, numChannels * sizeof (double));
break;
default:
case CONVERT_HEX:
case CONVERT_DEC:
memset (dataline, 0, numChannels * sizeof (unsigned char));
}
//Each point is two bytes, so increment index and total bytes read
index++;
index++;
alignment++;
//totalread++;
//Read in each group
for (i = 0; i < numChannels; i++)
{
//Get the datapoint associated with the desired channel
datapoint =
ntohs (buf.
data[channel_list[i] +
numgroupsProcessed * numChannelsSampled]);
//Since channel data is packed, we need to know when to insert a newline
if(alignment == numChannelsSampled){
if(convert) {
for(i = 0; i < numChannels; i++) {
printf("%Lf ",voltline[i]);
//Place it into the line
switch (convert)
{
case CONVERT_VOLTS:
if (channel_list[i] <= 5)
{
volts =
(double) (datapoint / 32767.0) *
((precision & 0x01) ? 5.0 : 10.0);
}
} else {
for(i = 0; i < numChannels; i++) {
printf("%hd ",dataline[i]);
else
{
volts =
(double) (datapoint / 32767.0) *
((precision & 0x02) ? 5.0 : 10.0);
}
}
printf("\n");
alignment = 0;
numgroups++;
if(lines != 0) {
linesleft--;
if(linesleft == 0) {
return 0;
}
}
//If numgroups so far is equal to the numGroups in a packet, this packet is done
if(numgroups == numGroups) {
voltline[i] = volts;
break;
default:
case CONVERT_HEX:
case CONVERT_DEC:
dataline[i] = (unsigned short) (datapoint - INT16_MIN);
break;
}
}
//We want to dump the first line because it's usually spurious
if (linesdumped != 0)
{
//Now print the group
switch (convert)
{
case CONVERT_VOLTS:
for (i = 0; i < numChannels; i++)
{
if (printf ("%lf ", voltline[i]) < 0)
goto bad;
}
break;
case CONVERT_HEX:
for (i = 0; i < numChannels; i++)
{
if (printf ("%04hX", dataline[i]) < 0)
goto bad;
}
break;
default:
case CONVERT_DEC:
for (i = 0; i < numChannels; i++)
{
if (printf ("%hu ", dataline[i]) < 0)
goto bad;
}
break;
}
if (printf ("\n") < 0)
goto bad;
//If we're counting lines, decrement them
if (lines != 0)
{
linesleft--;
if (linesleft == 0)
{
return 0;
}
}
}
else
{
linesdumped = linesdumped + 1;
}
//We've processed this group, so advance the counter
numgroupsProcessed++;
}
index = 0;
}
return 0;
bad:
info ("Output error (disk full?)\n");
return -3;
}
int nerd_open(const char *address,int port) {
/* Open a connection to the NerdJack */
int
nerd_open (const char *address, int port)
{
struct hostent *he;
@@ -303,12 +615,13 @@ int nerd_open(const char *address,int port) {
if (-1 == i32SocketFD)
{
printf("cannot create socket");
verb ("cannot create socket");
return -1;
}
/* Set nonblocking */
if (soblock(i32SocketFD, 0) < 0) {
if (soblock (i32SocketFD, 0) < 0)
{
verb ("can't set nonblocking\n");
return -1;
}
@@ -320,7 +633,8 @@ int nerd_open(const char *address,int port) {
stSockAddr.sin_port = htons (port);
he = gethostbyname (address);
if (he == NULL) {
if (he == NULL)
{
verb ("gethostbyname(\"%s\") failed\n", address);
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));
/* Connect */
if (connect_timeout(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof(stSockAddr),
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }) < 0) {
if (connect_timeout
(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof (stSockAddr),
&(struct timeval)
{
.tv_sec = 3}) < 0)
{
verb ("connection to %s:%d failed: %s\n",
inet_ntoa (stSockAddr.sin_addr), port, compat_strerror (errno));
return -1;
@@ -339,23 +657,45 @@ int nerd_open(const char *address,int port) {
return i32SocketFD;
}
int nerd_generate_command(char * command, int * channel_list, int channel_count, int precision,
unsigned short period) {
//Generate an appropriate sample initiation command
int
nerd_generate_command (getPacket * command, int *channel_list,
int channel_count, int precision, unsigned long period)
{
int channelbit = 0;
short channelbit = 0;
int i;
int highestchannel = 0;
for( i = 0; i < channel_count; i++) {
channelbit = channelbit | (0x1 << channel_list[i]);
for (i = 0; i < channel_count; i++)
{
if (channel_list[i] > highestchannel)
{
highestchannel = channel_list[i];
}
//channelbit = channelbit | (0x1 << channel_list[i]);
}
sprintf(command,"GET%3.3X%d%5.5d", channelbit,precision,period);
for (i = 0; i <= highestchannel; i++)
{
channelbit = channelbit | (0x01 << i);
}
command->word[0] = 'G';
command->word[1] = 'E';
command->word[2] = 'T';
command->word[3] = 'D';
command->channelbit = htons (channelbit);
command->precision = precision;
command->period = htonl (period);
command->prescaler = 0;
return 0;
}
int nerd_close_conn(int data_fd)
int
nerd_close_conn (int data_fd)
{
shutdown (data_fd, 2);
close (data_fd);

View File

@@ -16,29 +16,48 @@
#include "netutil.h"
#define NERDJACK_CHANNELS 12
#define NERDJACK_CLOCK_RATE 54000000
#define NERDJACK_CLOCK_RATE 66000000
#define NERDJACK_DATA_PORT 49155
#define NERDJACK_UDP_RECEIVE_PORT 49156
#define NERDJACK_COMMAND_PORT 49157
#define NERDJACK_PACKET_SIZE 1460
#define NERDJACK_NUM_SAMPLES 724
#define NERDJACK_NUM_SAMPLES 726
/* Packet structure used in message to start sampling on NerdJack */
typedef struct __attribute__ ((__packed__))
{
char word[4];
unsigned long period;
unsigned short channelbit;
unsigned char precision;
unsigned char prescaler;
} getPacket;
/* Open/close TCP/IP connection to the NerdJack */
int nerd_open (const char *address, int port);
int nerd_close_conn (int data_fd);
/* Generate the command word for the NerdJack */
int nerd_generate_command(char * command, int * channel_list, int channel_count, int precision,
unsigned short period);
int nerd_generate_command (getPacket * command, int *channel_list,
int channel_count, int precision,
unsigned long period);
/* Send given command to NerdJack */
int nerd_send_command (const char *address, void *command, int length);
/* Stream data out of the NerdJack */
int nerd_data_stream(int data_fd, char * command, int numChannels, int * channel_list, int precision, int convert, int lines);
int nerd_data_stream (int data_fd, int numChannels, int *channel_list,
int precision, int convert, int lines, int showmem,
unsigned short *currentcount, unsigned int period,
int wasreset);
/* Detect the IP Address of the NerdJack and return in ipAddress */
int nerdjack_detect (char *ipAddress);
/* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns -1 if no valid config found */
int nerdjack_choose_scan(double desired_rate, double *actual_rate, int *period);
int nerdjack_choose_scan (double desired_rate, double *actual_rate,
unsigned long *period);
#endif

View File

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

View File

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

47
opt.c
View File

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

3
opt.h
View File

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

294
ue9.c
View File

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

9
ue9.h
View File

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

View File

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

View File

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