Commit 56a79c00 by cschantz

The changes allow ethstream to set the gain of individual labjack analog input channels

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-efcb8ce7c51f
parent bb4912a4
Showing with 197 additions and 24 deletions
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment