Example #1
0
static int brymen_bm86x_parse_digits(const unsigned char *buf, int length,
                                     char *str, float *floatval,
                                     char *temp_unit, int flag)
{
	char c, *p = str;
	int i, ret;

	if (buf[0] & flag)
		*p++ = '-';
	for (i = 0; i < length; i++) {
		if (i && i < 5 && buf[i+1] & 0x01)
			*p++ = '.';
		c = char_map[buf[i+1] >> 1];
		if (i == 5 && (c == 'C' || c == 'F'))
			*temp_unit = c;
		else if (c)
			*p++ = c;
	}
	*p = 0;

	if ((ret = sr_atof_ascii(str, floatval))) {
		sr_dbg("invalid float string: '%s'", str);
		return ret;
	}

	return SR_OK;
}
Example #2
0
/**
 * Parse sign and value from text buffer, byte 0-6.
 *
 * The first character always is the sign (' ' or '-'). Subsequent
 * positions contain digits, dots, or spaces. Overflow / open inputs
 * are signalled with several magic literals that cannot get interpreted
 * as a number, either with 'X' characters in them, or with several
 * forms of "OL".
 *
 * @param[in]	buf The text buffer received from the DMM.
 * @param[out]	result A floating point number value.
 * @param[out]	exponent Augments the number value.
 */
