Compare commits
No commits in common. "master" and "ethstream-1.1" have entirely different histories.
master
...
ethstream-
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -1,10 +0,0 @@
|
||||||
ethstream
|
|
||||||
ethstream.1
|
|
||||||
ethstream.txt
|
|
||||||
ethstream.exe
|
|
||||||
*.obj
|
|
||||||
*.d
|
|
||||||
*.dobj
|
|
||||||
*.o
|
|
||||||
|
|
||||||
|
|
31
Makefile
31
Makefile
|
@ -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
11
README
|
@ -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.
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
3
compat.h
3
compat.h
|
@ -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
21
debug.c
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
7
debug.h
7
debug.h
|
@ -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); \
|
||||||
})
|
})
|
||||||
|
|
498
ethstream.c
498
ethstream.c
|
@ -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, ¤tcount, period, wasreset);
|
showmem, ¤tcount, 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++;
|
||||||
|
|
|
@ -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
|
||||||
|
|
106
example.inc
106
example.inc
|
@ -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
102
ljconfig.c
Normal 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
68
ljtest.c
Normal 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;
|
||||||
|
}
|
290
nerdjack.c
290
nerdjack.c
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
52
netutil.c
52
netutil.c
|
@ -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
37
opt.c
|
@ -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
3
opt.h
|
@ -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
419
ue9.c
|
@ -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
32
ue9.h
|
@ -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
|
||||||
|
|
|
@ -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)";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user