with the -g flag and ethstream also grabs the factory calibration constants from the Labjack and uses them when the -c flag is given. changes by Chris Schantz git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@9683 ddd99763-3ecb-0310-9145-efcb8ce7c51ftags/ethstream-1.3
@@ -54,6 +54,7 @@ struct options opt[] = { | |||
{'d', "detect", NULL, "Detect NerdJack IP address"}, | |||
{'R', "range", "a,b", | |||
"Set range on NerdJack for channels 0-5,6-11 to either 5 or 10 (10,10)"}, | |||
{'g', "gian", "a,b,c", "Set Labjack AIN channel gains: 0,1,2,4,8 in -C channel order"}, | |||
{'o', "oneshot", NULL, "don't retry in case of errors"}, | |||
{'f', "forceretry", NULL, "retry no matter what happens"}, | |||
{'c', "convert", NULL, "convert output to volts"}, | |||
@@ -71,11 +72,13 @@ struct options opt[] = { | |||
int doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval, | |||
int *channel_list, int channel_count, | |||
int *timer_mode_list, 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 precision, unsigned long period, int convert, int lines, | |||
int showmem); | |||
int data_callback(int channels, uint16_t * data, void *context); | |||
int data_callback(int channels, int *channel_list, int gain_count, int *gain_list, | |||
uint16_t * data, void *context); | |||
int columns_left = 0; | |||
void handle_sig(int sig) | |||
@@ -108,6 +111,8 @@ int main(int argc, char *argv[]) | |||
int timer_mode_list[UE9_TIMERS]; | |||
int timer_mode_count = 0; | |||
int timer_divisor = 1; | |||
int gain_list[MAX_CHANNELS]; | |||
int gain_count = 0; | |||
int channel_list[MAX_CHANNELS]; | |||
int channel_count = 0; | |||
int nerdjack = 0; | |||
@@ -159,6 +164,29 @@ int main(int argc, char *argv[]) | |||
} | |||
while (*endp); | |||
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 == 4 || 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 { | |||
@@ -375,6 +403,12 @@ int main(int argc, char *argv[]) | |||
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) { | |||
info("error: too many arguments (%s)\n\n", argv[optind]); | |||
goto printhelp; | |||
@@ -450,6 +484,7 @@ int main(int argc, char *argv[]) | |||
ret = doStream(address, scanconfig, scaninterval, | |||
channel_list, channel_count, | |||
timer_mode_list, timer_mode_count, timer_divisor, | |||
gain_list, gain_count, | |||
convert, lines); | |||
verb("doStream returned %d\n", ret); | |||
} | |||
@@ -599,6 +634,7 @@ int | |||
doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval, | |||
int *channel_list, int channel_count, | |||
int *timer_mode_list, int timer_mode_count, int timer_divisor, | |||
int *gain_list, int gain_count, | |||
int convert, int lines) | |||
{ | |||
int retval = -EAGAIN; | |||
@@ -647,12 +683,22 @@ doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval, | |||
goto out2; | |||
} | |||
/* Set stream configuration */ | |||
if (ue9_streamconfig_simple(fd_cmd, channel_list, channel_count, | |||
scanconfig, scaninterval, | |||
UE9_BIPOLAR_GAIN1) < 0) { | |||
info("Failed to set stream 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 */ | |||
if (ue9_streamconfig_simple(fd_cmd, channel_list, channel_count, | |||
scanconfig, scaninterval, | |||
UE9_BIPOLAR_GAIN1) < 0) { | |||
info("Failed to set stream configuration\n"); | |||
goto out2; | |||
} | |||
} | |||
/* Start stream */ | |||
@@ -663,7 +709,7 @@ doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval, | |||
/* Stream data */ | |||
ret = | |||
ue9_stream_data(fd_data, channel_count, data_callback, (void *)&ci); | |||
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); | |||
goto out3; | |||
@@ -684,7 +730,7 @@ doStream(const char *address, uint8_t scanconfig, uint16_t scaninterval, | |||
return retval; | |||
} | |||
int data_callback(int channels, uint16_t * data, void *context) | |||
int data_callback(int channels, int *channel_list, int gain_count, int *gain_list, uint16_t * data, void *context) | |||
{ | |||
int i; | |||
struct callbackInfo *ci = (struct callbackInfo *)context; | |||
@@ -693,12 +739,20 @@ int data_callback(int channels, uint16_t * data, void *context) | |||
columns_left = channels; | |||
for (i = 0; i < channels; i++) { | |||
if (ci->convert == CONVERT_VOLTS && | |||
i <= UE9_MAX_ANALOG_CHANNEL) { | |||
channel_list[i] <= UE9_MAX_ANALOG_CHANNEL) { | |||
/* CONVERT_VOLTS */ | |||
if (i < gain_count) | |||
{ | |||
if (printf("%lf", ue9_binary_to_analog( | |||
&ci->calib, gain_list[i], | |||
12, data[i])) < 0) | |||
goto bad; | |||
} else { | |||
if (printf("%lf", ue9_binary_to_analog( | |||
&ci->calib, UE9_BIPOLAR_GAIN1, | |||
&ci->calib, 0, | |||
12, data[i])) < 0) | |||
goto bad; | |||
} | |||
} else if (ci->convert == CONVERT_HEX) { | |||
/* CONVERT_HEX */ | |||
if (printf("%04X", data[i]) < 0) | |||
@@ -71,4 +71,36 @@ 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\ | |||
"; |
@@ -119,7 +119,7 @@ int ue9_verify_extended(uint8_t * buffer, size_t len) | |||
/* Data conversion. If calib is NULL, use uncalibrated conversions. */ | |||
double | |||
ue9_binary_to_analog(struct ue9Calibration *calib, | |||
uint8_t gain, uint8_t resolution, uint16_t data) | |||
int gain, uint8_t resolution, uint16_t data) | |||
{ | |||
double slope = 0, offset; | |||
@@ -133,13 +133,27 @@ ue9_binary_to_analog(struct ue9Calibration *calib, | |||
} | |||
if (resolution < 18) { | |||
if (gain <= 3) { | |||
slope = calib->unipolarSlope[gain]; | |||
offset = calib->unipolarOffset[gain]; | |||
} else if (gain == 8) { | |||
slope = calib->bipolarSlope; | |||
offset = calib->bipolarOffset; | |||
} | |||
switch (gain) { | |||
case 1: | |||
slope = calib->unipolarSlope[0]; | |||
offset = calib->unipolarOffset[0]; | |||
break; | |||
case 2: | |||
slope = calib->unipolarSlope[1]; | |||
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; | |||
offset = calib->bipolarOffset; | |||
} | |||
} else { | |||
if (gain == 0) { | |||
slope = calib->hiResUnipolarSlope; | |||
@@ -588,6 +602,74 @@ ue9_streamconfig_simple(int fd, int *channel_list, int channel_count, | |||
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 mode_count, int divisor) | |||
{ | |||
@@ -639,7 +721,7 @@ int ue9_timer_config(int fd, int *mode_list, int mode_count, int divisor) | |||
/* Stream data and pass it to the data callback. If callback returns | |||
negative, stops reading and returns 0. Returns < 0 on error. */ | |||
int | |||
ue9_stream_data(int fd, int channels, ue9_stream_cb_t callback, void *context) | |||
ue9_stream_data(int fd, int channels, int *channel_list, int gain_count, int *gain_list, ue9_stream_cb_t callback, void *context) | |||
{ | |||
int ret; | |||
uint8_t buf[46]; | |||
@@ -708,7 +790,7 @@ ue9_stream_data(int fd, int channels, ue9_stream_cb_t callback, void *context) | |||
/* Received a full scan, send to callback */ | |||
channel = 0; | |||
if ((*callback) (channels, data, context) < 0) { | |||
if ((*callback) (channels, channel_list, gain_count, gain_list, data, context) < 0) { | |||
/* We're done */ | |||
return 0; | |||
} | |||
@@ -104,7 +104,7 @@ int ue9_get_control_config(int fd, struct ue9ControlConfig *config); | |||
/* Data conversion. If calib is NULL, use uncalibrated conversions. */ | |||
double ue9_binary_to_analog(struct ue9Calibration *calib, | |||
uint8_t gain, uint8_t resolution, uint16_t data); | |||
int gain, uint8_t resolution, uint16_t data); | |||
/* Compute scanrate based on the provided values. */ | |||
double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval); | |||
@@ -134,14 +134,19 @@ int ue9_command(int fd, uint8_t * out, uint8_t * in, int inlen); | |||
int ue9_streamconfig_simple(int fd, int *channel_list, int channel_count, | |||
uint8_t scanconfig, uint16_t scaninterval, | |||
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 mode_count, int divisor); | |||
/* Stream data and pass it to the data callback. If callback returns | |||
negative, stops reading and returns 0. Returns < 0 on error. */ | |||
typedef int (*ue9_stream_cb_t) (int channels, uint16_t * data, void *context); | |||
int ue9_stream_data(int fd, int channels, | |||
typedef int (*ue9_stream_cb_t) (int channels, int *channel_list, int gain_count, int *gain_list, uint16_t * data, void *context); | |||
int ue9_stream_data(int fd, int channels, int *channel_list, int gain_count, int *gain_list, | |||
ue9_stream_cb_t callback, void *context); | |||
#endif |