]> sigrok.org Git - libsigrok.git/commitdiff
fluke-dmm: support for all basic 287 functionality
authorBert Vermeulen <redacted>
Tue, 25 Sep 2012 17:38:59 +0000 (19:38 +0200)
committerBert Vermeulen <redacted>
Tue, 25 Sep 2012 17:53:05 +0000 (19:53 +0200)
hardware/fluke-dmm/Makefile.am
hardware/fluke-dmm/api.c
hardware/fluke-dmm/fluke-dmm.h
hardware/fluke-dmm/fluke.c [new file with mode: 0644]

index 1140b4c91bd7fad7079ddebc5b8001ff9908fdec..8f37802349cd110740db032117c9d937ebc43ef8 100644 (file)
@@ -24,6 +24,7 @@ noinst_LTLIBRARIES = libsigrokhwflukedmm.la
 
 libsigrokhwflukedmm_la_SOURCES = \
        api.c \
+       fluke.c \
        fluke-dmm.h
 
 libsigrokhwflukedmm_la_CFLAGS = \
index 3b3d3f7bedf353772a361af271ba0400361c03d6..e75849e6e0134e9dbbef816d8107c19b21f7154f 100644 (file)
@@ -51,8 +51,8 @@ SR_PRIV struct sr_dev_driver flukedmm_driver_info;
 static struct sr_dev_driver *di = &flukedmm_driver_info;
 
 static const struct flukedmm_profile supported_flukedmm[] = {
-       { FLUKE_187, "187" },
-       { FLUKE_287, "287" },
+       { FLUKE_187, "187", 100 },
+       { FLUKE_287, "287", 100 },
 };
 
 
@@ -404,7 +404,14 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
        sr_session_send(devc->cb_data, &packet);
 
        /* Poll every 100ms, or whenever some data comes in. */
-       sr_source_add(devc->serial->fd, G_IO_IN, 100, fluke_receive_data, (void *)sdi);
+       sr_source_add(devc->serial->fd, G_IO_IN, 50, fluke_receive_data, (void *)sdi);
+
+       if (serial_write(devc->serial->fd, "QM\r", 3) == -1) {
+               sr_err("fluke-dmm: unable to send QM: %s", strerror(errno));
+               return SR_ERR;
+       }
+       devc->cmd_sent_at = g_get_monotonic_time() / 1000;
+       devc->expect_response = TRUE;
 
        return SR_OK;
 }
index 7174531c4ee8df49fa030076a083704ff537bd16..0aac45b7c23b4cedb11f91a37d5153ed3456832a 100644 (file)
@@ -33,6 +33,8 @@ enum {
 struct flukedmm_profile {
        int model;
        const char *modelname;
+       /* How often to poll, in ms. */
+       int poll_period;
 };
 
 /* Private driver context. */
@@ -53,8 +55,12 @@ struct dev_context {
 
        /* Runtime. */
        uint64_t num_samples;
-       unsigned char buf[FLUKEDMM_BUFSIZE];
+       char buf[FLUKEDMM_BUFSIZE];
        int buflen;
+       int64_t cmd_sent_at;
+       int expect_response;
 };
 
+SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data);
+
 #endif /* LIBSIGROK_FLUKE_DMM_H */
