/** * Process received line. It consists of 20 hex digits + \\r\\n, * e.g. '08100400018100400000'. */ static void nma_process_line(const struct sr_dev_inst *sdi) { struct dev_context *devc; int pos, flags; int vt, range; /* Measurement value type, range in device format */ int mmode, devstat; /* Measuring mode, device status */ float value; /* Measured value */ float scale; /* Scaling factor depending on range and function */ struct sr_datafeed_analog analog; struct sr_analog_encoding encoding; struct sr_analog_meaning meaning; struct sr_analog_spec spec; struct sr_datafeed_packet packet; devc = sdi->priv; devc->buf[LINE_LENGTH] = '\0'; sr_spew("Received line '%s'.", devc->buf); /* Check line. */ if (strlen((const char *)devc->buf) != LINE_LENGTH) { sr_err("line: Invalid status '%s', must be 20 hex digits.", devc->buf); devc->buflen = 0; return; } for (pos = 0; pos < LINE_LENGTH; pos++) { if (!isxdigit(devc->buf[pos])) { sr_err("line: Expected hex digit in '%s' at pos %d!", devc->buf, pos); devc->buflen = 0; return; } } /* Start decoding. */ value = 0.0; scale = 1.0; /* TODO: Use proper 'digits' value for this device (and its modes). */ sr_analog_init(&analog, &encoding, &meaning, &spec, 2); /* * The numbers are hex digits, starting from 0. * 0: Keyboard status, currently not interesting. * 1: Central switch status, currently not interesting. * 2: Type of measured value. */ vt = xgittoint(devc->buf[2]); switch (vt) { case 0: analog.meaning->mq = SR_MQ_VOLTAGE; break; case 1: analog.meaning->mq = SR_MQ_CURRENT; /* 2A */ break; case 2: analog.meaning->mq = SR_MQ_RESISTANCE; break; case 3: analog.meaning->mq = SR_MQ_CAPACITANCE; break; case 4: analog.meaning->mq = SR_MQ_TEMPERATURE; break; case 5: analog.meaning->mq = SR_MQ_FREQUENCY; break; case 6: analog.meaning->mq = SR_MQ_CURRENT; /* 10A */ break; case 7: analog.meaning->mq = SR_MQ_GAIN; /* TODO: Scale factor */ break; case 8: analog.meaning->mq = SR_MQ_GAIN; /* Percentage */ scale /= 100.0; break; case 9: analog.meaning->mq = SR_MQ_GAIN; /* dB */ scale /= 100.0; break; default: sr_err("Unknown value type: 0x%02x.", vt); break; } /* 3: Measurement range for measured value */ range = xgittoint(devc->buf[3]); switch (vt) { case 0: /* V */ scale *= pow(10.0, range - 5); break; case 1: /* A */ scale *= pow(10.0, range - 7); break; case 2: /* Ω */ scale *= pow(10.0, range - 2); break; case 3: /* F */ scale *= pow(10.0, range - 12); break; case 4: /* °C */ scale *= pow(10.0, range - 1); break; case 5: /* Hz */ scale *= pow(10.0, range - 2); break; // No default, other value types have fixed display format. } /* 5: Sign and 1st digit */ flags = xgittoint(devc->buf[5]); value = (flags & 0x03); if (flags & 0x04) scale *= -1; /* 6-9: 2nd-4th digit */ for (pos = 6; pos < 10; pos++) value = value * 10 + xgittoint(devc->buf[pos]); value *= scale; /* 10: Display counter */ mmode = xgittoint(devc->buf[10]); switch (mmode) { case 0: /* Frequency */ analog.meaning->unit = SR_UNIT_HERTZ; break; case 1: /* V TRMS, only type 5 */ analog.meaning->unit = SR_UNIT_VOLT; analog.meaning->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS); break; case 2: /* V AC */ analog.meaning->unit = SR_UNIT_VOLT; analog.meaning->mqflags |= SR_MQFLAG_AC; if (devc->type >= 3) analog.meaning->mqflags |= SR_MQFLAG_RMS; break; case 3: /* V DC */ analog.meaning->unit = SR_UNIT_VOLT; analog.meaning->mqflags |= SR_MQFLAG_DC; break; case 4: /* Ohm */ analog.meaning->unit = SR_UNIT_OHM; break; case 5: /* Continuity */ analog.meaning->unit = SR_UNIT_BOOLEAN; analog.meaning->mq = SR_MQ_CONTINUITY; /* TODO: Continuity handling is a bit odd in libsigrok. */ break; case 6: /* Degree Celsius */ analog.meaning->unit = SR_UNIT_CELSIUS; break; case 7: /* Capacity */ analog.meaning->unit = SR_UNIT_FARAD; break; case 8: /* Current DC */ analog.meaning->unit = SR_UNIT_AMPERE; analog.meaning->mqflags |= SR_MQFLAG_DC; break; case 9: /* Current AC */ analog.meaning->unit = SR_UNIT_AMPERE; analog.meaning->mqflags |= SR_MQFLAG_AC; if (devc->type >= 3) analog.meaning->mqflags |= SR_MQFLAG_RMS; break; case 0xa: /* Current TRMS, only type 5 */ analog.meaning->unit = SR_UNIT_AMPERE; analog.meaning->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS); break; case 0xb: /* Diode */ analog.meaning->unit = SR_UNIT_VOLT; analog.meaning->mqflags |= (SR_MQFLAG_DIODE | SR_MQFLAG_DC); break; default: sr_err("Unknown mmode: 0x%02x.", mmode); break; } /* 11: Device status */ devstat = xgittoint(devc->buf[11]); switch (devstat) { case 1: /* Normal measurement */ break; case 2: /* Input loop (limit, reference values) */ break; case 3: /* TRANS/SENS */ break; case 4: /* Error */ sr_err("Device error. Fuse?"); /* TODO: Really abort? */ devc->buflen = 0; return; /* Cannot continue. */ default: sr_err("Unknown device status: 0x%02x", devstat); break; } /* 12-19: Flags and display symbols */ /* 12, 13 */ flags = (xgittoint(devc->buf[12]) << 8) | xgittoint(devc->buf[13]); /* 0x80: PRINT TODO: Stop polling when discovered? */ /* 0x40: EXTR */ if (analog.meaning->mq == SR_MQ_CONTINUITY) { if (flags & 0x20) value = 1.0; /* Beep */ else value = 0.0; } /* 0x10: AVG */ /* 0x08: Diode */ if (flags & 0x04) /* REL */ analog.meaning->mqflags |= SR_MQFLAG_RELATIVE; /* 0x02: SHIFT */ if (flags & 0x01) /* % */ analog.meaning->unit = SR_UNIT_PERCENTAGE; /* 14, 15 */ flags = (xgittoint(devc->buf[14]) << 8) | xgittoint(devc->buf[15]); if (!(flags & 0x80)) /* MAN: Manual range */ analog.meaning->mqflags |= SR_MQFLAG_AUTORANGE; if (flags & 0x40) /* LOBATT1: Low battery, measurement still within specs */ devc->lowbatt = 1; /* 0x20: PEAK */ /* 0x10: COUNT */ if (flags & 0x08) /* HOLD */ analog.meaning->mqflags |= SR_MQFLAG_HOLD; /* 0x04: LIMIT */ if (flags & 0x02) /* MAX */ analog.meaning->mqflags |= SR_MQFLAG_MAX; if (flags & 0x01) /* MIN */ analog.meaning->mqflags |= SR_MQFLAG_MIN; /* 16, 17 */ flags = (xgittoint(devc->buf[16]) << 8) | xgittoint(devc->buf[17]); /* 0xe0: undefined */ if (flags & 0x10) { /* LOBATT2: Low battery, measurement inaccurate */ devc->lowbatt = 2; sr_warn("Low battery, measurement quality degraded!"); } /* 0x08: SCALED */ /* 0x04: RATE (=lower resolution, allows higher data rate up to 10/s. */ /* 0x02: Current clamp */ if (flags & 0x01) { /* dB */ /* * TODO: The Norma has an adjustable dB reference value. If * changed from default, this is not correct. */ if (analog.meaning->unit == SR_UNIT_VOLT) analog.meaning->unit = SR_UNIT_DECIBEL_VOLT; else analog.meaning->unit = SR_UNIT_UNITLESS; } /* 18, 19 */ /* flags = (xgittoint(devc->buf[18]) << 8) | xgittoint(devc->buf[19]); */ /* 0x80: Undefined. */ /* 0x40: Remote mode, keyboard locked */ /* 0x38: Undefined. */ /* 0x04: MIN > MAX */ /* 0x02: Measured value < Min */ /* 0x01: Measured value > Max */ /* 4: Flags. Evaluating this after setting value! */ flags = xgittoint(devc->buf[4]); if (flags & 0x04) /* Invalid value */ value = NAN; else if (flags & 0x01) /* Overload */ value = INFINITY; if (flags & 0x02) { /* Duplicate value, has been sent before. */ sr_spew("Duplicate value, dismissing!"); devc->buflen = 0; return; } sr_spew("range=%d/scale=%f/value=%f", range, (double)scale, (double)value); /* Finish and send packet. */ analog.meaning->channels = sdi->channels; analog.num_samples = 1; analog.data = &value; memset(&packet, 0, sizeof(struct sr_datafeed_packet)); packet.type = SR_DF_ANALOG; packet.payload = &analog; sr_session_send(sdi, &packet); /* Finish processing. */ sr_sw_limits_update_samples_read(&devc->limits, 1); devc->buflen = 0; }
static GSList *scan(GSList *options) { struct sr_dev_inst *sdi; struct drv_context *drvc; struct dev_context *devc; struct sr_config *src; struct sr_probe *probe; struct sr_serial_dev_inst *serial; GSList *l, *devices; int len, cnt; const char *conn, *serialcomm; char *buf; char fmttype[10]; char req[10]; int auxtype; devices = NULL; drvc = di->priv; drvc->instances = NULL; conn = serialcomm = NULL; for (l = options; l; l = l->next) { src = l->data; switch (src->key) { case SR_CONF_CONN: conn = g_variant_get_string(src->data, NULL); break; case SR_CONF_SERIALCOMM: serialcomm = g_variant_get_string(src->data, NULL); break; } } if (!conn) return NULL; if (!serialcomm) serialcomm = SERIALCOMM; if (!(serial = sr_serial_dev_inst_new(conn, serialcomm))) return NULL; if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) return NULL; serial_flush(serial); if (!(buf = g_try_malloc(BUF_MAX))) { sr_err("Serial buffer malloc failed."); return NULL; } snprintf(req, sizeof(req), "%s\r\n", nmadmm_requests[NMADMM_REQ_IDN].req_str); for (cnt = 0; cnt < 7; cnt++) { if (serial_write(serial, req, strlen(req)) == -1) { sr_err("Unable to send identification request: %d %s.", errno, strerror(errno)); return NULL; } len = BUF_MAX; serial_readline(serial, &buf, &len, 1500); if (!len) continue; buf[BUF_MAX - 1] = '\0'; /* Match ID string, e.g. "1834 065 V1.06,IF V1.02" (DM950) */ if (g_regex_match_simple("^1834 [^,]*,IF V*", (char *)buf, 0, 0)) { auxtype = xgittoint(buf[7]); // TODO: Will this work with non-DM950? snprintf(fmttype, sizeof(fmttype), "DM9%d0", auxtype); sr_spew("Norma %s DMM %s detected!", fmttype, &buf[9]); if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Norma", fmttype, buf + 9))) return NULL; if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); return NULL; } devc->type = auxtype; devc->version = g_strdup(&buf[9]); devc->elapsed_msec = g_timer_new(); sdi->conn = serial; sdi->priv = devc; sdi->driver = di; if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1"))) return NULL; sdi->probes = g_slist_append(sdi->probes, probe); drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); break; } /* * The interface of the DM9x0 contains a cap that needs to * charge for up to 10s before the interface works, if not * powered externally. Therefore wait a little to improve * chances. */ if (cnt == 3) { sr_info("Waiting 5s to allow interface to settle."); g_usleep(5 * 1000 * 1000); } } g_free(buf); serial_close(serial); if (!devices) sr_serial_dev_inst_free(serial); return devices; }