X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=hardware%2Fagilent-dmm%2Fsched.c;h=81fd333aabff735a0d295d663719cd0194711edb;hb=fe9d5abefcebb3a382d990e069d93c28e9541e35;hp=582ad28d1440c84c43bf6726f930baf0258e457b;hpb=e93cdf428c6383b9868d08bdae07ff775bedd0c0;p=libsigrok.git diff --git a/hardware/agilent-dmm/sched.c b/hardware/agilent-dmm/sched.c index 582ad28d..81fd333a 100644 --- a/hardware/agilent-dmm/sched.c +++ b/hardware/agilent-dmm/sched.c @@ -1,5 +1,5 @@ /* - * This file is part of the sigrok project. + * This file is part of the libsigrok project. * * Copyright (C) 2012 Bert Vermeulen * @@ -20,14 +20,12 @@ #include #include "libsigrok.h" #include "libsigrok-internal.h" -#include "config.h" #include "agilent-dmm.h" #include #include #include #include - static void dispatch(const struct sr_dev_inst *sdi) { struct dev_context *devc; @@ -40,12 +38,11 @@ static void dispatch(const struct sr_dev_inst *sdi) now = g_get_monotonic_time() / 1000; for (i = 0; (&jobs[i])->interval; i++) { if (now - devc->jobqueue[i] > (&jobs[i])->interval) { - sr_spew("agilent-dmm: running job %d", i); + sr_spew("Running job %d.", i); (&jobs[i])->send(sdi); devc->jobqueue[i] = now; } } - } static void receive_line(const struct sr_dev_inst *sdi) @@ -66,7 +63,7 @@ static void receive_line(const struct sr_dev_inst *sdi) else break; } - sr_spew("agilent-dmm: received '%s'", devc->buf); + sr_spew("Received '%s'.", devc->buf); recv = NULL; recvs = devc->profile->recvs; @@ -83,43 +80,48 @@ static void receive_line(const struct sr_dev_inst *sdi) recv->recv(sdi, match); g_match_info_unref(match); g_regex_unref(reg); - } + } else + sr_dbg("Unknown line '%s'.", devc->buf); /* Done with this. */ devc->buflen = 0; - } SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data) { - const struct sr_dev_inst *sdi; + struct sr_dev_inst *sdi; struct dev_context *devc; + struct sr_serial_dev_inst *serial; int len; + (void)fd; + if (!(sdi = cb_data)) return TRUE; if (!(devc = sdi->priv)) return TRUE; + serial = sdi->conn; if (revents == G_IO_IN) { /* Serial data arrived. */ - len = AGDMM_BUFSIZE - devc->buflen - 1; - if (len > 0) { - len = serial_read(fd, devc->buf + devc->buflen, len); - if (len > 0) { - devc->buflen += len; - *(devc->buf + devc->buflen) = '\0'; - if (devc->buflen > 0 && *(devc->buf + devc->buflen - 1) == '\n') - /* End of line */ - receive_line(sdi); + while(AGDMM_BUFSIZE - devc->buflen - 1 > 0) { + len = serial_read(serial, devc->buf + devc->buflen, 1); + if (len < 1) + break; + devc->buflen += len; + *(devc->buf + devc->buflen) = '\0'; + if (*(devc->buf + devc->buflen - 1) == '\n') { + /* End of line */ + receive_line(sdi); + break; } } } dispatch(sdi); - if (devc->num_samples >= devc->limit_samples) + if (devc->limit_samples && devc->num_samples >= devc->limit_samples) sdi->driver->dev_acquisition_stop(sdi, cb_data); return TRUE; @@ -127,69 +129,114 @@ SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data) static int agdmm_send(const struct sr_dev_inst *sdi, const char *cmd) { - struct dev_context *devc; + struct sr_serial_dev_inst *serial; char buf[32]; - devc = sdi->priv; - sr_spew("agilent-dmm: sending '%s'", cmd); + serial = sdi->conn; + + sr_spew("Sending '%s'.", cmd); strncpy(buf, cmd, 28); if (!strncmp(buf, "*IDN?", 5)) strncat(buf, "\r\n", 32); else strncat(buf, "\n\r\n", 32); - if (serial_write(devc->serial->fd, buf, strlen(buf)) == -1) { - sr_err("agilent-dmm: failed to send: %s", strerror(errno)); + if (serial_write(serial, buf, strlen(buf)) == -1) { + sr_err("Failed to send: %s.", strerror(errno)); return SR_ERR; } - + return SR_OK; } -static int agdmm_ident_send(const struct sr_dev_inst *sdi) +static int send_stat(const struct sr_dev_inst *sdi) { - - return agdmm_send(sdi, "*IDN?"); + return agdmm_send(sdi, "STAT?"); } -static int agdmm_ident_recv(const struct sr_dev_inst *sdi, GMatchInfo *match) +static int recv_stat_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match) { + struct dev_context *devc; + char *s; - (void)sdi; + devc = sdi->priv; + s = g_match_info_fetch(match, 1); + sr_spew("STAT response '%s'.", s); + + /* Max, Min or Avg mode -- no way to tell which, so we'll + * set both flags to denote it's not a normal measurement. */ + if (s[0] == '1') + devc->cur_mqflags |= SR_MQFLAG_MAX | SR_MQFLAG_MIN; + else + devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN); + + if (s[1] == '1') + devc->cur_mqflags |= SR_MQFLAG_RELATIVE; + else + devc->cur_mqflags &= ~SR_MQFLAG_RELATIVE; + + /* Triggered or auto hold modes. */ + if (s[2] == '1' || s[3] == '1') + devc->cur_mqflags |= SR_MQFLAG_HOLD; + else + devc->cur_mqflags &= ~SR_MQFLAG_HOLD; - sr_spew("got ident '%s'", g_match_info_get_string(match)); + /* Temp/aux mode. */ + if (s[7] == '1') + devc->mode_tempaux = TRUE; + else + devc->mode_tempaux = FALSE; + + /* Continuity mode. */ + if (s[16] == '1') + devc->mode_continuity = TRUE; + else + devc->mode_continuity = FALSE; + + g_free(s); return SR_OK; } -static int agdmm_stat_send(const struct sr_dev_inst *sdi) +static int recv_stat_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match) { + struct dev_context *devc; + char *s; - return agdmm_send(sdi, "STAT?"); -} + devc = sdi->priv; + s = g_match_info_fetch(match, 1); + sr_spew("STAT response '%s'.", s); -static int agdmm_stat_recv(const struct sr_dev_inst *sdi, GMatchInfo *match) -{ + /* Peak hold mode. */ + if (s[4] == '1') + devc->cur_mqflags |= SR_MQFLAG_MAX; + else + devc->cur_mqflags &= ~SR_MQFLAG_MAX; - sr_spew("got stat '%s'", g_match_info_get_string(match)); + /* Triggered hold mode. */ + if (s[7] == '1') + devc->cur_mqflags |= SR_MQFLAG_HOLD; + else + devc->cur_mqflags &= ~SR_MQFLAG_HOLD; + + g_free(s); return SR_OK; } -SR_PRIV int agdmm_fetc_send(const struct sr_dev_inst *sdi) +static int send_fetc(const struct sr_dev_inst *sdi) { - return agdmm_send(sdi, "FETC?"); } -SR_PRIV int agdmm_fetc_recv(const struct sr_dev_inst *sdi, GMatchInfo *match) +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; float fvalue; - char *mstr, *eptr; + char *mstr; - sr_spew("agilent-dmm: FETC reply '%s'", g_match_info_get_string(match)); + sr_spew("FETC reply '%s'.", g_match_info_get_string(match)); devc = sdi->priv; if (devc->cur_mq == -1) @@ -199,26 +246,27 @@ SR_PRIV int agdmm_fetc_recv(const struct sr_dev_inst *sdi, GMatchInfo *match) return SR_OK; if (!strcmp(g_match_info_get_string(match), "+9.90000000E+37")) { - /* An invalid measurement shows up on the display as "O.L, but + /* 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); - fvalue = strtof(mstr, &eptr); - g_free(mstr); - if (fvalue == 0.0 && eptr == mstr) { - sr_err("agilent-dmm: invalid float"); + if (sr_atof_ascii(mstr, &fvalue) != SR_OK || fvalue == 0.0) { + g_free(mstr); + sr_err("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)); analog.mq = devc->cur_mq; - analog.unit = devc->cur_mq_unit; - analog.mqflags = devc->cur_mq_flags; + analog.unit = devc->cur_unit; + analog.mqflags = devc->cur_mqflags; + analog.probes = sdi->probes; analog.num_samples = 1; analog.data = &fvalue; packet.type = SR_DF_ANALOG; @@ -230,106 +278,197 @@ SR_PRIV int agdmm_fetc_recv(const struct sr_dev_inst *sdi, GMatchInfo *match) return SR_OK; } -SR_PRIV int agdmm_conf_send(const struct sr_dev_inst *sdi) +static int send_conf(const struct sr_dev_inst *sdi) { - return agdmm_send(sdi, "CONF?"); } -SR_PRIV int agdmm_conf_recv(const struct sr_dev_inst *sdi, GMatchInfo *match) +static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match) { struct dev_context *devc; char *mstr; - sr_spew("got conf '%s'", g_match_info_get_string(match)); + sr_spew("CONF? response '%s'.", g_match_info_get_string(match)); devc = sdi->priv; mstr = g_match_info_fetch(match, 1); if (!strcmp(mstr, "V")) { devc->cur_mq = SR_MQ_VOLTAGE; - devc->cur_mq_unit = SR_UNIT_VOLT; - devc->cur_mq_flags = 0; + devc->cur_unit = SR_UNIT_VOLT; + devc->cur_mqflags = 0; devc->cur_divider = 0; } else if(!strcmp(mstr, "MV")) { - devc->cur_mq = SR_MQ_VOLTAGE; - devc->cur_mq_unit = SR_UNIT_VOLT; - devc->cur_mq_flags = 0; - devc->cur_divider = 1000; + if (devc->mode_tempaux) { + devc->cur_mq = SR_MQ_TEMPERATURE; + /* No way to detect whether Fahrenheit or Celcius + * is used, so we'll just default to Celcius. */ + devc->cur_unit = SR_UNIT_CELSIUS; + devc->cur_mqflags = 0; + devc->cur_divider = 0; + } else { + devc->cur_mq = SR_MQ_VOLTAGE; + devc->cur_unit = SR_UNIT_VOLT; + devc->cur_mqflags = 0; + devc->cur_divider = 1000; + } } else if(!strcmp(mstr, "A")) { devc->cur_mq = SR_MQ_CURRENT; - devc->cur_mq_unit = SR_UNIT_AMPERE; - devc->cur_mq_flags = 0; + devc->cur_unit = SR_UNIT_AMPERE; + devc->cur_mqflags = 0; devc->cur_divider = 0; } else if(!strcmp(mstr, "UA")) { devc->cur_mq = SR_MQ_CURRENT; - devc->cur_mq_unit = SR_UNIT_AMPERE; - devc->cur_mq_flags = 0; + devc->cur_unit = SR_UNIT_AMPERE; + devc->cur_mqflags = 0; devc->cur_divider = 1000000; } else if(!strcmp(mstr, "FREQ")) { devc->cur_mq = SR_MQ_FREQUENCY; - devc->cur_mq_unit = SR_UNIT_HERTZ; - devc->cur_mq_flags = 0; + devc->cur_unit = SR_UNIT_HERTZ; + devc->cur_mqflags = 0; devc->cur_divider = 0; } else if(!strcmp(mstr, "RES")) { - devc->cur_mq = SR_MQ_RESISTANCE; - devc->cur_mq_unit = SR_UNIT_OHM; - devc->cur_mq_flags = 0; + if (devc->mode_continuity) { + devc->cur_mq = SR_MQ_CONTINUITY; + devc->cur_unit = SR_UNIT_BOOLEAN; + } else { + devc->cur_mq = SR_MQ_RESISTANCE; + devc->cur_unit = SR_UNIT_OHM; + } + devc->cur_mqflags = 0; devc->cur_divider = 0; } else if(!strcmp(mstr, "CAP")) { devc->cur_mq = SR_MQ_CAPACITANCE; - devc->cur_mq_unit = SR_UNIT_FARAD; - devc->cur_mq_flags = 0; - devc->cur_divider = 0; - } else if(!strcmp(mstr, "DIOD")) { - devc->cur_mq = SR_MQ_VOLTAGE; - devc->cur_mq_unit = SR_UNIT_VOLT; - devc->cur_mq_flags = SR_MQFLAG_DIODE; + devc->cur_unit = SR_UNIT_FARAD; + devc->cur_mqflags = 0; devc->cur_divider = 0; } else - sr_dbg("agilent-dmm: unknown first argument"); + sr_dbg("Unknown first argument."); g_free(mstr); - if (g_match_info_get_match_count(match) == 3) { - mstr = g_match_info_fetch(match, 1); + if (g_match_info_get_match_count(match) == 4) { + mstr = g_match_info_fetch(match, 3); /* Third value, if present, is always AC or DC. */ if (!strcmp(mstr, "AC")) - devc->cur_acdc = 1; + devc->cur_mqflags |= SR_MQFLAG_AC; else if (!strcmp(mstr, "DC")) - devc->cur_acdc = 2; + devc->cur_mqflags |= SR_MQFLAG_DC; else - sr_dbg("agilent-dmm: unknown third argument"); + sr_dbg("Unknown third argument."); g_free(mstr); - } + } else + devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC); return SR_OK; } -SR_PRIV int agdmm_switch_recv(const struct sr_dev_inst *sdi, GMatchInfo *match) +static int recv_conf_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match) { + struct dev_context *devc; + char *mstr; - (void)sdi; + sr_spew("CONF? response '%s'.", g_match_info_get_string(match)); + devc = sdi->priv; + mstr = g_match_info_fetch(match, 1); + if (!strncmp(mstr, "VOLT", 4)) { + devc->cur_mq = SR_MQ_VOLTAGE; + devc->cur_unit = SR_UNIT_VOLT; + devc->cur_mqflags = 0; + devc->cur_divider = 0; + if (mstr[4] == ':') { + if (!strcmp(mstr + 4, "AC")) + devc->cur_mqflags |= SR_MQFLAG_AC; + else if (!strcmp(mstr + 4, "DC")) + devc->cur_mqflags |= SR_MQFLAG_DC; + else + /* "ACDC" appears as well, no idea what it means. */ + devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC); + } else + devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC); + } else if(!strcmp(mstr, "CURR")) { + devc->cur_mq = SR_MQ_CURRENT; + devc->cur_unit = SR_UNIT_AMPERE; + devc->cur_mqflags = 0; + devc->cur_divider = 0; + } else if(!strcmp(mstr, "RES")) { + if (devc->mode_continuity) { + devc->cur_mq = SR_MQ_CONTINUITY; + devc->cur_unit = SR_UNIT_BOOLEAN; + } else { + devc->cur_mq = SR_MQ_RESISTANCE; + devc->cur_unit = SR_UNIT_OHM; + } + devc->cur_mqflags = 0; + devc->cur_divider = 0; + } else + sr_dbg("Unknown first argument."); + g_free(mstr); + + return SR_OK; +} + +/* At least the 123x and 125x appear to have this. */ +static int recv_conf(const struct sr_dev_inst *sdi, GMatchInfo *match) +{ + struct dev_context *devc; + char *mstr; - sr_spew("got switch '%s'", g_match_info_get_string(match)); + sr_spew("CONF? response '%s'.", g_match_info_get_string(match)); + devc = sdi->priv; + mstr = g_match_info_fetch(match, 1); + if(!strcmp(mstr, "DIOD")) { + devc->cur_mq = SR_MQ_VOLTAGE; + devc->cur_unit = SR_UNIT_VOLT; + devc->cur_mqflags = SR_MQFLAG_DIODE; + devc->cur_divider = 0; + } else + sr_dbg("Unknown single argument."); + g_free(mstr); return SR_OK; } +/* This comes in whenever the rotary switch is changed to a new position. + * We could use it to determine the major measurement mode, but we already + * have the output of CONF? for that, which is more detailed. However + * we do need to catch this here, or it'll show up in some other output. */ +static int recv_switch(const struct sr_dev_inst *sdi, GMatchInfo *match) +{ + (void)sdi; + + sr_spew("Switch '%s'.", g_match_info_get_string(match)); + + return SR_OK; +} -SR_PRIV const struct agdmm_job u123x_jobs[] = { - { 1000, agdmm_ident_send }, - { 143, agdmm_stat_send }, - { 1000, agdmm_conf_send }, - { 143, agdmm_fetc_send }, +SR_PRIV const struct agdmm_job agdmm_jobs_u123x[] = { + { 143, send_stat }, + { 1000, send_conf }, + { 143, send_fetc }, { 0, NULL } }; -SR_PRIV const struct agdmm_recv u123x_recvs[] = { - { "^\"(\\d\\d.{18}\\d)\"$", agdmm_stat_recv }, - { "^\\*([0-9])$", agdmm_switch_recv }, - { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", agdmm_fetc_recv }, - { "^\"(V|MV|A|UA|FREQ),(\\d),(AC|DC)\"$", agdmm_conf_recv }, - { "^\"(RES|CAP),(\\d)\"$", agdmm_conf_recv }, - { "^\"(DIOD)\"$", agdmm_conf_recv }, +SR_PRIV const struct agdmm_recv agdmm_recvs_u123x[] = { + { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u123x }, + { "^\\*([0-9])$", recv_switch }, + { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc }, + { "^\"(V|MV|A|UA|FREQ),(\\d),(AC|DC)\"$", recv_conf_u123x }, + { "^\"(RES|CAP),(\\d)\"$", recv_conf_u123x}, + { "^\"(DIOD)\"$", recv_conf }, { NULL, NULL } }; +SR_PRIV const struct agdmm_job agdmm_jobs_u125x[] = { + { 143, send_stat }, + { 1000, send_conf }, + { 143, send_fetc }, + { 0, NULL } +}; +SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = { + { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x }, + { "^\\*([0-9])$", recv_switch }, + { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc }, + { "^(VOLT|CURR|RES|CAP) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x }, + { "^(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x }, + { "^\"(DIOD)\"$", recv_conf }, + { NULL, NULL } +};