From: Andreas Sandberg Date: Sun, 29 Sep 2019 21:48:52 +0000 (+0100) Subject: fluke-dmm: Cleanup Fluke 28x QM handling X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=73afd1a2f7c5008eacb738bb00a2246f96823182;p=libsigrok.git fluke-dmm: Cleanup Fluke 28x QM handling The code that parses QM responses from Fluke 28x DMMs uses a long series of if-else statements to determine the type of measurement reported by the device. Rewrite this to use a conversion table that contains a mapping between DMM units and Sigrok's internal units. Signed-off-by: Andreas Sandberg --- diff --git a/Makefile.am b/Makefile.am index d28a1333..ea32cb89 100644 --- a/Makefile.am +++ b/Makefile.am @@ -359,6 +359,7 @@ if HW_FLUKE_DMM src_libdrivers_la_SOURCES += \ src/hardware/fluke-dmm/protocol.h \ src/hardware/fluke-dmm/protocol.c \ + src/hardware/fluke-dmm/fluke-28x.c \ src/hardware/fluke-dmm/api.c endif if HW_FTDI_LA diff --git a/src/hardware/fluke-dmm/fluke-28x.c b/src/hardware/fluke-dmm/fluke-28x.c new file mode 100644 index 00000000..ec8678dc --- /dev/null +++ b/src/hardware/fluke-dmm/fluke-28x.c @@ -0,0 +1,250 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2019-2020, 2024 Andreas Sandberg + * Copyright (C) 2012 Bert Vermeulen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include "libsigrok-internal.h" +#include "protocol.h" + +enum measurement_state { + MEAS_S_INVALID = 0, + MEAS_S_NORMAL, + MEAS_S_BLANK, + MEAS_S_DISCHARGE, + MEAS_S_OL, + MEAS_S_OL_MINUS, + MEAS_S_OPEN_TC, +}; + +struct state_mapping { + const char *name; + enum measurement_state state; +}; + +static struct state_mapping state_map[] = { + { "INVALID", MEAS_S_INVALID }, + { "NORMAL", MEAS_S_NORMAL }, + { "BLANK", MEAS_S_BLANK }, + { "DISCHARGE", MEAS_S_DISCHARGE }, + { "OL", MEAS_S_OL }, + { "OL_MINUS", MEAS_S_OL_MINUS }, + { "OPEN_TC", MEAS_S_OPEN_TC }, +}; + +enum measurement_attribute { + MEAS_A_INVALID = 0, + MEAS_A_NONE, + MEAS_A_OPEN_CIRCUIT, + MEAS_A_SHORT_CIRCUIT, + MEAS_A_GLITCH_CIRCUIT, + MEAS_A_GOOD_DIODE, + MEAS_A_LO_OHMS, + MEAS_A_NEGATIVE_EDGE, + MEAS_A_POSITIVE_EDGE, + MEAS_A_HIGH_CURRENT, +}; + +struct attribute_mapping { + const char *name; + enum measurement_attribute attribute; +}; + +static struct attribute_mapping attribute_map[] = { + { "NONE", MEAS_A_NONE }, + { "OPEN_CIRCUIT", MEAS_A_OPEN_CIRCUIT }, + { "SHORT_CIRCUIT", MEAS_A_SHORT_CIRCUIT }, + { "GLITCH_CIRCUIT", MEAS_A_GLITCH_CIRCUIT }, + { "GOOD_DIODE", MEAS_A_GOOD_DIODE }, + { "LO_OHMS", MEAS_A_LO_OHMS }, + { "NEGATIVE_EDGE", MEAS_A_NEGATIVE_EDGE }, + { "POSITIVE_EDGE", MEAS_A_POSITIVE_EDGE }, + { "HIGH_CURRENT", MEAS_A_HIGH_CURRENT }, +}; + +struct unit_mapping { + const char *name; + enum sr_mq mq; + enum sr_unit unit; + enum sr_mqflag mqflags; +}; + +static struct unit_mapping unit_map[] = { + { "VDC", SR_MQ_VOLTAGE, SR_UNIT_VOLT, SR_MQFLAG_DC }, + { "VAC", SR_MQ_VOLTAGE, SR_UNIT_VOLT, SR_MQFLAG_AC | SR_MQFLAG_RMS }, + { "ADC", SR_MQ_CURRENT, SR_UNIT_AMPERE, SR_MQFLAG_DC }, + { "AAC", SR_MQ_CURRENT, SR_UNIT_AMPERE, SR_MQFLAG_AC | SR_MQFLAG_RMS }, + { "VAC_PLUS_DC", SR_MQ_VOLTAGE, SR_UNIT_VOLT, 0 }, + { "AAC_PLUS_DC", SR_MQ_VOLTAGE, SR_UNIT_VOLT, 0 }, + /* Used in peak */ + { "V", SR_MQ_VOLTAGE, SR_UNIT_VOLT, 0 }, + /* Used in peak */ + { "A", SR_MQ_VOLTAGE, SR_UNIT_AMPERE, 0 }, + { "OHM", SR_MQ_RESISTANCE, SR_UNIT_OHM, 0 }, + { "SIE", SR_MQ_CONDUCTANCE, SR_UNIT_SIEMENS, 0 }, + { "Hz", SR_MQ_FREQUENCY, SR_UNIT_HERTZ, 0 }, + { "S", SR_MQ_PULSE_WIDTH, SR_UNIT_SECOND, 0 }, + { "F", SR_MQ_CAPACITANCE, SR_UNIT_FARAD, 0 }, + { "CEL", SR_MQ_TEMPERATURE, SR_UNIT_CELSIUS, 0 }, + { "FAR", SR_MQ_TEMPERATURE, SR_UNIT_FAHRENHEIT, 0 }, + { "PCT", SR_MQ_DUTY_CYCLE, SR_UNIT_PERCENTAGE, 0 }, + { "dBm", SR_MQ_VOLTAGE, SR_UNIT_DECIBEL_MW, SR_MQFLAG_AC | SR_MQFLAG_RMS }, + { "dBV", SR_MQ_VOLTAGE, SR_UNIT_DECIBEL_VOLT, SR_MQFLAG_AC | SR_MQFLAG_RMS }, +}; + +static const struct unit_mapping *parse_unit(const char *name) +{ + unsigned int i; + + if (!name) + return NULL; + + for (i = 0; i < ARRAY_SIZE(unit_map); i++) { + if (!strcmp(unit_map[i].name, name)) + return &unit_map[i]; + } + + sr_warn("Unknown unit '%s'", name); + return NULL; +} + +static enum measurement_state parse_measurement_state(const char *name) +{ + unsigned int i; + + if (!name) + return MEAS_S_INVALID; + + for (i = 0; i < ARRAY_SIZE(state_map); i++) { + if (!strcmp(state_map[i].name, name)) + return state_map[i].state; + } + + sr_warn("Unknown measurement state '%s'", name); + return MEAS_S_INVALID; +} + +static enum measurement_attribute parse_attribute(const char *name) +{ + unsigned int i; + + if (!name) + return MEAS_A_INVALID; + + for (i = 0; i < ARRAY_SIZE(attribute_map); i++) { + if (!strcmp(attribute_map[i].name, name)) + return attribute_map[i].attribute; + } + + sr_warn("Unknown measurement attribute '%s'", name); + return MEAS_A_INVALID; +} + +SR_PRIV void fluke_handle_qm_28x(const struct sr_dev_inst *sdi, char **tokens) +{ + 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; + + float fvalue; + int digits; + const struct unit_mapping *unit; + enum measurement_state state; + enum measurement_attribute attr; + + devc = sdi->priv; + + /* We should have received four values: + * value, unit, state, attribute + */ + if (sr_atof_ascii_digits(tokens[0], &fvalue, &digits) != SR_OK) { + sr_err("Invalid float '%s'.", tokens[0]); + return; + } + + unit = parse_unit(tokens[1]); + if (!unit) { + sr_err("Invalid unit '%s'.", tokens[1]); + return; + } + + state = parse_measurement_state(tokens[2]); + attr = parse_attribute(tokens[3]); + + sr_analog_init(&analog, &encoding, &meaning, &spec, digits); + analog.data = &fvalue; + analog.meaning->channels = sdi->channels; + analog.num_samples = 1; + analog.meaning->mq = unit->mq; + analog.meaning->mqflags = unit->mqflags; + analog.meaning->unit = unit->unit; + + if (unit->mq == SR_MQ_RESISTANCE) { + switch (attr) { + case MEAS_A_NONE: + /* Normal reading */ + break; + case MEAS_A_OPEN_CIRCUIT: + case MEAS_A_SHORT_CIRCUIT: + /* Continuity measurement */ + analog.meaning->mq = SR_MQ_CONTINUITY; + analog.meaning->unit = SR_UNIT_BOOLEAN; + fvalue = attr == MEAS_A_OPEN_CIRCUIT ? 0.0 : 1.0; + break; + default: + analog.meaning->mq = 0; + break; + }; + } + + switch (state) { + case MEAS_S_NORMAL: + break; + + case MEAS_S_OL: + fvalue = INFINITY; + break; + + case MEAS_S_OL_MINUS: + fvalue = -INFINITY; + break; + + case MEAS_S_OPEN_TC: + fvalue = NAN; + break; + + default: + analog.meaning->mq = 0; + break; + } + + if (analog.meaning->mq) { + /* Got a measurement. */ + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + sr_session_send(sdi, &packet); + sr_sw_limits_update_samples_read(&devc->limits, 1); + } +} diff --git a/src/hardware/fluke-dmm/protocol.c b/src/hardware/fluke-dmm/protocol.c index d8837f66..848374a4 100644 --- a/src/hardware/fluke-dmm/protocol.c +++ b/src/hardware/fluke-dmm/protocol.c @@ -196,140 +196,6 @@ static void handle_qm_18x(const struct sr_dev_inst *sdi, char **tokens) } } -static void handle_qm_28x(const struct sr_dev_inst *sdi, char **tokens) -{ - 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; - float fvalue; - int digits; - int exponent; - char *e; - - devc = sdi->priv; - - if (!tokens[1]) - return; - - /* Split measurement into mantissa / exponent */ - e = tokens[0]; - while (*e) { - if (*e == 'e' || *e == 'E') { - *e = '\0'; - e++; - break; - } - e++; - } - - if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK) { - sr_err("Invalid mantissa '%s'.", tokens[0]); - return; - } - - if (sr_atoi(e, &exponent) != SR_OK) { - sr_err("Invalid exponent '%s'.", e); - return; - } - - digits = count_digits(tokens[0]) - exponent; - fvalue *= pow(10.0f, exponent); - - sr_analog_init(&analog, &encoding, &meaning, &spec, digits); - analog.data = &fvalue; - analog.meaning->channels = sdi->channels; - analog.num_samples = 1; - analog.meaning->mq = 0; - - if (!strcmp(tokens[1], "VAC") || !strcmp(tokens[1], "VDC")) { - analog.meaning->mq = SR_MQ_VOLTAGE; - analog.meaning->unit = SR_UNIT_VOLT; - if (!strcmp(tokens[2], "NORMAL")) { - if (tokens[1][1] == 'A') { - analog.meaning->mqflags |= SR_MQFLAG_AC; - analog.meaning->mqflags |= SR_MQFLAG_RMS; - } else - analog.meaning->mqflags |= SR_MQFLAG_DC; - } else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) { - fvalue = NAN; - } else - analog.meaning->mq = 0; - } else if (!strcmp(tokens[1], "dBV") || !strcmp(tokens[1], "dBm")) { - analog.meaning->mq = SR_MQ_VOLTAGE; - if (tokens[1][2] == 'm') - analog.meaning->unit = SR_UNIT_DECIBEL_MW; - else - analog.meaning->unit = SR_UNIT_DECIBEL_VOLT; - analog.meaning->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS; - } else if (!strcmp(tokens[1], "CEL") || !strcmp(tokens[1], "FAR")) { - if (!strcmp(tokens[2], "NORMAL")) { - analog.meaning->mq = SR_MQ_TEMPERATURE; - if (tokens[1][0] == 'C') - analog.meaning->unit = SR_UNIT_CELSIUS; - else - analog.meaning->unit = SR_UNIT_FAHRENHEIT; - } - } else if (!strcmp(tokens[1], "OHM")) { - if (!strcmp(tokens[3], "NONE")) { - analog.meaning->mq = SR_MQ_RESISTANCE; - analog.meaning->unit = SR_UNIT_OHM; - if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) { - fvalue = INFINITY; - } else if (strcmp(tokens[2], "NORMAL")) - analog.meaning->mq = 0; - } else if (!strcmp(tokens[3], "OPEN_CIRCUIT")) { - analog.meaning->mq = SR_MQ_CONTINUITY; - analog.meaning->unit = SR_UNIT_BOOLEAN; - fvalue = 0.0; - } else if (!strcmp(tokens[3], "SHORT_CIRCUIT")) { - analog.meaning->mq = SR_MQ_CONTINUITY; - analog.meaning->unit = SR_UNIT_BOOLEAN; - fvalue = 1.0; - } - } else if (!strcmp(tokens[1], "F") - && !strcmp(tokens[2], "NORMAL") - && !strcmp(tokens[3], "NONE")) { - analog.meaning->mq = SR_MQ_CAPACITANCE; - analog.meaning->unit = SR_UNIT_FARAD; - } else if (!strcmp(tokens[1], "AAC") || !strcmp(tokens[1], "ADC")) { - analog.meaning->mq = SR_MQ_CURRENT; - analog.meaning->unit = SR_UNIT_AMPERE; - if (!strcmp(tokens[2], "NORMAL")) { - if (tokens[1][1] == 'A') { - analog.meaning->mqflags |= SR_MQFLAG_AC; - analog.meaning->mqflags |= SR_MQFLAG_RMS; - } else - analog.meaning->mqflags |= SR_MQFLAG_DC; - } else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) { - fvalue = NAN; - } else - analog.meaning->mq = 0; - } else if (!strcmp(tokens[1], "Hz") && !strcmp(tokens[2], "NORMAL")) { - analog.meaning->mq = SR_MQ_FREQUENCY; - analog.meaning->unit = SR_UNIT_HERTZ; - } else if (!strcmp(tokens[1], "PCT") && !strcmp(tokens[2], "NORMAL")) { - analog.meaning->mq = SR_MQ_DUTY_CYCLE; - analog.meaning->unit = SR_UNIT_PERCENTAGE; - } else if (!strcmp(tokens[1], "S") && !strcmp(tokens[2], "NORMAL")) { - analog.meaning->mq = SR_MQ_PULSE_WIDTH; - analog.meaning->unit = SR_UNIT_SECOND; - } else if (!strcmp(tokens[1], "SIE") && !strcmp(tokens[2], "NORMAL")) { - analog.meaning->mq = SR_MQ_CONDUCTANCE; - analog.meaning->unit = SR_UNIT_SIEMENS; - } - - if (analog.meaning->mq != 0) { - /* Got a measurement. */ - packet.type = SR_DF_ANALOG; - packet.payload = &analog; - sr_session_send(sdi, &packet); - sr_sw_limits_update_samples_read(&devc->limits, 1); - } -} - static void handle_qm_19x_meta(const struct sr_dev_inst *sdi, char **tokens) { struct dev_context *devc; @@ -545,7 +411,7 @@ static void handle_line(const struct sr_dev_inst *sdi) case FLUKE_287: case FLUKE_289: devc->expect_response = FALSE; - handle_qm_28x(sdi, tokens); + fluke_handle_qm_28x(sdi, tokens); break; } } diff --git a/src/hardware/fluke-dmm/protocol.h b/src/hardware/fluke-dmm/protocol.h index 4eab15ac..14adc18e 100644 --- a/src/hardware/fluke-dmm/protocol.h +++ b/src/hardware/fluke-dmm/protocol.h @@ -63,6 +63,8 @@ struct dev_context { enum sr_mqflag mqflags; }; +SR_PRIV void fluke_handle_qm_28x(const struct sr_dev_inst *sdi, char **tokens); + SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data); #endif