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; }
/** * 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; }
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; }
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); }
/** * 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; }
/** * 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; }
/** * 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; }
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; }
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; }
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; }