]> sigrok.org Git - libsigrok.git/commitdiff
serial-dmm, metex14: add support for multiple channels per DMM
authorGerhard Sittig <redacted>
Wed, 7 Feb 2018 21:09:14 +0000 (22:09 +0100)
committerUwe Hermann <redacted>
Sun, 18 Feb 2018 14:43:34 +0000 (15:43 +0100)
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 <redacted> for testing and
fixing the initial implementation of this extension.

src/dmm/metex14.c
src/hardware/serial-dmm/api.c
src/hardware/serial-dmm/protocol.c
src/hardware/serial-dmm/protocol.h
src/libsigrok-internal.h

index 687df9063fbb50cf14679dae361d53030763b4e5..2d0a70d640475d9778a92c03973e974d0c7c8d2e 100644 (file)
@@ -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;
+}
index eb453c78a7a8b040b7217c63b7b457c272456ac9..2611aa6fe905d8edad4a9511e9ba2a4b9b068182 100644 (file)
@@ -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(
index 9d3bc916271cb6e9fc0bc0cd09328f56ecde8862..e5f50ff7a1de7bf3587d755a68bc770d9480f0f5 100644 (file)
@@ -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);
        }
 }
index c80180ce0b976c089036b8d26d4b50d249b3ef53..696f6b6ef314e0dfca2e7cae6777669f07f1b428 100644 (file)
@@ -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. */
index 9fdd81dac4c26310614f1f2a22307ec7ba572444..98f224b481f5406b0fa7912a2443be3beb153e06 100644 (file)
@@ -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 -------------------------------------------------*/