static int parse_value(const char *buf, struct asycii_info *info,
			float *result, int *exponent)
{
	char valstr[7 + 1];
	const char *valp;
	int i, cnt, is_ol;
	const char *dot_pos;

	/*
	 * Strip all spaces from bytes 0-6. By copying all
	 * non-space characters into a buffer.
	 */
	cnt = 0;
	for (i = 0; i < 7; i++) {
		if (buf[i] != ' ')
			valstr[cnt++] = buf[i];
	}
	valstr[cnt] = '\0';
	valp = &valstr[0];
	sr_spew("%s(), number buffer [%s]", __func__, valp);

	/*
	 * Check for "over limit" conditions. Depending on the meter's
	 * selected mode, the textual representation might differ. Test
	 * all known variations.
	 */
	is_ol = 0;
	is_ol += (g_ascii_strcasecmp(valp, ".OL") == 0) ? 1 : 0;
	is_ol += (g_ascii_strcasecmp(valp, "O.L") == 0) ? 1 : 0;
	is_ol += (g_ascii_strcasecmp(valp, "-.OL") == 0) ? 1 : 0;
	is_ol += (g_ascii_strcasecmp(valp, "-O.L") == 0) ? 1 : 0;
	is_ol += (g_ascii_strncasecmp(valp, "X", 1) == 0) ? 1 : 0;
	is_ol += (g_ascii_strncasecmp(valp, "-X", 2) == 0) ? 1 : 0;
	if (is_ol) {
		sr_spew("%s(), over limit", __func__);
		*result = INFINITY;
		return SR_OK;
	}

	/*
	 * Convert the textual number representation to a float, and
	 * an exponent.
	 */
	if (sr_atof_ascii(valp, result) != SR_OK) {
		info->is_invalid = TRUE;
		sr_spew("%s(), cannot convert number", __func__);
		return SR_ERR_DATA;
	}
	dot_pos = g_strstr_len(valstr, -1, ".");
	if (dot_pos)
		*exponent = -(valstr + strlen(valstr) - dot_pos - 1);
	else
		*exponent = 0;
	sr_spew("%s(), display value is %f, exponent %d",
		__func__, *result, *exponent);
	return SR_OK;
}
Example #3
0
static int recv_fetc(const struct sr_dev_inst *sdi, GMatchInfo *match)
{
	struct dev_context *devc;
	struct sr_datafeed_packet packet;
	struct sr_datafeed_analog_old analog;
	float fvalue;
	const char *s;
	char *mstr;

	sr_spew("FETC reply '%s'.", g_match_info_get_string(match));
	devc = sdi->priv;

	if (devc->cur_mq == -1)
		/* Haven't seen configuration yet, so can't know what
		 * the fetched float means. Not really an error, we'll
		 * get metadata soon enough. */
		return SR_OK;

	s = g_match_info_get_string(match);
	if (!strcmp(s, "-9.90000000E+37") || !strcmp(s, "+9.90000000E+37")) {
		/* An invalid measurement shows up on the display as "O.L", but
		 * comes through like this. Since comparing 38-digit floats
		 * is rather problematic, we'll cut through this here. */
		fvalue = NAN;
	} else {
		mstr = g_match_info_fetch(match, 1);
		if (sr_atof_ascii(mstr, &fvalue) != SR_OK) {
			g_free(mstr);
			sr_dbg("Invalid float.");
			return SR_ERR;
		}
		g_free(mstr);
		if (devc->cur_divider > 0)
			fvalue /= devc->cur_divider;
	}

	memset(&analog, 0, sizeof(struct sr_datafeed_analog_old));
	analog.mq = devc->cur_mq;
	analog.unit = devc->cur_unit;
	analog.mqflags = devc->cur_mqflags;
	analog.channels = sdi->channels;
	analog.num_samples = 1;
	analog.data = &fvalue;
	packet.type = SR_DF_ANALOG_OLD;
	packet.payload = &analog;
	sr_session_send(devc->cb_data, &packet);

	devc->num_samples++;

	return SR_OK;
}
Example #4
0
static void handle_qm_19x_data(const struct sr_dev_inst *sdi, char **tokens)
{
	struct dev_context *devc;
	struct sr_datafeed_packet packet;
	struct sr_datafeed_analog_old analog;
	float fvalue;

	if (!strcmp(tokens[0], "9.9E+37")) {
		/* An invalid measurement shows up on the display as "OL", but
		 * comes through like this. Since comparing 38-digit floats
		 * is rather problematic, we'll cut through this here. */
		fvalue = NAN;
	} else {
		if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) {
			sr_err("Invalid float '%s'.", tokens[0]);
			return;
		}
	}

	devc = sdi->priv;
	if (devc->mq == -1 || devc->unit == -1)
		/* Don't have valid metadata yet. */
		return;

	if (devc->mq == SR_MQ_RESISTANCE && isnan(fvalue))
		fvalue = INFINITY;
	else if (devc->mq == SR_MQ_CONTINUITY) {
		if (isnan(fvalue))
			fvalue = 0.0;
		else
			fvalue = 1.0;
	}

	analog.channels = sdi->channels;
	analog.num_samples = 1;
	analog.data = &fvalue;
	analog.mq = devc->mq;
	analog.unit = devc->unit;
	analog.mqflags = 0;
	packet.type = SR_DF_ANALOG_OLD;
	packet.payload = &analog;
	sr_session_send(sdi, &packet);

	sr_sw_limits_update_samples_read(&devc->limits, 1);
}
Example #5
0
/**
 * Send a SCPI command, read the reply, parse it as comma separated list of
 * floats and store the as an result in scpi_response.
 *
 * @param scpi Previously initialised SCPI device structure.
 * @param command The SCPI command to send to the device (can be NULL).
 * @param scpi_response Pointer where to store the parsed result.
 *
 * @return SR_OK upon successfully parsing all values, SR_ERR* upon a parsing
 *         error or upon no response. The allocated response must be freed by
 *         the caller in the case of an SR_OK as well as in the case of
 *         parsing error.
 */