diff --git a/hardware/fluke-dmm/fluke.c b/hardware/fluke-dmm/fluke.c
new file mode 100644 (file)
index 0000000..8095097
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * This file is part of the sigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "config.h"
+#include "fluke-dmm.h"
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+
+
+static struct sr_datafeed_analog *handle_qm_v2(const struct sr_dev_inst *sdi,
+               char **tokens)
+{
+       struct sr_datafeed_analog *analog;
+       float fvalue;
+       char *eptr;
+
+       (void)sdi;
+       fvalue = strtof(tokens[0], &eptr);
+       if (fvalue == 0.0 && eptr == tokens[0]) {
+               sr_err("fluke-dmm: invalid float");
+               return NULL;
+       }
+
+       analog = g_try_malloc0(sizeof(struct sr_datafeed_analog));
+       analog->num_samples = 1;
+       analog->data = g_try_malloc(sizeof(float));
+       *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;
+       } 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;
+               }
+       } 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;
+               }
+       } 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;
+               analog->mqflags = SR_MQFLAG_RMS;
+               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;
+       } if (!strcmp(tokens[1], "PCT") && !strcmp(tokens[2], "NORMAL")) {
+               analog->mq = SR_MQ_DUTY_CYCLE;
+               analog->unit = SR_UNIT_PERCENTAGE;
+       } if (!strcmp(tokens[1], "S") && !strcmp(tokens[2], "NORMAL")) {
+               analog->mq = SR_MQ_PULSE_WIDTH;
+               analog->unit = SR_UNIT_SECOND;
+       } 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;
+}
+
+static void handle_line(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog *analog;
+       char **tokens;
+
+       devc = sdi->priv;
+       sr_spew("fluke-dmm: received line '%s' (%d)", devc->buf, devc->buflen);
+
+       if (devc->buflen == 1) {
+               if (devc->buf[0] != '0') {
+                       /* Not just a CMD_ACK from the query command. */
+                       sr_dbg("fluke-dmm: got CMD_ACK '%c'", devc->buf[0]);
+                       devc->expect_response = FALSE;
+               }
+               devc->buflen = 0;
+               return;
+       }
+
+       analog = NULL;
+       tokens = g_strsplit(devc->buf, ",", 0);
+       if (devc->profile->model == FLUKE_187) {
+               if (!strcmp(tokens[0], "QM")) {
+                       /* Yes, this is the response to the query. */
+                       devc->expect_response = FALSE;
+                       sr_spew("187 line");
+                       /* TODO */
+                       devc->buflen = 0;
+               }
+       } else if (devc->profile->model == FLUKE_287) {
+               devc->expect_response = FALSE;
+               analog = handle_qm_v2(sdi, tokens);
+       }
+       g_strfreev(tokens);
+       devc->buflen = 0;
+
+       if (analog) {
+               /* Got a measurement. */
+               sr_dbg("val %f", *analog->data);
+               packet.type = SR_DF_ANALOG;
+               packet.payload = analog;
+               sr_session_send(devc->cb_data, &packet);
+               devc->num_samples++;
+               g_free(analog->data);
+               g_free(analog);
+       }
+
+}
+
+SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data)
+{
+       const struct sr_dev_inst *sdi;
+       struct dev_context *devc;
+       int len;
+       int64_t now, elapsed;
+
+       if (!(sdi = cb_data))
+               return TRUE;
+
+       if (!(devc = sdi->priv))
+               return TRUE;
+
+       if (revents == G_IO_IN) {
+               /* Serial data arrived. */
+               while(FLUKEDMM_BUFSIZE - devc->buflen - 1 > 0) {
+                       len = serial_read(fd, devc->buf + devc->buflen, 1);
+                       if (len < 1)
+                               break;
+                       devc->buflen++;
+                       *(devc->buf + devc->buflen) = '\0';
+                       if (*(devc->buf + devc->buflen - 1) == '\r') {
+                               *(devc->buf + --devc->buflen) = '\0';
+                               handle_line(sdi);
+                               break;
+                       }
+               }
+       }
+
+       if (devc->num_samples >= devc->limit_samples) {
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
+               return TRUE;
+       }
+
+       now = g_get_monotonic_time() / 1000;
+       elapsed = now - devc->cmd_sent_at;
+       /* Send query command at poll_period interval, or after 1 second
+        * has elapsed. This will make it recover from any out-of-sync
+        * or temporary disconnect issues. */
+       if ((devc->expect_response == FALSE && elapsed > devc->profile->poll_period)
+                       || elapsed > 1000) {
+               sr_spew("fluke-dmm: sending QM");
+               if (serial_write(devc->serial->fd, "QM\r", 3) == -1)
+                       sr_err("fluke-dmm: unable to send QM: %s", strerror(errno));
+               devc->cmd_sent_at = now;
+               devc->expect_response = TRUE;
+       }
+
+       return TRUE;
+}
+
+