Compare commits

..

No commits in common. "master" and "ethstream-1.1" have entirely different histories.

24 changed files with 2318 additions and 2434 deletions

10
.gitignore vendored
View File

@ -1,10 +0,0 @@
ethstream
ethstream.1
ethstream.txt
ethstream.exe
*.obj
*.d
*.dobj
*.o

View File

@ -14,15 +14,12 @@
# Build options # Build options
CFLAGS += -Wall -g #-pg CFLAGS += -Wall -g #-pg
LDFLAGS += #-pg LDFLAGS += -lm #-pg
LDLIBS += -lm
PREFIX = /usr/local PREFIX = /usr/local
MANPATH = ${PREFIX}/man/man1/ MANPATH = ${PREFIX}/man/man1
BINPATH = ${PREFIX}/bin BINPATH = ${PREFIX}/bin
#WINCC = i386-mingw32-gcc WINCC = i386-mingw32-gcc
WINCC = i586-mingw32msvc-gcc
WINCFLAGS += $(CFLAGS) WINCFLAGS += $(CFLAGS)
WINLDFLAGS += $(LDFLAGS) -lws2_32 -liphlpapi -s WINLDFLAGS += $(LDFLAGS) -lws2_32 -liphlpapi -s
@ -35,10 +32,11 @@ default: lin
all: lin win all: lin win
.PHONY: lin .PHONY: lin
lin: ethstream ethstream.1 ethstream.txt lin: ljtest ethstream ljconfig \
ethstream.1 ljconfig.1
.PHONY: win .PHONY: win
win: ethstream.exe win: ljtest.exe ethstream.exe ljconfig.exe
version.h: VERSION version.h: VERSION
@ -48,12 +46,17 @@ version.h: VERSION
# Object files for each executable # Object files for each executable
obj-common = opt.o ue9.o ue9error.o netutil.o debug.o nerdjack.o obj-common = opt.o ue9.o ue9error.o netutil.o debug.o nerdjack.o
obj-ljconfig = ljconfig.o $(obj-common)
obj-ethstream = ethstream.o $(obj-common) obj-ethstream = ethstream.o $(obj-common)
obj-ljtest = ljtest.o $(obj-common)
ljconfig: $(obj-ljconfig)
ethstream: $(obj-ethstream) ethstream: $(obj-ethstream)
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) ljtest: $(obj-ljtest)
ljconfig.exe: $(obj-ljconfig:.o=.obj) compat-win32.obj
ethstream.exe: $(obj-ethstream:.o=.obj) compat-win32.obj ethstream.exe: $(obj-ethstream:.o=.obj) compat-win32.obj
ljtest.exe: $(obj-ljtest:.o=.obj) compat-win32.obj
# Manpages # Manpages
@ -68,7 +71,6 @@ ethstream.exe: $(obj-ethstream:.o=.obj) compat-win32.obj
.PHONY: install .PHONY: install
install: ethstream.1 ethstream install: ethstream.1 ethstream
mkdir -p ${BINPATH} ${MANPATH}
install -m 0755 ethstream ${BINPATH} install -m 0755 ethstream ${BINPATH}
install -m 0644 ethstream.1 ${MANPATH} install -m 0644 ethstream.1 ${MANPATH}
@ -90,19 +92,16 @@ dist: version.h
.PHONY: clean distclean .PHONY: clean distclean
clean distclean: clean distclean:
rm -f *.o *.obj *.exe ethstream core *.d *.dobj *.1 *.txt rm -f *.o *.obj *.exe ethstream ljtest ljconfig core *.d *.1 *.txt
# Dependency tracking: # Dependency tracking:
allsources = $(wildcard *.c) allsources = $(wildcard *.c)
-include $(allsources:.c=.d) -include $(allsources:.c=.d)
%.o : %.c %.o : %.c
$(COMPILE.c) -MP -MMD -MT '$*.o' -MF '$*.d' -o $@ $< $(COMPILE.c) -MP -MMD -MT '$*.obj' -o $@ $<
-include $(allsources:.c=.dobj)
%.obj : %.c %.obj : %.c
$(WINCC) $(WINCFLAGS) -MP -MMD -MT '$*.obj' -MF '$*.dobj' -c -o $@ $< $(WINCC) $(WINCFLAGS) -MP -MMD -MT '$*.o' -c -o $@ $<
# Win32 executable # Win32 executable

11
README
View File

@ -1,13 +1,6 @@
Labjack/Nerdjack Tools Labjack/Nerdjack Tools
by Jim Paris <jim@jtan.com> by Jim Paris <jim@jtan.com>
with modifications by with modifications by Zach Clifford <zacharyc@mit.edu>
Zach Clifford <zacharyc@mit.edu>
John Donnal <jdonnal@mit.edu>
These tools are for interacting with the LabJack UE9 or the NerdJack These tools are for interacting with the LabJack UE9 or the NerdJack over the Ethernet interface. More information about the UE9 device:
over the Ethernet interface. More information about the UE9 device:
http://www.labjack.com/labjack_ue9.php http://www.labjack.com/labjack_ue9.php
The NerdJack device is a custom board made in LEES by Zach Clifford.
Use ethstream -h or ethstream -X for usage instructions and examples.

View File

@ -1 +1 @@
1.3.2 1.1

View File

@ -2,46 +2,71 @@
#include <stdio.h> #include <stdio.h>
#include "compat.h" #include "compat.h"
#include <windows.h> #include <windows.h>
#include "errno.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"},
}; {
WSAENETUNREACH, "Winsock: Network is unreachable"},
char *compat_strerror(int errnum) {
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];
@ -49,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;
} }

View File

@ -5,6 +5,9 @@
unsigned int sleep (unsigned int seconds); unsigned int sleep (unsigned int seconds);
char *compat_strerror (int errnum); char *compat_strerror (int errnum);
//const char *inet_ntop(int af, void *src, const char *dst, socklen_t cnt); //const char *inet_ntop(int af, void *src, const char *dst, socklen_t cnt);
#define INET_ADDRSTRLEN 16
#define ETIMEDOUT 110
#define ENOTCONN 107
#else #else
#define compat_strerror strerror #define compat_strerror strerror
#endif #endif

21
debug.c
View File

@ -1,35 +1,18 @@
#include "debug.h" #include "debug.h"
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <sys/time.h>
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;
struct timeval tv;
gettimeofday(&tv, NULL);
fprintf(stream, "%ld.%06ld: ", (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec);
fprintf (stream, "%s: ", func); fprintf (stream, "%s: ", func);
va_start (ap, format); va_start (ap, format);
ret = vfprintf (stream, format, ap); ret = vfprintf (stream, format, ap);
va_end (ap); va_end (ap);
return ret; return ret;
} }
int my_fprintf(FILE * stream, const char *format, ...)
{
va_list ap;
int ret;
struct timeval tv;
gettimeofday(&tv, NULL);
fprintf(stream, "%ld.%06ld: ", (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec);
va_start(ap, format);
ret = vfprintf(stream, format, ap);
va_end(ap);
return ret;
}

View File

@ -16,8 +16,6 @@ extern int verb_count;
int func_fprintf (const char *func, FILE * stream, const char *format, int func_fprintf (const char *func, FILE * stream, const char *format,
...) __attribute__ ((format (printf, 3, 4))); ...) __attribute__ ((format (printf, 3, 4)));
int my_fprintf(FILE * stream, const char *format,
...) __attribute__ ((format(printf, 2, 3)));
#define debug(x...) ({ \ #define debug(x...) ({ \
if(verb_count >= 2) \ if(verb_count >= 2) \
@ -30,11 +28,6 @@ int my_fprintf(FILE * stream, const char *format,
}) })
#define info(x...) ({ \ #define info(x...) ({ \
if(verb_count >= 0) \
my_fprintf(stderr,x); \
})
#define info_no_timestamp(x...) ({ \
if(verb_count >= 0) \ if(verb_count >= 0) \
fprintf(stderr,x); \ fprintf(stderr,x); \
}) })

View File