SR_PRIV int sr_scpi_get_floatv(struct sr_scpi_dev_inst *scpi,
			       const char *command, GArray **scpi_response)
{
	int ret;
	float tmp;
	char *response;
	gchar **ptr, **tokens;
	GArray *response_array;

	response = NULL;
	tokens = NULL;

	ret = sr_scpi_get_string(scpi, command, &response);
	if (ret != SR_OK && !response)
		return ret;

	tokens = g_strsplit(response, ",", 0);
	ptr = tokens;

	response_array = g_array_sized_new(TRUE, FALSE, sizeof(float), 256);

	while (*ptr) {
		if (sr_atof_ascii(*ptr, &tmp) == SR_OK)
			response_array = g_array_append_val(response_array,
							    tmp);
		else
			ret = SR_ERR_DATA;

		ptr++;
	}
	g_strfreev(tokens);
	g_free(response);

	if (ret != SR_OK && response_array->len == 0) {
		g_array_free(response_array, TRUE);
		*scpi_response = NULL;
		return SR_ERR_DATA;
	}

	*scpi_response = response_array;

	return ret;
}
Example #6
0
/**
 * This function takes a value of the form "2.000E-03", converts it to a
 * significand / factor pair and returns the index of an array where
 * a matching pair was found.
 *
 * It's a bit convoluted because of floating-point issues. The value "10.00E-09"
 * is parsed by g_ascii_strtod() as 0.000000009999999939, for example.
 * Therefore it's easier to break the number up into two strings and handle
 * them separately.
 *
 * @param value The string to be parsed.
 * @param array The array of s/f pairs.
 * @param array_len The number of pairs in the array.
 * @param result The index at which a matching pair was found.
 *
 * @return SR_ERR on any parsing error, SR_OK otherwise.
 */
static int array_float_get(gchar *value, const uint64_t array[][2],
		int array_len, int *result)
{
	int i;
	uint64_t f;
	float s;
	unsigned int s_int;
	gchar ss[10], es[10];

	memset(ss, 0, sizeof(ss));
	memset(es, 0, sizeof(es));

	strncpy(ss, value, 5);
	strncpy(es, &(value[6]), 3);

	if (sr_atof_ascii(ss, &s) != SR_OK)
		return SR_ERR;
	if (sr_atoi(es, &i) != SR_OK)
		return SR_ERR;

	/* Transform e.g. 10^-03 to 1000 as the array stores the inverse. */
	f = pow(10, abs(i));

	/*
	 * Adjust the significand/factor pair to make sure
	 * that f is a multiple of 1000.
	 */
	while ((int)fmod(log10(f), 3) > 0) { s *= 10; f *= 10; }

	/* Truncate s to circumvent rounding errors. */
	s_int = (unsigned int)s;

	for (i = 0; i < array_len; i++) {
		if ( (s_int == array[i][0]) && (f == array[i][1]) ) {
			*result = i;
			return SR_OK;
		}
	}

	return SR_ERR;
}
Example #7
0
/**
 * Send a SCPI command, read the reply, parse it as a float and store the
 * result in scpi_response.
 *
 * @param scpi Previously initialised SCPI device structure.
 * @param command The SCPI command to send to the device (can be NULL).
 * @param scpi_response Pointer where to store the parsed result.
 *
 * @return SR_OK on success, SR_ERR* on failure.
 */
