From: Gerhard Sittig Date: Wed, 7 Feb 2018 21:09:14 +0000 (+0100) Subject: serial-dmm, metex14: add support for multiple channels per DMM X-Git-Url: https://sigrok.org/gitweb/?a=commitdiff_plain;h=556a926d432dd21a1d911daec13c6a6bbc49cdbb;p=libsigrok.git serial-dmm, metex14: add support for multiple channels per DMM Optionally create multiple analog channels in serial-dmm's scan() routine. Allow the meters' parse routines to fill in more than one analog value from the inspection of a single packet. Use "large" (4 times 14 bytes) packets for the Metex M-3860M and the PeakTech 4390A meters, and have those large packets parsed by wrapping the routines for regular 14-byte Metex packets, and sending four values to the session bus after reception of one large packet. Thanks to Frank Stettner for testing and fixing the initial implementation of this extension. --- diff --git a/src/dmm/metex14.c b/src/dmm/metex14.c index 687df906..2d0a70d6 100644 --- a/src/dmm/metex14.c +++ b/src/dmm/metex14.c @@ -313,6 +313,25 @@ SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf) return TRUE; } +SR_PRIV gboolean sr_metex14_4packets_valid(const uint8_t *buf) +{ + struct metex14_info info; + size_t ch_idx; + const uint8_t *ch_buf; + + ch_buf = buf; + for (ch_idx = 0; ch_idx < 4; ch_idx++) { + if (ch_buf[13] != '\r') + return FALSE; + memset(&info, 0x00, sizeof(info)); + parse_flags((const char *)ch_buf, &info); + if (!flags_valid(&info)) + return FALSE; + ch_buf += METEX14_PACKET_SIZE; + } + return TRUE; +} + /** * Parse a protocol packet. * @@ -354,3 +373,34 @@ SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval, return SR_OK; } + +/** + * Parse one out of four values of a four-display Metex14 variant. + * + * The caller's 'info' parameter can be used to track the channel index, + * as long as the information is kept across calls to the 14-byte packet + * parse routine (which clears the 'info' container). + * + * Since analog values have further details in the 'analog' parameter, + * passing multiple values per parse routine call is problematic. So we + * prefer the approach of passing one value per call, which is most + * reliable and shall fit every similar device with multiple displays. + * + * The meters which use this parse routine send one 14-byte packet per + * display. Each packet has the regular Metex14 layout. + */ +SR_PRIV int sr_metex14_4packets_parse(const uint8_t *buf, float *floatval, + struct sr_datafeed_analog *analog, void *info) +{ + struct metex14_info *info_local; + size_t ch_idx; + const uint8_t *ch_buf; + int rc; + + info_local = info; + ch_idx = info_local->ch_idx; + ch_buf = buf + ch_idx * METEX14_PACKET_SIZE; + rc = sr_metex14_parse(ch_buf, floatval, analog, info); + info_local->ch_idx = ch_idx + 1; + return rc; +} diff --git a/src/hardware/serial-dmm/api.c b/src/hardware/serial-dmm/api.c index eb453c78..2611aa6f 100644 --- a/src/hardware/serial-dmm/api.c +++ b/src/hardware/serial-dmm/api.c @@ -56,6 +56,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) int dropped, ret; size_t len; uint8_t buf[128]; + size_t ch_idx; + char ch_name[12]; dmm = (struct dmm_info *)di; @@ -131,7 +133,13 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) sdi->inst_type = SR_INST_SERIAL; sdi->conn = serial; sdi->priv = devc; - sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P1"); + dmm->channel_count = 1; + if (dmm->packet_parse == sr_metex14_4packets_parse) + dmm->channel_count = 4; + for (ch_idx = 0; ch_idx < dmm->channel_count; ch_idx++) { + snprintf(ch_name, sizeof(ch_name), "P%zu", ch_idx); + sr_channel_new(sdi, ch_idx, SR_CHANNEL_ANALOG, TRUE, ch_name); + } devices = g_slist_append(devices, sdi); scan_cleanup: @@ -197,7 +205,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) .context = NULL, \ }, \ VENDOR, MODEL, CONN, BAUDRATE, PACKETSIZE, TIMEOUT, DELAY, \ - REQUEST, VALID, PARSE, DETAILS, sizeof(struct CHIPSET##_info) \ + REQUEST, 1, VALID, PARSE, DETAILS, sizeof(struct CHIPSET##_info) \ }).di SR_REGISTER_DEV_DRIVER_LIST(serial_dmm_drivers, @@ -440,8 +448,8 @@ SR_REGISTER_DEV_DRIVER_LIST(serial_dmm_drivers, DMM( "metex-m3860m", metex14, "Metex", "M-3860M", "9600/7n2/rts=0/dtr=1", 9600, - METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request, - sr_metex14_packet_valid, sr_metex14_parse, + 4 * METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request, + sr_metex14_4packets_valid, sr_metex14_4packets_parse, NULL ), DMM( @@ -475,8 +483,8 @@ SR_REGISTER_DEV_DRIVER_LIST(serial_dmm_drivers, DMM( "peaktech-4390a", metex14, "PeakTech", "4390A", "9600/7n2/rts=0/dtr=1", 9600, - METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request, - sr_metex14_packet_valid, sr_metex14_parse, + 4 * METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request, + sr_metex14_4packets_valid, sr_metex14_4packets_parse, NULL ), DMM( diff --git a/src/hardware/serial-dmm/protocol.c b/src/hardware/serial-dmm/protocol.c index 9d3bc916..e5f50ff7 100644 --- a/src/hardware/serial-dmm/protocol.c +++ b/src/hardware/serial-dmm/protocol.c @@ -49,31 +49,42 @@ static void handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi, struct sr_analog_meaning meaning; struct sr_analog_spec spec; struct dev_context *devc; + gboolean sent_sample; + size_t ch_idx; dmm = (struct dmm_info *)sdi->driver; log_dmm_packet(buf); devc = sdi->priv; - /* Note: digits/spec_digits will be overridden by the DMM parsers. */ - sr_analog_init(&analog, &encoding, &meaning, &spec, 0); - - analog.meaning->channels = sdi->channels; - analog.num_samples = 1; - analog.meaning->mq = 0; - - dmm->packet_parse(buf, &floatval, &analog, info); - analog.data = &floatval; - - /* If this DMM needs additional handling, call the resp. function. */ - if (dmm->dmm_details) - dmm->dmm_details(&analog, info); + sent_sample = FALSE; + memset(info, 0, dmm->info_size); + for (ch_idx = 0; ch_idx < dmm->channel_count; ch_idx++) { + /* Note: digits/spec_digits will be overridden by the DMM parsers. */ + sr_analog_init(&analog, &encoding, &meaning, &spec, 0); + + analog.meaning->channels = + g_slist_append(NULL, g_slist_nth_data(sdi->channels, ch_idx)); + analog.num_samples = 1; + analog.meaning->mq = 0; + + dmm->packet_parse(buf, &floatval, &analog, info); + analog.data = &floatval; + + /* If this DMM needs additional handling, call the resp. function. */ + if (dmm->dmm_details) + dmm->dmm_details(&analog, info); + + if (analog.meaning->mq != 0) { + /* Got a measurement. */ + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + sr_session_send(sdi, &packet); + sent_sample = TRUE; + } + } - if (analog.meaning->mq != 0) { - /* Got a measurement. */ - packet.type = SR_DF_ANALOG; - packet.payload = &analog; - sr_session_send(sdi, &packet); + if (sent_sample) { sr_sw_limits_update_samples_read(&devc->limits, 1); } } diff --git a/src/hardware/serial-dmm/protocol.h b/src/hardware/serial-dmm/protocol.h index c80180ce..696f6b6e 100644 --- a/src/hardware/serial-dmm/protocol.h +++ b/src/hardware/serial-dmm/protocol.h @@ -47,6 +47,8 @@ struct dmm_info { int64_t req_delay_ms; /** Packet request function. */ int (*packet_request)(struct sr_serial_dev_inst *); + /** Number of channels / displays. */ + size_t channel_count; /** Packet validation function. */ gboolean (*packet_valid)(const uint8_t *); /** Packet parsing function. */ diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index 9fdd81da..98f224b4 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -1273,6 +1273,7 @@ SR_PRIV int sr_m2110_parse(const uint8_t *buf, float *floatval, #define METEX14_PACKET_SIZE 14 struct metex14_info { + size_t ch_idx; gboolean is_ac, is_dc, is_resistance, is_capacity, is_temperature; gboolean is_diode, is_frequency, is_ampere, is_volt, is_farad; gboolean is_hertz, is_ohm, is_celsius, is_pico, is_nano, is_micro; @@ -1286,6 +1287,9 @@ SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial); SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf); SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval, struct sr_datafeed_analog *analog, void *info); +SR_PRIV gboolean sr_metex14_4packets_valid(const uint8_t *buf); +SR_PRIV int sr_metex14_4packets_parse(const uint8_t *buf, float *floatval, + struct sr_datafeed_analog *analog, void *info); /*--- hardware/dmm/rs9lcd.c -------------------------------------------------*/