@ -7,6 +7,11 @@
* License as published by the Free Software Foundation; see COPYING. * License as published by the Free Software Foundation; see COPYING.
*/ */
/* ljstream: Stream data from the first N (1-14) analog inputs.
Resolution is set to 12-bit and all channels are in bipolar (-5 to
+5V) mode.
*/
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -26,15 +31,13 @@
#include "compat.h" #include "compat.h"
#include "ethstream.h" #include "ethstream.h"
#include "example.inc"
#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
#define MAX_CHANNELS 256
struct callbackInfo { struct callbackInfo
{
struct ue9Calibration calib; struct ue9Calibration calib;
int convert; int convert;
int maxlines; int maxlines;
@ -43,77 +46,47 @@ struct callbackInfo {
struct options opt[] = { struct options opt[] = {
{'a', "address", "string", "host/address of device (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)"},
{'C', "channels", "a,b,c", "sample channels a, b, and c"},
{'r', "rate", "hz", "sample each channel at this rate (8000.0)"},
{'L', "labjack", NULL, "Force LabJack device"},
{'t', "timers", "a[:A],b[:B]", "set LabJack timer modes a,b and optional values A,B"},
{'T', "timerdivisor", "n", "set LabJack timer divisor to n"},
{'N', "nerdjack", NULL, "Force NerdJack device"}, {'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"},
{'R', "range", "a,b", {'R', "range", "a,b",
"Set range on NerdJack for channels 0-5,6-11 to either 5 or 10 (10,10)"}, "Set range on NerdJack for channels 0-5,6-11 to either 5 or 10 (10,10)"},
{'g', "gain", "a,b,c", "Set Labjack AIN channel gains: 0,1,2,4,8 in -C channel order"}, {'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"}, {'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, "convert output to volts/temperature"}, {'c', "convert", NULL, "convert output to volts"},
{'H', "converthex", NULL, "convert output to hex"}, {'H', "converthex", NULL, "convert output to hex"},
{'m', "showmem", NULL, "output memory stats with data (NJ only)"}, {'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"},
{'V', "version", NULL, "show version number and exit"}, {'V', "version", NULL, "show version number and exit"},
{'i', "info", NULL, "get info from device (NJ only)"},
{'X', "examples", NULL, "show ethstream examples and exit"},
{0, NULL, NULL, NULL} {0, NULL, NULL, NULL}
}; };
int doStream (const char *address, uint8_t scanconfig, uint16_t scaninterval, int doStream (const char *address, uint8_t scanconfig, uint16_t scaninterval,
int *channel_list, int channel_count, int *channel_list, int channel_count, int convert,
int *timer_mode_list, int *timer_value_list, int maxlines);
int timer_mode_count, int timer_divisor,
int *gain_list, int gain_count,
int convert, int maxlines);
int nerdDoStream (const char *address, int *channel_list, int channel_count, int nerdDoStream (const char *address, int *channel_list, int channel_count,
int precision, unsigned long period, int convert, int lines, int precision, unsigned long period, int convert, int lines,
int showmem); int showmem);
int data_callback(int channels, int *channel_list, int gain_count, int *gain_list, int data_callback (int channels, uint16_t * data, void *context);
uint16_t * data, void *context);
int columns_left = 0; int columns_left = 0;
void
////////EXTRA GLOBAL VARS/////////// handle_sig (int sig)
// for clean shutdown // {
// added by John Donnal 2015 // while (columns_left--)
////////////////////////////////////
int fd_cmd, fd_data;
int ue9_running = 0; //flag if labjack is currently streaming data
void handle_sig(int sig)
{ {
while (columns_left--) {
printf (" 0"); printf (" 0");
} }
/******************************************************
* added by John Donnal 2015 *
* Close out connection to LabJack, firmware glitches *
* if the stream is not closed correctly *
******************************************************/
if(ue9_running==1){
printf("Performing clean shutdown of LabJack\n");
ue9_stream_stop(fd_cmd);
ue9_buffer_flush(fd_cmd);
ue9_close(fd_data);
ue9_close(fd_cmd);
}
/******************************************************/
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;
@ -128,16 +101,13 @@ int main(int argc, char *argv[])
int forceretry = 0; int forceretry = 0;
int convert = CONVERT_DEC; int convert = CONVERT_DEC;
int showmem = 0; int showmem = 0;
int inform = 0;
uint8_t scanconfig; uint8_t scanconfig;
uint16_t scaninterval; uint16_t scaninterval;
int timer_mode_list[UE9_TIMERS]; #if UE9_CHANNELS > NERDJACK_CHANNELS
int timer_value_list[UE9_TIMERS]; int channel_list[UE9_CHANNELS];
int timer_mode_count = 0; #else
int timer_divisor = 1; int channel_list[NERDJACK_CHANNELS];
int gain_list[MAX_CHANNELS]; #endif
int gain_count = 0;
int channel_list[MAX_CHANNELS];
int channel_count = 0; int channel_count = 0;
int nerdjack = 0; int nerdjack = 0;
int labjack = 0; int labjack = 0;
@ -149,8 +119,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);
@ -159,7 +131,8 @@ int main(int argc, char *argv[])
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 > MAX_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;
} }
@ -168,18 +141,25 @@ 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 != ',')
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 //The rest of the sanity checking can come later after we know
//whether this is a //whether this is a
//LabJack or a NerdJack //LabJack or a NerdJack
if (channel_count >= MAX_CHANNELS) { #if UE9_CHANNELS > NERDJACK_CHANNELS
if (channel_count >= UE9_CHANNELS)
{
#else
if (channel_count >= NERDJACK_CHANNELS)
{
#endif
info ("error: too many channels specified\n"); info ("error: too many channels specified\n");
goto printhelp; goto printhelp;
} }
@ -188,86 +168,26 @@ int main(int argc, char *argv[])
} }
while (*endp); while (*endp);
break; break;
case 'g': /* labjack only */
gain_count = 0;
do {
tmp = strtol(optarg, &endp, 0);
if (*endp != '\0' && *endp != ',') {
info("bad gain number: %s\n",
optarg);
goto printhelp;
}
if (gain_count >= MAX_CHANNELS) {
info("error: too many gains specified\n");
goto printhelp;
}
if (!(tmp == 0 || tmp == 1 || tmp == 2 || tmp == 3 || tmp == 8)) {
info("error: invalid gain specified\n");
goto printhelp;
}
gain_list[gain_count++] = tmp;
optarg = endp + 1;
}
while (*endp);
break;
case 't': /* labjack only */
timer_mode_count = 0;
do {
/* get mode */
tmp = strtol(optarg, &endp, 0);
if (*endp != '\0' && *endp != ',' && *endp != ':') {
info("bad timer mode: %s\n", optarg);
goto printhelp;
}
if (timer_mode_count >= UE9_TIMERS) {
info("error: too many timers specified\n");
goto printhelp;
}
timer_mode_list[timer_mode_count] = tmp;
/* get optional value */
if (*endp == ':') {
optarg = endp + 1;
tmp = strtol(optarg, &endp, 0);
if (*endp != '\0' && *endp != ',') {
info("bad timer value: %s\n", optarg);
goto printhelp;
}
timer_value_list[timer_mode_count] = tmp;
} else {
timer_value_list[timer_mode_count] = 0;
}
timer_mode_count++;
optarg = endp + 1;
}
while (*endp);
break;
case 'T': /* labjack only */
timer_divisor = strtod(optarg, &endp);
if (*endp || timer_divisor < 0 || timer_divisor > 255) {
info("bad timer divisor: %s\n", optarg);
goto printhelp;
}
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 'R': case 'R':
tmp = strtol (optarg, &endp, 0); tmp = strtol (optarg, &endp, 0);
if (*endp != ',') { if (*endp != ',')
{
info ("bad range number: %s\n", optarg); info ("bad range number: %s\n", optarg);
goto printhelp; goto printhelp;
} }
@ -275,8 +195,7 @@ int main(int argc, char *argv[])
info("valid choices for range are 5 or 10\n"); info("valid choices for range are 5 or 10\n");
goto printhelp; goto printhelp;
} }
if (tmp == 5) if(tmp == 5) precision = precision + 1;
precision = precision + 1;
optarg = endp + 1; optarg = endp + 1;
if (*endp == '\0') { if (*endp == '\0') {
@ -292,8 +211,7 @@ int main(int argc, char *argv[])
info("valid choices for range are 5 or 10\n"); info("valid choices for range are 5 or 10\n");
goto printhelp; goto printhelp;
} }
if (tmp == 5) if(tmp == 5) precision = precision + 2;
precision = precision + 2;
break; break;
case 'N': case 'N':
nerdjack++; nerdjack++;
@ -311,14 +229,16 @@ int main(int argc, char *argv[])
forceretry++; forceretry++;
break; break;
case 'c': case 'c':
if (convert != 0) { if (convert != 0)
{
info ("specify only one conversion type\n"); info ("specify only one conversion type\n");
goto printhelp; goto printhelp;
} }
convert = CONVERT_VOLTS; convert = CONVERT_VOLTS;
break; break;
case 'H': case 'H':
if (convert != 0) { if (convert != 0)
{
info ("specify only one conversion type\n"); info ("specify only one conversion type\n");
goto printhelp; goto printhelp;
} }
@ -329,22 +249,14 @@ int main(int argc, char *argv[])
case 'v': case 'v':
verb_count++; verb_count++;
break; break;
case 'X':
printf("%s", examplestring);
return 0;
break;
case 'V': case 'V':
printf("ethstream " 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 John Donnal <jdonnal@mit.edu>\n"); printf ("and Zachary Clifford <zacharyc@mit.edu>\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;
break; break;
case 'i':
inform++;
break;
case 'h': case 'h':
help = stdout; help = stdout;
default: default:
@ -388,148 +300,137 @@ int main(int argc, char *argv[])
doneparse: doneparse:
if (inform) {
//We just want information from NerdJack
if (!detect) {
if (nerd_get_version(address) < 0) {
info("Could not find NerdJack at specified address\n");
} else {
return 0;
}
}
info("Autodetecting NerdJack address\n");
free(address);
if (nerdjack_detect(address) < 0) {
info("Error with autodetection\n");
goto printhelp;
} else {
info("Found NerdJack at address: %s\n", address);
if (nerd_get_version(address) < 0) {
info("Error getting NerdJack version\n");
goto printhelp;
}
return 0;
}
}
if (donerdjack) {
if (channel_count > NERDJACK_CHANNELS) { 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) { {
if (channel_list[i] >= NERDJACK_CHANNELS)
{
info ("Channel is out of NerdJack range: %d\n", info ("Channel is out of NerdJack range: %d\n",
channel_list[i]); channel_list[i]);
goto printhelp; goto printhelp;
} }
} }
} else { }
if (channel_count > UE9_MAX_CHANNEL_COUNT) { 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_MAX_CHANNEL) { {
info("Channel is out of LabJack range: %d\n", if (channel_list[i] >= UE9_CHANNELS)
channel_list[i]); {
info ("Channel is out of LabJack range: %d\n", channel_list[i]);
goto printhelp; goto printhelp;
} }
} }
} }
/* Timer requires Labjack */
if (timer_mode_count && !labjack) {
info("Can't use timers on NerdJack\n");
goto printhelp;
}
/* Individual Analog Channel Gain Set requires Labjack*/
if (gain_count && !labjack) {
info("Can't use Individual Gain Set on NerdJack\n");
goto printhelp;
}
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_no_timestamp(" AIN%d", channel_list[i]); info (" AIN%d", channel_list[i]);
info_no_timestamp("\n"); info ("\n");
} }
/* Figure out actual rate. */ /* Figure out actual rate. */
if (donerdjack) { 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", desired_rate); {
info ("error: can't achieve requested scan rate (%lf Hz)\n",
desired_rate);
} }
} 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", desired_rate); {
info ("error: can't achieve requested scan rate (%lf Hz)\n",
desired_rate);
} }
} }
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); 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);
#ifdef SIGPIPE /* not on Windows */ if (detect)
/* Ignore SIGPIPE so I/O errors to the network device won't kill the process */ {
signal(SIGPIPE, SIG_IGN);
#endif
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");
goto printhelp; goto printhelp;
} else { }
else
{
info ("Found NerdJack at address: %s\n", address); info ("Found NerdJack at address: %s\n", address);
} }
} }
for (;;) {
for (;;)
{
int ret; int ret;
if (donerdjack) { if (donerdjack)
{
ret = ret =
nerdDoStream(address, channel_list, channel_count, nerdDoStream (address, channel_list, channel_count, precision,
precision, period, convert, lines, period, convert, lines, showmem);
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, channel_list, channel_count, convert, lines);
timer_mode_list, timer_value_list,
timer_mode_count, timer_divisor,
gain_list, gain_count,
convert, lines);
verb ("doStream returned %d\n", ret); verb ("doStream returned %d\n", ret);
} }
if (oneshot) if (oneshot)
@ -540,38 +441,42 @@ int main(int argc, char *argv[])
//Neither options specified at command line and first time through. //Neither options specified at command line and first time through.
//Try LabJack //Try LabJack
if (ret == -ENOTCONN && donerdjack && !labjack && !nerdjack) { if (ret == -ENOTCONN && donerdjack && !labjack && !nerdjack)
{
info ("Could not connect NerdJack...Trying LabJack\n"); info ("Could not connect NerdJack...Trying LabJack\n");
donerdjack = 0; donerdjack = 0;
goto doneparse; goto doneparse;
} }
//Neither option supplied, no address, and second time through. //Neither option supplied, no address, and second time through.
//Try autodetection //Try autodetection
if (ret == -ENOTCONN && !donerdjack && !labjack && !nerdjack if (ret == -ENOTCONN && !donerdjack && !labjack && !nerdjack && !addressSpecified) {
&& !addressSpecified) {
info ("Could not connect LabJack...Trying to autodetect Nerdjack\n"); info ("Could not connect LabJack...Trying to autodetect Nerdjack\n");
detect = 1; detect = 1;
donerdjack = 1; donerdjack = 1;
goto doneparse; goto doneparse;
} }
if (ret == -ENOTCONN && nerdjack && !detect if (ret == -ENOTCONN && nerdjack && !detect && !addressSpecified) {
&& !addressSpecified) {
info ("Could not reach NerdJack...Trying to autodetect\n"); info ("Could not reach NerdJack...Trying to autodetect\n");
detect = 1; detect = 1;
goto doneparse; goto doneparse;
} }
if (ret == -ENOTCONN && !forceretry) { 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");
} }
} }
@ -597,36 +502,41 @@ nerdDoStream(const char *address, int *channel_list, int channel_count,
//If this is the first time, set up acquisition //If this is the first time, set up acquisition
//Otherwise try to resume the previous one //Otherwise try to resume the previous one
if (started == 0) { if (started == 0)
{
if (nerd_generate_command if (nerd_generate_command
(&command, channel_list, channel_count, precision, (&command, channel_list, channel_count, precision, period) < 0)
period) < 0) { {
info ("Failed to create configuration command\n"); info ("Failed to create configuration command\n");
goto out; goto out;
} }
if (nerd_send_command(address, "STOP", 4) < 0) { if (nerd_send_command (address, "STOP", 4) < 0)
{
if (first_call) { if (first_call) {
retval = -ENOTCONN; retval = -ENOTCONN;
if (verb_count) if(verb_count) info("Failed to send STOP command\n");
info("Failed to send STOP command\n");
} else { } else {
info ("Failed to send STOP command\n"); info ("Failed to send STOP command\n");
} }
goto out; goto out;
} }
if (nerd_send_command(address, &command, sizeof(command)) < 0) { if (nerd_send_command (address, &command, sizeof (command)) < 0)
{
info ("Failed to send GET command\n"); info ("Failed to send GET command\n");
goto out; goto out;
} }
} else { }
else
{
//If we had a transmission in progress, send a command to resume from there //If we had a transmission in progress, send a command to resume from there
char cmdbuf[10]; char cmdbuf[10];
sprintf (cmdbuf, "SETC%05hd", currentcount); sprintf (cmdbuf, "SETC%05hd", currentcount);
retval = nerd_send_command (address, cmdbuf, strlen (cmdbuf)); retval = nerd_send_command (address, cmdbuf, strlen (cmdbuf));
if (retval == -4) { if (retval == -4)
{
info ("NerdJack was reset\n"); info ("NerdJack was reset\n");
//Assume we have not started yet, reset on this side. //Assume we have not started yet, reset on this side.
//If this routine is retried, start over //If this routine is retried, start over
@ -635,7 +545,9 @@ nerdDoStream(const char *address, int *channel_list, int channel_count,
started = 0; started = 0;
wasreset = 1; wasreset = 1;
goto tryagain; goto tryagain;
} else if (retval < 0) { }
else if (retval < 0)
{
info ("Failed to send SETC command\n"); info ("Failed to send SETC command\n");
goto out; goto out;
} }
@ -646,7 +558,8 @@ nerdDoStream(const char *address, int *channel_list, int channel_count,
/* Open connection */ /* Open connection */
fd_data = nerd_open (address, NERDJACK_DATA_PORT); fd_data = nerd_open (address, NERDJACK_DATA_PORT);
if (fd_data < 0) { if (fd_data < 0)
{
info ("Connect failed: %s:%d\n", address, NERDJACK_DATA_PORT); info ("Connect failed: %s:%d\n", address, NERDJACK_DATA_PORT);
goto out; goto out;
} }
@ -655,10 +568,12 @@ nerdDoStream(const char *address, int *channel_list, int channel_count,
(fd_data, channel_count, channel_list, precision, convert, lines, (fd_data, channel_count, channel_list, precision, convert, lines,
showmem, &currentcount, period, wasreset); showmem, &currentcount, period, wasreset);
wasreset = 0; wasreset = 0;
if (retval == -3) { if (retval == -3)
{
retval = 0; retval = 0;
} }
if (retval < 0) { if (retval < 0)
{
info ("Failed to open data stream\n"); info ("Failed to open data stream\n");
goto out1; goto out1;
} }
@ -676,14 +591,10 @@ nerdDoStream(const char *address, int *channel_list, int channel_count,
int int
doStream (const char *address, uint8_t scanconfig, uint16_t scaninterval, doStream (const char *address, uint8_t scanconfig, uint16_t scaninterval,
int *channel_list, int channel_count, int *channel_list, int channel_count, int convert, int lines)
int *timer_mode_list, int *timer_value_list,
int timer_mode_count, int timer_divisor,
int *gain_list, int gain_count,
int convert, int lines)
{ {
int retval = -EAGAIN; int retval = -EAGAIN;
// int fd_cmd, fd_data; *these are now globals so sighandler can use them* int fd_cmd, fd_data;
int ret; int ret;
static int first_call = 1; static int first_call = 1;
struct callbackInfo ci = { struct callbackInfo ci = {
@ -694,7 +605,8 @@ 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;
@ -709,54 +621,39 @@ 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;
} }
/* Set timer configuration */
if (timer_mode_count &&
ue9_timer_config(fd_cmd, timer_mode_list, timer_value_list,
timer_mode_count, timer_divisor) < 0) {
info("Failed to set timer configuration\n");
goto out2;
}
if (gain_count) {
/* Set stream configuration */
if (ue9_streamconfig(fd_cmd, channel_list, channel_count,
scanconfig, scaninterval,
gain_list, gain_count) < 0) {
info("Failed to set stream configuration\n");
goto out2;
}
} else {
/* 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 */
ue9_running = 1; ret = ue9_stream_data (fd_data, channel_count, data_callback, (void *) &ci);
ret = if (ret < 0)
ue9_stream_data(fd_data, channel_count, channel_list, gain_count, gain_list, data_callback, (void *)&ci); {
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;
} }
@ -773,53 +670,46 @@ doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval,
out1: out1:
ue9_close (fd_cmd); ue9_close (fd_cmd);
out: out:
ue9_running = 0;
return retval; return retval;
} }
int data_callback(int channels, int *channel_list, int gain_count, int *gain_list, 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 == CONVERT_VOLTS &&
channel_list[i] <= UE9_MAX_ANALOG_CHANNEL) {
/* CONVERT_VOLTS */
if (i < gain_count)
{ {
if (printf("%lf", ue9_binary_to_analog( switch (ci->convert)
&ci->calib, gain_list[i], {
12, data[i])) < 0) case CONVERT_VOLTS:
if (printf
("%lf",
ue9_binary_to_analog (&ci->calib, UE9_BIPOLAR_GAIN1, 12,
data[i])) < 0)
goto bad; goto bad;
} else { break;
if (printf("%lf", ue9_binary_to_analog( case CONVERT_HEX:
&ci->calib, 0,
12, data[i])) < 0)
goto bad;
}
} else if (ci->convert == CONVERT_VOLTS &&
(channel_list[i] == 141 || channel_list[i] == 133)) {
/* CONVERT_VOLTS but output temperature */
if (printf("%lf", ue9_binary_to_temperature(
&ci->calib, data[i])) < 0)
goto bad;
} else if (ci->convert == CONVERT_HEX) {
/* CONVERT_HEX */
if (printf ("%04X", data[i]) < 0) if (printf ("%04X", data[i]) < 0)
goto bad; goto bad;
} else { break;
/* CONVERT_DEC */ default:
case CONVERT_DEC:
if (printf ("%d", data[i]) < 0) if (printf ("%d", data[i]) < 0)
goto bad; goto bad;
break;
} }
columns_left--; columns_left--;
if (i < (channels - 1)) { if (i < (channels - 1))
{
if (ci->convert != CONVERT_HEX && putchar (' ') < 0) if (ci->convert != CONVERT_HEX && putchar (' ') < 0)
goto bad; goto bad;
} else { }
else
{
if (putchar ('\n') < 0) if (putchar ('\n') < 0)
goto bad; goto bad;
lines++; lines++;

View File

@ -5,6 +5,4 @@
#define CONVERT_VOLTS 1 #define CONVERT_VOLTS 1
#define CONVERT_HEX 2 #define CONVERT_HEX 2
#define TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
#endif #endif

View File

@ -1,106 +0,0 @@
char examplestring[] = "\n\
\n\
Welcome to the NILM Ethstream examples.\n\
\n\
For the most part, typing \"ethstream\" by itself will sample the first\n\
two channels at 8 kHz on 10V range. Press CTRL-C to terminate sampling.\n\
\n\
If you want current measurements on the first two phases of NILM\n\
with default sample rate of 8 kHz and 10V range:\n\
\n\
ethstream -C 0,3\n\
\n\
The device is configured so that channels 0 through 2 are currents for\n\
the three phases and channels 3-5 are for voltages of the three phases.\n\
The current channels sample voltages that will depend on the DIP switch\n\
settings in the NILM box. The DIP switch positions allow you to convert\n\
ethstream's readings to true current readings.\n\
\n\
If you want only currents at 16 kHz and 10V range:\n\
\n\
ethstream -n 3 -r 16000\n\
\n\
The -n option samples a number of channels starting at 0. The rate can be\n\
at least 16000 if 12 channels are sampled , but it can do more if\n\
fewer channels are sampled. The limiting factor is the highest channel\n\
sampled. Sampling just the top channel (11) is as bad as sampling\n\
all 12 at once.\n\
Ethstream will warn if you approach the limits of the NerdJack with the\n\
given sampled channels. Sampling outside the range of the NerdJack might\n\
result in corrupt data or crashing of the device. There will be no\n\
permanent damage to NILM or NerdJack, but be aware of the possibility of\n\
data corruption.\n\
\n\
If you need a higher accuracy but lower range measurement on the voltages:\n\
\n\
ethstream -R 5,10 -C 3,4,5\n\
\n\
The two numbers to the R command set the range to either 5V or 10V. Above,\n\
we are setting channels 0-5 to 5 V range and channels 6-11 to 10 V range.\n\
Channels 6-11 are unconnected, but they can have range set independently.\n\
\n\
All of the above examples output a digital number from 0 to 65535 with\n\
65535 representing the highest range (5V or 10V). 0 represents the most\n\
negative range (-5V or -10V). If you want conversion\n\
to volts for all six voltages and currents:\n\
\n\
ethstream -c -C 0,3,1,4,2,5\n\
\n\
The channels will be output in the order given in the C command. This\n\
command will group the current and voltage data by phase.\n\
\n\
If you are supplying data from ethstream to another program, you might\n\
want to dump its output to a file and terminate after a certain number of\n\
samples:\n\
\n\
ethstream -n 6 -r 8000 - l 16000 > outfile.dat\n\
\n\
This will take 16000 samples at 8 kHz (2 seconds of acquisition) of all\n\
channels and write the data to outfile.dat. This can be directly read\n\
by a package like MATLAB.\n\
\n\
If there are multiple NerdJacks or you have changed the TCP/IP settings\n\
from default, you might have to specify which one you want to talk to:\n\
\n\
ethstream -a 192.168.1.210\n\
\n\
This will sample two channels at 8 kHz from the NerdJack at 192.168.1.210.\n\
This is the default \"1\" setting on the NerdJack. If no address is\n\
specified, ethstream connects first to 192.168.1.209. It then tries\n\
to autodetect the NerdJack. This should find the device if you are on\n\
the same network, but it will get confused if there are multiple NerdJacks\n\
on the network.\n\
\n\
Labjack only Timer modes are also avaliable. Read the Labjack UE9 Users Guide\n\
for more information. Upto 6 timers of various modes can be specified,\n\
they occur on FIO0-FIO5 which are on channels 200-205 respectively in order\n\
of specification. For 32 bit timer modes, the MSW should be read from\n\
channel 224 imeadiately after the LSW is read from one the timer channel.\n\
A clock frequency divisor is specified on a per device basis. For example:\n\
\n\
ethstream -t 4,12 -T 1 -C 200,224,201\n\
\n\
This will enable two timers with the fastest system clock divisor (48 MhZ/1)\n\
and read the two 16 bit words for timer mode 4 and the single 16 bit word of\n\
timer mode 12. These three words will occupy their own columns in the output\n\
stream. Digital timer mode channels can be interspersed with analog inouts.\n\
\n\
Labjack only individual analog input channel gain set is also avaliable.\n\
Gain 0 is default on labjack and corresponds to -5.18v to +5.07v. Gain 1 is\n\
is -0.01 to +5.07v. Gain 2 is -0.01 to +2.53v. Gain 4 is -0.01 to +1.26v.\n\
Gain 8 is -0.01 to +0.62v. Gains on the -g flag should be put in the desired\n\
order corresponding to the channels as specified by the -C flag. If there are\n\
less gains specified than channels the remainder default to gain 0. Extra gains\n\
are ignored. Gains can be specified for digital inputs or timer modes but they\n\
are irrelevant. A case where one should do this is if there are dital input\n\
channels intersperced within analog input channels; this keeps the order matched\n\
up so later analog input channels have the expected gain.\n\
\n\
ethstream -t 4 -T 1 -C 0,1,200,224,2,3 -g 2,2,0,0,4,4 -c\n\
\n\
This will set channles 0,1 and 2,3 to gain 2,2 and 4,4, respectively and convert\n\
the data to volts using the firmware stored factory calibrated data on the\n\
labjack. The digital channels 200 and 224 will remain undisturbed as integers.\n\
\n\
";

102
ljconfig.c Normal file
View File

@ -0,0 +1,102 @@
/*
* Labjack Tools
* Copyright (c) 2003-2007 Jim Paris <jim@jtan.com>
*
* This is free software; you can redistribute it and/or modify it and
* it is provided under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation; see COPYING.
*/
/* ljconfig: display/change comm/control processor configuration */
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "debug.h"
#include "ue9.h"
#include "ue9error.h"
#include "opt.h"
#include "version.h"
#define DEFAULT_HOST "192.168.1.209"
#define UE9_COMMAND_PORT 52360
struct options opt[] = {
{'a', "address", "string", "host/address of UE9 (192.168.1.209)"},
{'h', "help", NULL, "this help"},
{'v', "verbose", NULL, "be verbose"},
{'V', "version", NULL, "show version number and exit"},
{0, NULL, NULL, NULL}
};
int
main (int argc, char *argv[])
{
int optind;
char *optarg;
char c;
FILE *help = stderr;
char *address = strdup (DEFAULT_HOST);
int fd;
int ret;
/* Parse arguments */
opt_init (&optind);
while ((c = opt_parse (argc, argv, &optind, &optarg, opt)) != 0)
{
switch (c)
{
case 'a':
free (address);
address = strdup (optarg);
break;
case 'v':
verb_count++;
break;
case 'V':
printf ("ljconfig " VERSION "\n");
printf ("Written by Jim Paris <jim@jtan.com>\n");
printf ("This program comes with no warranty and is "
"provided under the GPLv2.\n");
return 0;
break;
case 'h':
help = stdout;
default:
printhelp:
fprintf (help, "Usage: %s [options]\n", *argv);
opt_help (opt, help);
fprintf (help, "Displays/changes Labjack UE9 config.\n");
return (help == stdout) ? 0 : 1;
}
}
if (optind < argc)
{
info ("Error: too many arguments (%s)\n\n", argv[optind]);
goto printhelp;
}
ret = 1;
/* Open */
fd = ue9_open (address, UE9_COMMAND_PORT);
if (fd < 0)
{
info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT);
goto out0;
}
goto out1;
ret = 0;
out1:
/* Close */
ue9_close (fd);
out0:
return ret;
}

68
ljtest.c Normal file
View File

@ -0,0 +1,68 @@
/*
* Labjack Tools
* Copyright (c) 2003-2007 Jim Paris <jim@jtan.com>
*
* This is free software; you can redistribute it and/or modify it and
* it is provided under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation; see COPYING.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "debug.h"
#include "ue9.h"
#include "compat.h"
int
main (int argc, char *argv[])
{
int fd_cmd;
struct ue9Calibration calib;
verb_count = 2;
fd_cmd = ue9_open ("192.168.1.209", 52360);
if (fd_cmd < 0)
{
fprintf (stderr, "ue9_open: %s\n", compat_strerror (errno));
return 1;
}
if (ue9_get_calibration (fd_cmd, &calib) < 0)
{
fprintf (stderr, "ue9_get_calibration: %s\n", compat_strerror (errno));
return 1;
}
printf ("double unipolarSlope[0] = %lf\n", calib.unipolarSlope[0]);
printf ("double unipolarSlope[1] = %lf\n", calib.unipolarSlope[1]);
printf ("double unipolarSlope[2] = %lf\n", calib.unipolarSlope[2]);
printf ("double unipolarSlope[3] = %lf\n", calib.unipolarSlope[3]);
printf ("double unipolarOffset[0] = %lf\n", calib.unipolarOffset[0]);
printf ("double unipolarOffset[1] = %lf\n", calib.unipolarOffset[1]);
printf ("double unipolarOffset[2] = %lf\n", calib.unipolarOffset[2]);
printf ("double unipolarOffset[3] = %lf\n", calib.unipolarOffset[3]);
printf ("double bipolarSlope = %lf\n", calib.bipolarSlope);
printf ("double bipolarOffset = %lf\n", calib.bipolarOffset);
printf ("double DACSlope[0] = %lf\n", calib.DACSlope[0]);
printf ("double DACSlope[1] = %lf\n", calib.DACSlope[1]);
printf ("double DACOffset[0] = %lf\n", calib.DACOffset[0]);
printf ("double DACOffset[1] = %lf\n", calib.DACOffset[1]);
printf ("double tempSlope = %lf\n", calib.tempSlope);
printf ("double tempSlopeLow = %lf\n", calib.tempSlopeLow);
printf ("double calTemp = %lf\n", calib.calTemp);
printf ("double Vref = %lf\n", calib.Vref);
printf ("double VrefDiv2 = %lf\n", calib.VrefDiv2);
printf ("double VsSlope = %lf\n", calib.VsSlope);
printf ("double hiResUnipolarSlope = %lf\n", calib.hiResUnipolarSlope);
printf ("double hiResUnipolarOffset = %lf\n", calib.hiResUnipolarOffset);
printf ("double hiResBipolarSlope = %lf\n", calib.hiResBipolarSlope);
printf ("double hiResBipolarOffset = %lf\n", calib.hiResBipolarOffset);
ue9_close (fd_cmd);
return 0;
}

View File

@ -25,10 +25,13 @@
#include "netutil.h" #include "netutil.h"
#include "ethstream.h" #include "ethstream.h"
#define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
#define NERD_HEADER_SIZE 8 #define NERD_HEADER_SIZE 8
#define MAX_SOCKETS 32 #define MAX_SOCKETS 32
typedef struct __attribute__ ((__packed__)) { typedef struct __attribute__ ((__packed__))
{
unsigned char headerone; unsigned char headerone;
unsigned char headertwo; unsigned char headertwo;
unsigned short packetNumber; unsigned short packetNumber;
@ -58,7 +61,8 @@ nerdjack_choose_scan(double desired_rate, double *actual_rate,
//devices so far. It is worked around on the chip, but giving it exactly //devices so far. It is worked around on the chip, but giving it exactly
//0xfffff would cause the workaround code to roll over. //0xfffff would cause the workaround code to roll over.
*period = floor ((double) NERDJACK_CLOCK_RATE / desired_rate); *period = floor ((double) NERDJACK_CLOCK_RATE / desired_rate);
if (*period > 0x0ffffe) { if (*period > 0x0ffffe)
{
info ("Cannot sample that slowly\n"); info ("Cannot sample that slowly\n");
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) 0x0ffffe; *actual_rate = (double) NERDJACK_CLOCK_RATE / (double) 0x0ffffe;
*period = 0x0ffffe; *period = 0x0ffffe;
@ -66,7 +70,8 @@ nerdjack_choose_scan(double desired_rate, double *actual_rate,
} }
//Period holds the period register for the NerdJack, so it needs to be right //Period holds the period register for the NerdJack, so it needs to be right
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period; *actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period;
if (*actual_rate != desired_rate) { if (*actual_rate != desired_rate)
{
return -1; return -1;
} }
return 0; return 0;
@ -76,8 +81,7 @@ nerdjack_choose_scan(double desired_rate, double *actual_rate,
* Create a discovered socket and add it to the socket list structure. * 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 * 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, static int discovered_sock_create(struct discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)
uint32_t subnet_mask)
{ {
if (ds->sock_count >= MAX_SOCKETS) { if (ds->sock_count >= MAX_SOCKETS) {
return 0; return 0;
@ -91,13 +95,12 @@ static int discovered_sock_create(struct discover_t *ds, uint32_t local_ip,
/* Allow broadcast. */ /* Allow broadcast. */
int sock_opt = 1; int sock_opt = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
sizeof(sock_opt));
/* Set nonblocking */ /* Set nonblocking */
if (soblock(sock, 0) < 0) { if (soblock (sock, 0) < 0)
{
verb ("can't set nonblocking\n"); verb ("can't set nonblocking\n");
close(sock);
return 0; return 0;
} }
@ -120,15 +123,13 @@ static int discovered_sock_create(struct discover_t *ds, uint32_t local_ip,
return 1; return 1;
} }
/** /**
* Enumerate all interfaces we can find and open sockets on each * Enumerate all interfaces we can find and open sockets on each
*/ */
#if defined(USE_IPHLPAPI) #if defined(USE_IPHLPAPI)
static void enumerate_interfaces(struct discover_t *ds) static void enumerate_interfaces(struct discover_t *ds)
{ {
PIP_ADAPTER_INFO pAdapterInfo = PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
(IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO); ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
DWORD Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen); DWORD Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
@ -149,10 +150,8 @@ static void enumerate_interfaces(struct discover_t *ds)
while (pAdapter) { while (pAdapter) {
IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList;
while (pIPAddr) { while (pIPAddr) {
uint32_t local_ip = uint32_t local_ip = ntohl(inet_addr(pIPAddr->IpAddress.String));
ntohl(inet_addr(pIPAddr->IpAddress.String)); uint32_t mask = ntohl(inet_addr(pIPAddr->IpMask.String));
uint32_t mask =
ntohl(inet_addr(pIPAddr->IpMask.String));
if (local_ip == 0) { if (local_ip == 0) {
pIPAddr = pIPAddr->Next; pIPAddr = pIPAddr->Next;
@ -170,8 +169,7 @@ static void enumerate_interfaces(struct discover_t *ds)
} }
#else #else
static void enumerate_interfaces(struct discover_t *ds) static void enumerate_interfaces(struct discover_t *ds) {
{
int fd = socket(AF_INET, SOCK_DGRAM, 0); int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) { if (fd == -1) {
return; return;
@ -199,8 +197,7 @@ static void enumerate_interfaces(struct discover_t *ds)
if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
continue; continue;
} }
struct sockaddr_in *addr_in = struct sockaddr_in *addr_in = (struct sockaddr_in *)&(ifr->ifr_addr);
(struct sockaddr_in *)&(ifr->ifr_addr);
uint32_t local_ip = ntohl(addr_in->sin_addr.s_addr); uint32_t local_ip = ntohl(addr_in->sin_addr.s_addr);
if (local_ip == 0) { if (local_ip == 0) {
continue; continue;
@ -210,8 +207,7 @@ static void enumerate_interfaces(struct discover_t *ds)
continue; continue;
} }
struct sockaddr_in *mask_in = struct sockaddr_in *mask_in = (struct sockaddr_in *)&(ifr->ifr_addr);
(struct sockaddr_in *)&(ifr->ifr_addr);
uint32_t mask = ntohl(mask_in->sin_addr.s_addr); uint32_t mask = ntohl(mask_in->sin_addr.s_addr);
discovered_sock_create(ds, local_ip, mask); discovered_sock_create(ds, local_ip, mask);
@ -232,17 +228,19 @@ static void destroy_socks(struct discover_t *ds)
free(ds); free(ds);
} }
/* Perform autodetection. Returns 0 on success, -1 on error /* Perform autodetection. Returns 0 on success, -1 on error
* Sets ipAddress to the detected address * Sets ipAddress to the detected address
*/ */
int nerdjack_detect(char *ipAddress) int
nerdjack_detect (char *ipAddress)
{ {
int32_t receivesock; int32_t receivesock;
struct sockaddr_in sa, receiveaddr, sFromAddr; struct sockaddr_in sa, receiveaddr, sFromAddr;
int buffer_length; int buffer_length;
char buffer[200]; char buffer[200];
char incomingData[10]; char incomingData[10];
socklen_t lFromLen; unsigned int lFromLen;
sprintf (buffer, "TEST"); sprintf (buffer, "TEST");
buffer_length = strlen (buffer) + 1; buffer_length = strlen (buffer) + 1;
@ -252,15 +250,18 @@ int nerdjack_detect(char *ipAddress)
receivesock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); receivesock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
/* Set nonblocking */ /* Set nonblocking */
if (soblock(receivesock, 0) < 0) { if (soblock (receivesock, 0) < 0)
{
verb ("can't set nonblocking\n"); verb ("can't set nonblocking\n");
return -1; return -1;
} }
if (-1 == receivesock) { /* if socket failed to initialize, exit */ if (-1 == receivesock) /* if socket failed to initialize, exit */
{
verb ("Error Creating Socket\n"); verb ("Error Creating Socket\n");
return -1; return -1;
} }
//Setup family for both sockets //Setup family for both sockets
sa.sin_family = PF_INET; sa.sin_family = PF_INET;
receiveaddr.sin_family = PF_INET; receiveaddr.sin_family = PF_INET;
@ -275,8 +276,7 @@ int nerdjack_detect(char *ipAddress)
bind (receivesock, (struct sockaddr *) &receiveaddr, bind (receivesock, (struct sockaddr *) &receiveaddr,
sizeof (struct sockaddr_in)); sizeof (struct sockaddr_in));
struct discover_t *ds = struct discover_t *ds = (struct discover_t *)calloc(1, sizeof(struct discover_t));
(struct discover_t *)calloc(1, sizeof(struct discover_t));
if (!ds) { if (!ds) {
return -1; return -1;
} }
@ -299,8 +299,8 @@ int nerdjack_detect(char *ipAddress)
struct discovered_socket *dss = &ds->socks[i]; struct discovered_socket *dss = &ds->socks[i];
uint32_t target_ip = dss->local_ip | ~dss->subnet_mask; uint32_t target_ip = dss->local_ip | ~dss->subnet_mask;
sa.sin_addr.s_addr = htonl(target_ip); sa.sin_addr.s_addr = htonl(target_ip);
sendto(dss->sock, buffer, buffer_length, 0, sendto (dss->sock, buffer, buffer_length, 0, (struct sockaddr *) &sa,
(struct sockaddr *)&sa, sizeof(struct sockaddr_in)); sizeof (struct sockaddr_in));
} }
destroy_socks(ds); destroy_socks(ds);
@ -310,8 +310,10 @@ int nerdjack_detect(char *ipAddress)
if (0 > if (0 >
recvfrom_timeout (receivesock, incomingData, sizeof (incomingData), 0, recvfrom_timeout (receivesock, incomingData, sizeof (incomingData), 0,
(struct sockaddr *) &sFromAddr, &lFromLen, (struct sockaddr *) &sFromAddr, &lFromLen,
&(struct timeval) { &(struct timeval)
.tv_sec = TIMEOUT})) { {
.tv_sec = NERDJACK_TIMEOUT}))
{
close(receivesock); close(receivesock);
return -1; return -1;
} }
@ -325,77 +327,46 @@ int nerdjack_detect(char *ipAddress)
return 0; return 0;
} }
/*
* Get the NerdJack version string and print it
*/
int nerd_get_version(const char *address)
{
int ret, fd_command;
char buf[200];
fd_command = nerd_open(address, NERDJACK_COMMAND_PORT);
if (fd_command < 0) {
info("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT);
return -2;
}
/* Send request */
ret = send_all_timeout(fd_command, "VERS", 4, 0, &(struct timeval) {
.tv_sec = TIMEOUT});
if (ret < 0) {
verb("short send %d\n", (int)ret);
return -1;
}
ret = recv_all_timeout(fd_command, buf, 200, 0, &(struct timeval) {
.tv_sec = TIMEOUT});
nerd_close_conn(fd_command);
if (ret < 0) {
verb("Error receiving command\n");
return -1;
}
//Slice off the "OK" from the string
buf[strlen(buf) - 2] = '\0';
printf("%s\n", buf);
return 0;
}
/* Send the given command to address. The command should be something /* Send the given command to address. The command should be something
* of the specified length. This expects the NerdJack to reply with OK * of the specified length. This expects the NerdJack to reply with OK
* or NO * or NO
*/ */
int nerd_send_command(const char *address, void *command, int length) int
nerd_send_command (const char *address, void *command, int length)
{ {
int ret, fd_command; int ret, fd_command;
char buf[3]; char buf[3];
fd_command = nerd_open (address, NERDJACK_COMMAND_PORT); fd_command = nerd_open (address, NERDJACK_COMMAND_PORT);
if (fd_command < 0) { if (fd_command < 0)
{
info ("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT); info ("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT);
return -2; return -2;
} }
/* Send request */ /* Send request */
ret = send_all_timeout(fd_command, command, length, 0, &(struct timeval) { ret = send_all_timeout (fd_command, command, length, 0, &(struct timeval)
.tv_sec = TIMEOUT}); {
if (ret < 0 || ret != length) { .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;
} }
ret = recv_all_timeout(fd_command, buf, 3, 0, &(struct timeval) { ret = recv_all_timeout (fd_command, buf, 3, 0, &(struct timeval)
.tv_sec = TIMEOUT}); {
.tv_sec = NERDJACK_TIMEOUT});
nerd_close_conn (fd_command); nerd_close_conn (fd_command);
if (ret < 0 || ret != 3) { if (ret < 0 || ret != 3)
{
verb ("Error receiving OK for command\n"); verb ("Error receiving OK for command\n");
return -1; return -1;
} }
if (0 != strcmp("OK", buf)) { if (0 != strcmp ("OK", buf))
{
verb ("Did not receive OK. Received %s\n", buf); verb ("Did not receive OK. Received %s\n", buf);
return -4; return -4;
} }
@ -403,6 +374,7 @@ int nerd_send_command(const char *address, void *command, int length)
return 0; return 0;
} }
int int
nerd_data_stream (int data_fd, int numChannels, int *channel_list, nerd_data_stream (int data_fd, int numChannels, int *channel_list,
int precision, int convert, int lines, int showmem, int precision, int convert, int lines, int showmem,
@ -422,11 +394,13 @@ nerd_data_stream(int data_fd, int numChannels, int *channel_list,
//The number sampled will be the highest channel requested plus 1 //The number sampled will be the highest channel requested plus 1
//(i.e. channel 0 requested means 1 sampled) //(i.e. channel 0 requested means 1 sampled)
for (i = 0; i < numChannels; i++) { for (i = 0; i < numChannels; i++)
{
if (channel_list[i] + 1 > numChannelsSampled) if (channel_list[i] + 1 > numChannelsSampled)
numChannelsSampled = channel_list[i] + 1; numChannelsSampled = channel_list[i] + 1;
} }
double voltline[numChannels]; double voltline[numChannels];
unsigned short dataline[numChannels]; unsigned short dataline[numChannels];
@ -446,48 +420,64 @@ nerd_data_stream(int data_fd, int numChannels, int *channel_list,
//Check to see if we're trying to resume //Check to see if we're trying to resume
//Don't blow away linesleft in that case //Don't blow away linesleft in that case
if (lines != 0 && linesleft == 0) { if (lines != 0 && linesleft == 0)
{
linesleft = lines; linesleft = lines;
} }
//If there was a reset, we still need to dump a line because of faulty PDCA start //If there was a reset, we still need to dump a line because of faulty PDCA start
if (wasreset) { if (wasreset)
{
linesdumped = 0; linesdumped = 0;
} }
//If this is the first time called, warn the user if we're too fast //If this is the first time called, warn the user if we're too fast
if (linesdumped == 0) { if (linesdumped == 0)
if (period < (numChannelsSampled * 200 + 600)) { {
if (period < (numChannelsSampled * 200 + 600))
{
info ("You are sampling close to the limit of NerdJack\n"); info ("You are sampling close to the limit of NerdJack\n");
info ("Sample fewer channels or sample slower\n"); info ("Sample fewer channels or sample slower\n");
} }
} }
//Now destination structure array is set as well as numDuplicates. //Now destination structure array is set as well as numDuplicates.
int totalGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled; int totalGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled;
//Loop forever to grab data //Loop forever to grab data
while ((charsread = while ((charsread =
recv_all_timeout (data_fd, &buf, NERDJACK_PACKET_SIZE, 0, recv_all_timeout (data_fd, &buf, NERDJACK_PACKET_SIZE, 0,
&(struct timeval) { &(struct timeval)
.tv_sec = expectedtimeout}))) { {
.tv_sec = expectedtimeout})))
{
if (charsread != NERDJACK_PACKET_SIZE) { if (charsread != NERDJACK_PACKET_SIZE)
{
//There was a problem getting data. Probably a closed //There was a problem getting data. Probably a closed
//connection. //connection.
info ("Packet timed out or was too short\n"); info ("Packet timed out or was too short\n");
return -2; return -2;
} }
//First check the header info //First check the header info
if (buf.headerone != 0xF0 || buf.headertwo != 0xAA) { if (buf.headerone != 0xF0 || buf.headertwo != 0xAA)
{
info ("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 = ntohs (buf.packetNumber); tempshort = ntohs (buf.packetNumber);
if (tempshort != *currentcount) { if (tempshort != *currentcount)
info("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 + 1; *currentcount = *currentcount + 1;
@ -495,83 +485,86 @@ nerd_data_stream(int data_fd, int numChannels, int *channel_list,
packetsready = ntohs (buf.packetsready); packetsready = ntohs (buf.packetsready);
numgroupsProcessed = 0; numgroupsProcessed = 0;
if (showmem) { if (showmem)
{
printf ("%hd %hd\n", adcused, packetsready); printf ("%hd %hd\n", adcused, packetsready);
continue; continue;
} }
//While there is still more data in the packet, process it //While there is still more data in the packet, process it
while (numgroupsProcessed < totalGroups) { while (numgroupsProcessed < totalGroups)
{
//Poison the data structure //Poison the data structure
switch (convert) { switch (convert)
{
case CONVERT_VOLTS: case CONVERT_VOLTS:
memset(voltline, 0, memset (voltline, 0, numChannels * sizeof (double));
numChannels * sizeof(double));
break; break;
default: default:
case CONVERT_HEX: case CONVERT_HEX:
case CONVERT_DEC: case CONVERT_DEC:
memset(dataline, 0, memset (dataline, 0, numChannels * sizeof (unsigned char));
numChannels * sizeof(unsigned char));
} }
//Read in each group //Read in each group
for (i = 0; i < numChannels; i++) { for (i = 0; i < numChannels; i++)
{
//Get the datapoint associated with the desired channel //Get the datapoint associated with the desired channel
datapoint = datapoint =
ntohs(buf.data[channel_list[i] + ntohs (buf.
numgroupsProcessed * data[channel_list[i] +
numChannelsSampled]); numgroupsProcessed * numChannelsSampled]);
//Place it into the line //Place it into the line
switch (convert) { switch (convert)
{
case CONVERT_VOLTS: case CONVERT_VOLTS:
if (channel_list[i] <= 5) { if (channel_list[i] <= 5)
{
volts = volts =
(double)(datapoint / (double) (datapoint / 32767.0) *
32767.0) * ((precision & 0x01) ? 5.0 : 10.0);
((precision & 0x01) ? 5.0 : }
10.0); else
} else { {
volts = volts =
(double)(datapoint / (double) (datapoint / 32767.0) *
32767.0) * ((precision & 0x02) ? 5.0 : 10.0);
((precision & 0x02) ? 5.0 :
10.0);
} }
voltline[i] = volts; voltline[i] = volts;
break; break;
default: default:
case CONVERT_HEX: case CONVERT_HEX:
case CONVERT_DEC: case CONVERT_DEC:
dataline[i] = dataline[i] = (unsigned short) (datapoint - INT16_MIN);
(unsigned short)(datapoint -
INT16_MIN);
break; break;
} }
} }
//We want to dump the first line because it's usually spurious //We want to dump the first line because it's usually spurious
if (linesdumped != 0) { if (linesdumped != 0)
{
//Now print the group //Now print the group
switch (convert) { switch (convert)
{
case CONVERT_VOLTS: case CONVERT_VOLTS:
for (i = 0; i < numChannels; i++) { for (i = 0; i < numChannels; i++)
if (printf("%lf ", voltline[i]) {
< 0) if (printf ("%lf ", voltline[i]) < 0)
goto bad; goto bad;
} }
break; break;
case CONVERT_HEX: case CONVERT_HEX:
for (i = 0; i < numChannels; i++) { for (i = 0; i < numChannels; i++)
if (printf("%04hX", dataline[i]) {
< 0) if (printf ("%04hX", dataline[i]) < 0)
goto bad; goto bad;
} }
break; break;
default: default:
case CONVERT_DEC: case CONVERT_DEC:
for (i = 0; i < numChannels; i++) { for (i = 0; i < numChannels; i++)
if (printf("%hu ", dataline[i]) {
< 0) if (printf ("%hu ", dataline[i]) < 0)
goto bad; goto bad;
} }
break; break;
@ -580,14 +573,18 @@ nerd_data_stream(int data_fd, int numChannels, int *channel_list,
goto bad; goto bad;
//If we're counting lines, decrement them //If we're counting lines, decrement them
if (lines != 0) { if (lines != 0)
{
linesleft--; linesleft--;
if (linesleft == 0) { if (linesleft == 0)
{
return 0; return 0;
} }
} }
} else { }
else
{
linesdumped = linesdumped + 1; linesdumped = linesdumped + 1;
} }
@ -606,7 +603,8 @@ nerd_data_stream(int data_fd, int numChannels, int *channel_list,
} }
/* Open a connection to the NerdJack */ /* Open a connection to the NerdJack */
int nerd_open(const char *address, int port) int
nerd_open (const char *address, int port)
{ {
struct hostent *he; struct hostent *he;
@ -615,13 +613,15 @@ int nerd_open(const char *address, int port)
int32_t i32SocketFD = socket (PF_INET, SOCK_STREAM, 0); int32_t i32SocketFD = socket (PF_INET, SOCK_STREAM, 0);
if (-1 == i32SocketFD) { if (-1 == i32SocketFD)
{
verb ("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;
} }
@ -633,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;
} }
@ -644,11 +645,12 @@ int nerd_open(const char *address, int port)
/* Connect */ /* Connect */
if (connect_timeout if (connect_timeout
(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof (stSockAddr), (i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof (stSockAddr),
&(struct timeval) { &(struct timeval)
.tv_sec = 3}) < 0) { {
.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, inet_ntoa (stSockAddr.sin_addr), port, compat_strerror (errno));
compat_strerror(errno));
return -1; return -1;
} }
@ -665,14 +667,17 @@ nerd_generate_command(getPacket * command, int *channel_list,
int i; int i;
int highestchannel = 0; int highestchannel = 0;
for (i = 0; i < channel_count; i++) { for (i = 0; i < channel_count; i++)
if (channel_list[i] > highestchannel) { {
if (channel_list[i] > highestchannel)
{
highestchannel = channel_list[i]; highestchannel = channel_list[i];
} }
//channelbit = channelbit | (0x1 << channel_list[i]); //channelbit = channelbit | (0x1 << channel_list[i]);
} }
for (i = 0; i <= highestchannel; i++) { for (i = 0; i <= highestchannel; i++)
{
channelbit = channelbit | (0x01 << i); channelbit = channelbit | (0x01 << i);
} }
@ -689,7 +694,8 @@ nerd_generate_command(getPacket * command, int *channel_list,
} }
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

@ -25,10 +25,10 @@
#define NERDJACK_NUM_SAMPLES 726 #define NERDJACK_NUM_SAMPLES 726
/* Packet structure used in message to start sampling on NerdJack */ /* Packet structure used in message to start sampling on NerdJack */
typedef struct __attribute__ ((__packed__)) { typedef struct __attribute__ ((__packed__))
{
char word[4]; char word[4];
unsigned int period; //CHANGED FROM TYPE LONG. With 64 bit compilers longs are 8 bytes and nerdjack expects a 4 byte value unsigned long period;
//since the int type is 4 bytes this works but should be changed to use defined datatypes rather than rely on compiler data types
unsigned short channelbit; unsigned short channelbit;
unsigned char precision; unsigned char precision;
unsigned char prescaler; unsigned char prescaler;
@ -46,9 +46,6 @@ int nerd_generate_command(getPacket * command, int *channel_list,
/* Send given command to NerdJack */ /* Send given command to NerdJack */
int nerd_send_command (const char *address, void *command, int length); int nerd_send_command (const char *address, void *command, int length);
/* Get the version string from NerdJack */
int nerd_get_version(const char *address);
/* Stream data out of the NerdJack */ /* Stream data out of the NerdJack */
int nerd_data_stream (int data_fd, int numChannels, int *channel_list, int nerd_data_stream (int data_fd, int numChannels, int *channel_list,
int precision, int convert, int lines, int showmem, int precision, int convert, int lines, int showmem,

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;
} }
@ -44,6 +47,7 @@ int soblock(int socket, int blocking)
#endif #endif
} }
/* Like connect(2), but with a timeout. Socket must be non-blocking. */ /* Like connect(2), but with a timeout. Socket must be non-blocking. */
int int
connect_timeout (int s, const struct sockaddr *serv_addr, socklen_t addrlen, connect_timeout (int s, const struct sockaddr *serv_addr, socklen_t addrlen,
@ -58,7 +62,8 @@ 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 @@ 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 @@ 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 @@ 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;
} }
@ -124,12 +133,14 @@ 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;
} }
@ -141,7 +152,8 @@ send_timeout(int s, const void *buf, size_t len, int flags,
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 ssize_t
recv_timeout(int s, void *buf, size_t len, int flags, struct timeval * timeout) recv_timeout (int s, void *buf, size_t len, int flags,
struct timeval * timeout)
{ {
fd_set readfds; fd_set readfds;
int ret; int ret;
@ -149,12 +161,14 @@ recv_timeout(int s, void *buf, size_t len, int flags, struct timeval * timeout)
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;
} }
@ -176,12 +190,14 @@ recvfrom_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;
} }
@ -200,7 +216,8 @@ send_all_timeout(int s, const void *buf, size_t len, int flags,
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);
@ -229,7 +246,8 @@ recv_all_timeout(int s, void *buf, size_t len, int flags,
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);

37
opt.c
View File

@ -11,7 +11,8 @@
#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;
} }
@ -27,7 +28,8 @@ 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] != 0) { argv[*optind][1] != '-' && 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];
@ -40,7 +42,8 @@ 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 '?';
} }
@ -48,47 +51,55 @@ 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] == '-' && argv[*optind][2] != 0) { else if (argv[*optind][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;

419
ue9.c
View File

@ -24,14 +24,17 @@
#include "ue9error.h" #include "ue9error.h"
#include "util.h" #include "util.h"
#include "netutil.h" #include "netutil.h"
#include "ethstream.h"
#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);
} }
@ -44,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);
} }
@ -64,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);
} }
@ -78,7 +85,8 @@ 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;
} }
@ -87,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);
} }
@ -107,7 +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] || 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", 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;
@ -116,69 +127,53 @@ int ue9_verify_extended(uint8_t * buffer, size_t len)
return 1; return 1;
} }
/* Temperature conversion. If calib is NULL, use uncalibrated conversions. */
double ue9_binary_to_temperature(struct ue9Calibration *calib, uint16_t data)
{
double slope;
if (calib == NULL) {
slope = 0.012683;
} else {
slope = calib->tempSlope;
}
return data * slope; /* output is in Kelvin */
}
/* Data conversion. If calib is NULL, use uncalibrated conversions. */ /* Data conversion. If calib is NULL, use uncalibrated conversions. */
double double
ue9_binary_to_analog (struct ue9Calibration *calib, ue9_binary_to_analog (struct ue9Calibration *calib,
int 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)
switch (gain) { {
case 1: if (gain <= 3)
slope = calib->unipolarSlope[0]; {
offset = calib->unipolarOffset[0]; slope = calib->unipolarSlope[gain];
break; offset = calib->unipolarOffset[gain];
case 2: }
slope = calib->unipolarSlope[1]; else if (gain == 8)
offset = calib->unipolarOffset[1]; {
break;
case 4:
slope = calib->unipolarSlope[2];
offset = calib->unipolarOffset[2];
break;
case 8:
slope = calib->unipolarSlope[3];
offset = calib->unipolarOffset[3];
break;
default:
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);
} }
@ -190,7 +185,8 @@ 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;
@ -200,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, &(struct timeval) { ret = send_all_timeout (fd, out, outlen, 0, &(struct timeval)
.tv_sec = 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;
} }
@ -223,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, &(struct timeval) { ret = recv_all_timeout (fd, in, inlen, 0, &(struct timeval)
.tv_sec = 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;
} }
@ -249,12 +252,15 @@ int ue9_command(int fd, uint8_t * out, uint8_t * in, int inlen)
return -1; return -1;
} }
/* Read a memory block from the device. Returns -1 on error. */ /* Read a memory block from the device. Returns -1 on error. */
int ue9_memory_read(int fd, int blocknum, uint8_t * buffer, int len) int
ue9_memory_read (int fd, int blocknum, uint8_t * buffer, int len)
{ {
uint8_t sendbuf[8], recvbuf[136]; uint8_t sendbuf[8], recvbuf[136];
if (len != 128) { if (len != 128)
{
fprintf (stderr, "ue9_memory_read: buffer length must be 128\n"); fprintf (stderr, "ue9_memory_read: buffer length must be 128\n");
exit (1); exit (1);
} }
@ -266,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;
} }
@ -278,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;
@ -290,7 +298,8 @@ 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];
@ -343,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];
@ -354,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;
} }
@ -363,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];
@ -374,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;
} }
@ -383,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;
@ -394,15 +408,16 @@ 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");
close(fd);
return -1; return -1;
} }
@ -416,9 +431,9 @@ 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);
close(fd);
return -1; return -1;
} }
address.sin_addr = *((struct in_addr *) he->h_addr); address.sin_addr = *((struct in_addr *) he->h_addr);
@ -427,21 +442,21 @@ 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) { &(struct timeval)
.tv_sec = TIMEOUT}) < 0) { {
.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));
close(fd);
return -1; return -1;
} }
debug("Connected to port %d\n", port);
return fd; return fd;
} }
/* Close connection to the UE9 */ /* Close connection to the UE9 */
void ue9_close(int fd) void
ue9_close (int fd)
{ {
/* does anyone actually call shutdown these days? */ /* does anyone actually call shutdown these days? */
shutdown (fd, 2 /* SHUT_RDWR */ ); shutdown (fd, 2 /* SHUT_RDWR */ );
@ -449,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;
@ -457,7 +473,8 @@ 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: case 0:
clock = 4e6; clock = 4e6;
break; break;
@ -488,37 +505,48 @@ 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 { struct
{
double clock; double clock;
uint8_t config; uint8_t config;
} valid[] = { } valid[] =
{
{
48e6, 0x08},
{
24e6, 0x18},
{
4e6, 0x00},
{
750e3, 0x10},
{
48e6 / 256, 0x0a},
{
24e6 / 256, 0x1a},
{
4e6 / 256, 0x02},
{
750e3 / 256, 0x12},
{ {
48e6, 0x08}, {
24e6, 0x18}, {
4e6, 0x00}, {
750e3, 0x10}, {
48e6 / 256, 0x0a}, {
24e6 / 256, 0x1a}, {
4e6 / 256, 0x02}, {
750e3 / 256, 0x12}, {
0, 0}}; 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 = *actual_rate = ue9_compute_rate (*scanconfig, *scaninterval);
ue9_compute_rate(*scanconfig, *scaninterval);
debug ("Config 0x%02x, desired %lf, actual %lf\n", debug ("Config 0x%02x, desired %lf, actual %lf\n",
*scanconfig, desired_rate, *actual_rate); *scanconfig, desired_rate, *actual_rate);
@ -531,25 +559,29 @@ 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;
} }
@ -562,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;
} }
@ -584,7 +618,8 @@ int ue9_stream_start(int fd)
configured with the same gain. */ configured with the same gain. */
int int
ue9_streamconfig_simple (int fd, int *channel_list, int channel_count, ue9_streamconfig_simple (int fd, int *channel_list, int channel_count,
uint8_t scanconfig, uint16_t scaninterval, uint8_t gain) uint8_t scanconfig, uint16_t scaninterval,
uint8_t gain)
{ {
int i; int i;
uint8_t buf[256]; uint8_t buf[256];
@ -600,18 +635,21 @@ 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;
} }
@ -619,130 +657,11 @@ ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
return 0; return 0;
} }
/* Stream configuration, each Analog Input channel can have its own gain. */
int
ue9_streamconfig(int fd, int *channel_list, int channel_count,
uint8_t scanconfig, uint16_t scaninterval, int *gain_list, int gain_count)
{
int i;
uint8_t buf[256];
/* Set up StreamConfig command with channels and scan options */
buf[1] = 0xF8; /* Extended command */
buf[2] = channel_count + 3; /* Command data words */
buf[3] = 0x11; /* StreamConfig */
buf[6] = channel_count; /* Number of channels */
buf[7] = 12; /* Bit resolution */
buf[8] = 0; /* Extra settling time */
buf[9] = scanconfig;
buf[10] = scaninterval & 0xff;
buf[11] = scaninterval >> 8;
for (i = 0; i < channel_count; i++) {
buf[12 + 2 * i] = channel_list[i]; /* Channel number */
if (i < gain_count) {
switch (gain_list[i]) {
case 0:
buf[13 + 2 * i] = UE9_BIPOLAR_GAIN1;
break;
case 1:
buf[13 + 2 * i] = UE9_UNIPOLAR_GAIN1;
break;
case 2:
buf[13 + 2 * i] = UE9_UNIPOLAR_GAIN2;
break;
case 4:
buf[13 + 2 * i] = UE9_UNIPOLAR_GAIN4;
break;
case 8:
buf[13 + 2 * i] = UE9_UNIPOLAR_GAIN8;
break;
default:
buf[13 + 2 * i] = UE9_BIPOLAR_GAIN1;
}
}
else
{
buf[13 + 2 * i] = UE9_BIPOLAR_GAIN1;
}
}
/* Send StreamConfig */
if (ue9_command(fd, buf, buf, 8) < 0) {
debug("command failed\n");
return -1;
}
if (buf[6] != 0) {
verb("returned error %s\n", ue9_error(buf[6]));
return -1;
}
return 0;
}
/* Timer configuration */
int ue9_timer_config(int fd, int *mode_list, int *value_list, int count, int divisor)
{
int i;
uint8_t buf[256];
if (count < 0 || count > 6) {
verb("invalid count\n");
return -1;
}
/* Set up TimerConfig command */
buf[1] = 0xF8; /* Extended command */
buf[2] = 0x0C; /* Command data words */
buf[3] = 0x18; /* TimerConfig */
buf[6] = divisor; /* TimerClockDivisor */
buf[7] = 0x80 | count; /* Number of timers enabled, UpdateConfig=1 */
buf[8] = 0x01; /* TimerClockBase = System 48MHz */
buf[9] = 0x00; /* Don't reset */
for (i = 0; i < 6; i++) {
if (i < count) {
buf[10 + 3 * i] = mode_list[i];
buf[11 + 3 * i] = value_list[i] & 0xff;
buf[12 + 3 * i] = value_list[i] >> 8;
}
else {
buf[10 + 3 * i] = 0;
buf[11 + 3 * i] = 0;
buf[12 + 3 * i] = 0;
}
}
buf[28] = 0;
buf[29] = 0;
/* Send StreamConfig */
if (ue9_command(fd, buf, buf, 40) < 0) {
debug("command failed\n");
return -1;
}
if (buf[6] != 0) {
verb("returned error %s\n", ue9_error(buf[6]));
return -1;
}
debug("timer EnableStatus=0x%02x\n", buf[7]);
return 0;
}
/* 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 int
ue9_stream_data(int fd, int channels, int *channel_list, int gain_count, int *gain_list, ue9_stream_cb_t callback, void *context) ue9_stream_data (int fd, int channels,
ue9_stream_cb_t callback, void *context)
{ {
int ret; int ret;
uint8_t buf[46]; uint8_t buf[46];
@ -751,34 +670,41 @@ ue9_stream_data(int fd, int channels, int *channel_list, int gain_count, int *ga
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 = 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) || !ue9_verify_normal(buf, 6)) { if (!ue9_verify_extended (buf, 46) || !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;
@ -786,7 +712,8 @@ ue9_stream_data(int fd, int channels, int *channel_list, int gain_count, int *ga
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;
} }
@ -795,32 +722,28 @@ ue9_stream_data(int fd, int channels, int *channel_list, int gain_count, int *ga
(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, channel_list, gain_count, gain_list, data, context) < 0) { if ((*callback) (channels, data, context) < 0)
{
/* We're done */ /* We're done */
return 0; return 0;
} }
} }
} }
} }
/*
Local variables:
c-basic-offset: 8
End:
*/