SR_PRIV int sr_scpi_get_float(struct sr_scpi_dev_inst *scpi,
			      const char *command, float *scpi_response)
{
	int ret;
	char *response;

	response = NULL;

	ret = sr_scpi_get_string(scpi, command, &response);
	if (ret != SR_OK && !response)
		return ret;

	if (sr_atof_ascii(response, scpi_response) == SR_OK)
		ret = SR_OK;
	else
		ret = SR_ERR_DATA;

	g_free(response);

	return ret;
}
Example #8
0
static int recv_fetc(const struct sr_dev_inst *sdi, GMatchInfo *match)
{
	struct dev_context *devc;
	struct sr_datafeed_packet packet;
	struct sr_datafeed_analog analog;
	struct sr_analog_encoding encoding;
	struct sr_analog_meaning meaning;
	struct sr_analog_spec spec;
	struct sr_channel *prev_chan;
	float fvalue;
	const char *s;
	char *mstr;
	int i, exp;

	sr_spew("FETC reply '%s'.", g_match_info_get_string(match));
	devc = sdi->priv;
	i = devc->cur_channel->index;

	if (devc->cur_mq[i] == -1)
		/* This detects when channel P2 is reporting TEMP as an identical
		 * copy of channel P3. In this case, we just skip P2. */
		goto skip_value;

	s = g_match_info_get_string(match);
	if (!strcmp(s, "-9.90000000E+37") || !strcmp(s, "+9.90000000E+37")) {
		/* An invalid measurement shows up on the display as "O.L", but
		 * comes through like this. Since comparing 38-digit floats
		 * is rather problematic, we'll cut through this here. */
		fvalue = NAN;
	} else {
		mstr = g_match_info_fetch(match, 1);
		if (sr_atof_ascii(mstr, &fvalue) != SR_OK) {
			g_free(mstr);
			sr_dbg("Invalid float.");
			return SR_ERR;
		}
		g_free(mstr);
		if (devc->cur_exponent[i] != 0)
			fvalue *= powf(10, devc->cur_exponent[i]);
	}

	if (devc->cur_unit[i] == SR_UNIT_DECIBEL_MW ||
	    devc->cur_unit[i] == SR_UNIT_DECIBEL_VOLT ||
	    devc->cur_unit[i] == SR_UNIT_PERCENTAGE) {
		mstr = g_match_info_fetch(match, 2);
		if (mstr && sr_atoi(mstr, &exp) == SR_OK) {
			devc->cur_digits[i] = MIN(4 - exp, devc->cur_digits[i]);
			devc->cur_encoding[i] = MIN(5 - exp, devc->cur_encoding[i]);
		}
		g_free(mstr);
	}

	sr_analog_init(&analog, &encoding, &meaning, &spec,
	               devc->cur_digits[i] - devc->cur_exponent[i]);
	analog.meaning->mq = devc->cur_mq[i];
	analog.meaning->unit = devc->cur_unit[i];
	analog.meaning->mqflags = devc->cur_mqflags[i];
	analog.meaning->channels = g_slist_append(NULL, devc->cur_channel);
	analog.num_samples = 1;
	analog.data = &fvalue;
	encoding.digits = devc->cur_encoding[i] - devc->cur_exponent[i];
	packet.type = SR_DF_ANALOG;
	packet.payload = &analog;
	sr_session_send(sdi, &packet);
	g_slist_free(analog.meaning->channels);

	sr_sw_limits_update_samples_read(&devc->limits, 1);

skip_value:
	prev_chan = devc->cur_channel;
	devc->cur_channel = sr_next_enabled_channel(sdi, devc->cur_channel);
	if (devc->cur_channel->index > prev_chan->index)
		return JOB_AGAIN;
	else
		return JOB_FETC;
}
Example #9
0
static struct sr_datafeed_analog_old *handle_qm_18x(const struct sr_dev_inst *sdi,
		char **tokens)
{
	struct sr_datafeed_analog_old *analog;
	float fvalue;
	char *e, *u;
	gboolean is_oor;

	if (strcmp(tokens[0], "QM") || !tokens[1])
		return NULL;

	if ((e = strstr(tokens[1], "Out of range"))) {
		is_oor = TRUE;
		fvalue = -1;
		while (*e && *e != '.')
			e++;
	} else {
		is_oor = FALSE;
		/* Delimit the float, since sr_atof_ascii() wants only
		 * a valid float here. */
		e = tokens[1];
		while (*e && *e != ' ')
			e++;
		*e++ = '\0';
		if (sr_atof_ascii(tokens[1], &fvalue) != SR_OK || fvalue == 0.0) {
			/* Happens all the time, when switching modes. */
			sr_dbg("Invalid float.");
			return NULL;
		}
	}
	while (*e && *e == ' ')
		e++;

	analog = g_malloc0(sizeof(struct sr_datafeed_analog_old));
	analog->data = g_malloc(sizeof(float));
	analog->channels = sdi->channels;
	analog->num_samples = 1;
	if (is_oor)
		*analog->data = NAN;
	else
		*analog->data = fvalue;
	analog->mq = -1;

	if ((u = strstr(e, "V DC")) || (u = strstr(e, "V AC"))) {
		analog->mq = SR_MQ_VOLTAGE;
		analog->unit = SR_UNIT_VOLT;
		if (!is_oor && e[0] == 'm')
			*analog->data /= 1000;
		/* This catches "V AC", "V DC" and "V AC+DC". */
		if (strstr(u, "AC"))
			analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
		if (strstr(u, "DC"))
			analog->mqflags |= SR_MQFLAG_DC;
	} else if ((u = strstr(e, "dBV")) || (u = strstr(e, "dBm"))) {
		analog->mq = SR_MQ_VOLTAGE;
		if (u[2] == 'm')
			analog->unit = SR_UNIT_DECIBEL_MW;
		else
			analog->unit = SR_UNIT_DECIBEL_VOLT;
		analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
	} else if ((u = strstr(e, "Ohms"))) {
		analog->mq = SR_MQ_RESISTANCE;
		analog->unit = SR_UNIT_OHM;
		if (is_oor)
			*analog->data = INFINITY;
		else if (e[0] == 'k')
			*analog->data *= 1000;
		else if (e[0] == 'M')
			*analog->data *= 1000000;
	} else if (!strcmp(e, "nS")) {
		analog->mq = SR_MQ_CONDUCTANCE;
		analog->unit = SR_UNIT_SIEMENS;
		*analog->data /= 1e+9;
	} else if ((u = strstr(e, "Farads"))) {
		analog->mq = SR_MQ_CAPACITANCE;
		analog->unit = SR_UNIT_FARAD;
		if (!is_oor) {
			if (e[0] == 'm')
				*analog->data /= 1e+3;
			else if (e[0] == 'u')
				*analog->data /= 1e+6;
			else if (e[0] == 'n')
				*analog->data /= 1e+9;
		}
	} else if ((u = strstr(e, "Deg C")) || (u = strstr(e, "Deg F"))) {
		analog->mq = SR_MQ_TEMPERATURE;
		if (u[4] == 'C')
			analog->unit = SR_UNIT_CELSIUS;
		else
			analog->unit = SR_UNIT_FAHRENHEIT;
	} else if ((u = strstr(e, "A AC")) || (u = strstr(e, "A DC"))) {
		analog->mq = SR_MQ_CURRENT;
		analog->unit = SR_UNIT_AMPERE;
		/* This catches "A AC", "A DC" and "A AC+DC". */
		if (strstr(u, "AC"))
			analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
		if (strstr(u, "DC"))
			analog->mqflags |= SR_MQFLAG_DC;
		if (!is_oor) {
			if (e[0] == 'm')
				*analog->data /= 1e+3;
			else if (e[0] == 'u')
				*analog->data /= 1e+6;
		}
	} else if ((u = strstr(e, "Hz"))) {
		analog->mq = SR_MQ_FREQUENCY;
		analog->unit = SR_UNIT_HERTZ;
		if (e[0] == 'k')
			*analog->data *= 1e+3;
	} else if (!strcmp(e, "%")) {
		analog->mq = SR_MQ_DUTY_CYCLE;
		analog->unit = SR_UNIT_PERCENTAGE;
	} else if ((u = strstr(e, "ms"))) {
		analog->mq = SR_MQ_PULSE_WIDTH;
		analog->unit = SR_UNIT_SECOND;
		*analog->data /= 1e+3;
	}

	if (analog->mq == -1) {
		/* Not a valid measurement. */
		g_free(analog->data);
		g_free(analog);
		analog = NULL;
	}

	return analog;
}
Example #10
0
static struct sr_datafeed_analog_old *handle_qm_28x(const struct sr_dev_inst *sdi,
		char **tokens)
{
	struct sr_datafeed_analog_old *analog;
	float fvalue;

	if (!tokens[1])
		return NULL;

	if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) {
		sr_err("Invalid float '%s'.", tokens[0]);
		return NULL;
	}

	analog = g_malloc0(sizeof(struct sr_datafeed_analog_old));
	analog->data = g_malloc(sizeof(float));
	analog->channels = sdi->channels;
	analog->num_samples = 1;
	*analog->data = fvalue;
	analog->mq = -1;

	if (!strcmp(tokens[1], "VAC") || !strcmp(tokens[1], "VDC")) {
		analog->mq = SR_MQ_VOLTAGE;
		analog->unit = SR_UNIT_VOLT;
		if (!strcmp(tokens[2], "NORMAL")) {
			if (tokens[1][1] == 'A') {
				analog->mqflags |= SR_MQFLAG_AC;
				analog->mqflags |= SR_MQFLAG_RMS;
			} else
				analog->mqflags |= SR_MQFLAG_DC;
		} else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
			*analog->data = NAN;
		} else
			analog->mq = -1;
	} else if (!strcmp(tokens[1], "dBV") || !strcmp(tokens[1], "dBm")) {
		analog->mq = SR_MQ_VOLTAGE;
		if (tokens[1][2] == 'm')
			analog->unit = SR_UNIT_DECIBEL_MW;
		else
			analog->unit = SR_UNIT_DECIBEL_VOLT;
		analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
	} else if (!strcmp(tokens[1], "CEL") || !strcmp(tokens[1], "FAR")) {
		if (!strcmp(tokens[2], "NORMAL")) {
			analog->mq = SR_MQ_TEMPERATURE;
			if (tokens[1][0] == 'C')
				analog->unit = SR_UNIT_CELSIUS;
			else
				analog->unit = SR_UNIT_FAHRENHEIT;
		}
	} else if (!strcmp(tokens[1], "OHM")) {
		if (!strcmp(tokens[3], "NONE")) {
			analog->mq = SR_MQ_RESISTANCE;
			analog->unit = SR_UNIT_OHM;
			if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
				*analog->data = INFINITY;
			} else if (strcmp(tokens[2], "NORMAL"))
				analog->mq = -1;
		} else if (!strcmp(tokens[3], "OPEN_CIRCUIT")) {
			analog->mq = SR_MQ_CONTINUITY;
			analog->unit = SR_UNIT_BOOLEAN;
			*analog->data = 0.0;
		} else if (!strcmp(tokens[3], "SHORT_CIRCUIT")) {
			analog->mq = SR_MQ_CONTINUITY;
			analog->unit = SR_UNIT_BOOLEAN;
			*analog->data = 1.0;
		}
	} else if (!strcmp(tokens[1], "F")
			&& !strcmp(tokens[2], "NORMAL")
			&& !strcmp(tokens[3], "NONE")) {
		analog->mq = SR_MQ_CAPACITANCE;
		analog->unit = SR_UNIT_FARAD;
	} else if (!strcmp(tokens[1], "AAC") || !strcmp(tokens[1], "ADC")) {
		analog->mq = SR_MQ_CURRENT;
		analog->unit = SR_UNIT_AMPERE;
		if (!strcmp(tokens[2], "NORMAL")) {
			if (tokens[1][1] == 'A') {
				analog->mqflags |= SR_MQFLAG_AC;
				analog->mqflags |= SR_MQFLAG_RMS;
			} else
				analog->mqflags |= SR_MQFLAG_DC;
		} else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
			*analog->data = NAN;
		} else
			analog->mq = -1;
	} if (!strcmp(tokens[1], "Hz") && !strcmp(tokens[2], "NORMAL")) {
		analog->mq = SR_MQ_FREQUENCY;
		analog->unit = SR_UNIT_HERTZ;
	} else if (!strcmp(tokens[1], "PCT") && !strcmp(tokens[2], "NORMAL")) {
		analog->mq = SR_MQ_DUTY_CYCLE;
		analog->unit = SR_UNIT_PERCENTAGE;
	} else if (!strcmp(tokens[1], "S") && !strcmp(tokens[2], "NORMAL")) {
		analog->mq = SR_MQ_PULSE_WIDTH;
		analog->unit = SR_UNIT_SECOND;
	} else if (!strcmp(tokens[1], "SIE") && !strcmp(tokens[2], "NORMAL")) {
		analog->mq = SR_MQ_CONDUCTANCE;
		analog->unit = SR_UNIT_SIEMENS;
	}

	if (analog->mq == -1) {
		/* Not a valid measurement. */
		g_free(analog->data);
		g_free(analog);
		analog = NULL;
	}

	return analog;
}