32
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;
@ -68,17 +71,13 @@ struct ue9ControlConfig {
uint16_t dac1; uint16_t dac1;
}; };
/* These are correct! 0, 1, 2, 3, 8 */
#define UE9_UNIPOLAR_GAIN1 0x00 #define UE9_UNIPOLAR_GAIN1 0x00
#define UE9_UNIPOLAR_GAIN2 0x01 #define UE9_UNIPOLAR_GAIN2 0x01
#define UE9_UNIPOLAR_GAIN4 0x02 #define UE9_UNIPOLAR_GAIN4 0x02
#define UE9_UNIPOLAR_GAIN8 0x03 #define UE9_UNIPOLAR_GAIN8 0x03
#define UE9_BIPOLAR_GAIN1 0x08 #define UE9_BIPOLAR_GAIN1 0x08
#define UE9_MAX_CHANNEL_COUNT 128 #define UE9_CHANNELS 14
#define UE9_MAX_CHANNEL 255
#define UE9_MAX_ANALOG_CHANNEL 13
#define UE9_TIMERS 6
/* Fill checksums in data buffers */ /* Fill checksums in data buffers */
void ue9_checksum_normal (uint8_t * buffer, size_t len); void ue9_checksum_normal (uint8_t * buffer, size_t len);
@ -105,10 +104,7 @@ int ue9_get_control_config(int fd, struct ue9ControlConfig *config);
/* Data conversion. If calib is NULL, use uncalibrated conversions. */ /* Data conversion. If calib is NULL, use uncalibrated conversions. */
double ue9_binary_to_analog (struct ue9Calibration *calib, double ue9_binary_to_analog (struct ue9Calibration *calib,
int gain, uint8_t resolution, uint16_t data); uint8_t gain, uint8_t resolution, uint16_t data);
/* Temperature conversion. If calib is NULL, use uncalibrated conversions. */
double ue9_binary_to_temperature(struct ue9Calibration *calib, uint16_t data);
/* Compute scanrate based on the provided values. */ /* Compute scanrate based on the provided values. */
double ue9_compute_rate (uint8_t scanconfig, uint16_t scaninterval); double ue9_compute_rate (uint8_t scanconfig, uint16_t scaninterval);
@ -139,18 +135,10 @@ int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
uint8_t scanconfig, uint16_t scaninterval, uint8_t scanconfig, uint16_t scaninterval,
uint8_t gain); uint8_t gain);
/* Stream configuration, each Analog Input channel can have its own gain. */
int ue9_streamconfig(int fd, int *channel_list, int channel_count,
uint8_t scanconfig, uint16_t scaninterval,
int *gain_list, int gain_count);
/* Timer configuration */
int ue9_timer_config(int fd, int *mode_list, int *value_list, int count, int divisor);
/* Stream data and pass it to the data callback. If callback returns /* Stream data and pass it to the data callback. If callback returns
negative, stops reading and returns 0. Returns < 0 on error. */ negative, stops reading and returns 0. Returns < 0 on error. */
typedef int (*ue9_stream_cb_t) (int channels, int *channel_list, int gain_count, int *gain_list, uint16_t * data, void *context); typedef int (*ue9_stream_cb_t) (int channels, uint16_t * data, void *context);
int ue9_stream_data(int fd, int channels, int *channel_list, int gain_count, int *gain_list, int ue9_stream_data (int fd, int channels,
ue9_stream_cb_t callback, void *context); ue9_stream_cb_t callback, void *context);
#endif #endif

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.3.2 (2016-07-13)" #define VERSION "1.1 (2009-04-17)"