/** * 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_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; memset(&analog, 0, sizeof(struct sr_datafeed_analog)); /* * 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.mq = SR_MQ_VOLTAGE; break; case 1: analog.mq = SR_MQ_CURRENT; /* 2A */ break; case 2: analog.mq = SR_MQ_RESISTANCE; break; case 3: analog.mq = SR_MQ_CAPACITANCE; break; case 4: analog.mq = SR_MQ_TEMPERATURE; break; case 5: analog.mq = SR_MQ_FREQUENCY; break; case 6: analog.mq = SR_MQ_CURRENT; /* 10A */ break; case 7: analog.mq = SR_MQ_GAIN; /* TODO: Scale factor */ break; case 8: analog.mq = SR_MQ_GAIN; /* Percentage */ scale /= 100.0; break; case 9: analog.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.unit = SR_UNIT_HERTZ; break; case 1: /* V TRMS, only type 5 */ analog.unit = SR_UNIT_VOLT; analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS); break; case 2: /* V AC */ analog.unit = SR_UNIT_VOLT; analog.mqflags |= SR_MQFLAG_AC; if (devc->type >= 3) analog.mqflags |= SR_MQFLAG_RMS; break; case 3: /* V DC */ analog.unit = SR_UNIT_VOLT; analog.mqflags |= SR_MQFLAG_DC; break; case 4: /* Ohm */ analog.unit = SR_UNIT_OHM; break; case 5: /* Continuity */ analog.unit = SR_UNIT_BOOLEAN; analog.mq = SR_MQ_CONTINUITY; /* TODO: Continuity handling is a bit odd in libsigrok. */ break; case 6: /* Degree Celsius */ analog.unit = SR_UNIT_CELSIUS; break; case 7: /* Capacity */ analog.unit = SR_UNIT_FARAD; break; case 8: /* Current DC */ analog.unit = SR_UNIT_AMPERE; analog.mqflags |= SR_MQFLAG_DC; break; case 9: /* Current AC */ analog.unit = SR_UNIT_AMPERE; analog.mqflags |= SR_MQFLAG_AC; if (devc->type >= 3) analog.mqflags |= SR_MQFLAG_RMS; break; case 0xa: /* Current TRMS, only type 5 */ analog.unit = SR_UNIT_AMPERE; analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS); break; case 0xb: /* Diode */ analog.unit = SR_UNIT_VOLT; analog.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.mq == SR_MQ_CONTINUITY) { if (flags & 0x20) value = 1.0; /* Beep */ else value = 0.0; } /* 0x10: AVG */ /* 0x08: Diode */ if (flags & 0x04) /* REL */ analog.mqflags |= SR_MQFLAG_RELATIVE; /* 0x02: SHIFT */ if (flags & 0x01) /* % */ analog.unit = SR_UNIT_PERCENTAGE; /* 14, 15 */ flags = (xgittoint(devc->buf[14]) << 8) | xgittoint(devc->buf[15]); if (!(flags & 0x80)) /* MAN: Manual range */ analog.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.mqflags |= SR_MQFLAG_HOLD; /* 0x04: LIMIT */ if (flags & 0x02) /* MAX */ analog.mqflags |= SR_MQFLAG_MAX; if (flags & 0x01) /* MIN */ analog.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.unit == SR_UNIT_VOLT) analog.unit = SR_UNIT_DECIBEL_VOLT; else analog.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.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(devc->cb_data, &packet); /* Finish processing. */ devc->num_samples++; devc->buflen = 0; }
static GSList *scan(struct sr_dev_driver *di, GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_usb_dev_inst *usb; struct sr_channel *ch; struct sr_channel_group *cg; struct sr_config *src; const struct fx2lafw_profile *prof; GSList *l, *devices, *conn_devices; gboolean has_firmware; struct libusb_device_descriptor des; libusb_device **devlist; struct libusb_device_handle *hdl; int ret, i, j; int num_logic_channels = 0, num_analog_channels = 0; const char *conn; char manufacturer[64], product[64], serial_num[64], connection_id[64]; char channel_name[16]; drvc = di->context; conn = 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; } } if (conn) conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); else conn_devices = NULL; /* Find all fx2lafw compatible devices and upload firmware to them. */ devices = NULL; libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if (conn) { usb = NULL; for (l = conn_devices; l; l = l->next) { usb = l->data; if (usb->bus == libusb_get_bus_number(devlist[i]) && usb->address == libusb_get_device_address(devlist[i])) break; } if (!l) /* This device matched none of the ones that * matched the conn specification. */ continue; } libusb_get_device_descriptor( devlist[i], &des); if (!is_plausible(&des)) continue; if ((ret = libusb_open(devlist[i], &hdl)) < 0) { sr_warn("Failed to open potential device with " "VID:PID %04x:%04x: %s.", des.idVendor, des.idProduct, libusb_error_name(ret)); continue; } if (des.iManufacturer == 0) { manufacturer[0] = '\0'; } else if ((ret = libusb_get_string_descriptor_ascii(hdl, des.iManufacturer, (unsigned char *) manufacturer, sizeof(manufacturer))) < 0) { sr_warn("Failed to get manufacturer string descriptor: %s.", libusb_error_name(ret)); continue; } if (des.iProduct == 0) { product[0] = '\0'; } else if ((ret = libusb_get_string_descriptor_ascii(hdl, des.iProduct, (unsigned char *) product, sizeof(product))) < 0) { sr_warn("Failed to get product string descriptor: %s.", libusb_error_name(ret)); continue; } if (des.iSerialNumber == 0) { serial_num[0] = '\0'; } else if ((ret = libusb_get_string_descriptor_ascii(hdl, des.iSerialNumber, (unsigned char *) serial_num, sizeof(serial_num))) < 0) { sr_warn("Failed to get serial number string descriptor: %s.", libusb_error_name(ret)); continue; } libusb_close(hdl); if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0) continue; prof = NULL; for (j = 0; supported_fx2[j].vid; j++) { if (des.idVendor == supported_fx2[j].vid && des.idProduct == supported_fx2[j].pid && (!supported_fx2[j].usb_manufacturer || !strcmp(manufacturer, supported_fx2[j].usb_manufacturer)) && (!supported_fx2[j].usb_product || !strcmp(product, supported_fx2[j].usb_product))) { prof = &supported_fx2[j]; break; } } if (!prof) continue; sdi = g_malloc0(sizeof(struct sr_dev_inst)); sdi->status = SR_ST_INITIALIZING; sdi->vendor = g_strdup(prof->vendor); sdi->model = g_strdup(prof->model); sdi->version = g_strdup(prof->model_version); sdi->serial_num = g_strdup(serial_num); sdi->connection_id = g_strdup(connection_id); /* Fill in channellist according to this device's profile. */ num_logic_channels = prof->dev_caps & DEV_CAPS_16BIT ? 16 : 8; num_analog_channels = prof->dev_caps & DEV_CAPS_AX_ANALOG ? 1 : 0; /* Logic channels, all in one channel group. */ cg = g_malloc0(sizeof(struct sr_channel_group)); cg->name = g_strdup("Logic"); for (j = 0; j < num_logic_channels; j++) { sprintf(channel_name, "D%d", j); ch = sr_channel_new(sdi, j, SR_CHANNEL_LOGIC, TRUE, channel_name); cg->channels = g_slist_append(cg->channels, ch); } sdi->channel_groups = g_slist_append(NULL, cg); for (j = 0; j < num_analog_channels; j++) { snprintf(channel_name, 16, "A%d", j); ch = sr_channel_new(sdi, j + num_logic_channels, SR_CHANNEL_ANALOG, TRUE, channel_name); /* Every analog channel gets its own channel group. */ cg = g_malloc0(sizeof(struct sr_channel_group)); cg->name = g_strdup(channel_name); cg->channels = g_slist_append(NULL, ch); sdi->channel_groups = g_slist_append(sdi->channel_groups, cg); } devc = fx2lafw_dev_new(); devc->profile = prof; sdi->priv = devc; devices = g_slist_append(devices, sdi); devc->samplerates = samplerates; devc->num_samplerates = ARRAY_SIZE(samplerates); has_firmware = usb_match_manuf_prod(devlist[i], "sigrok", "fx2lafw"); if (has_firmware) { /* Already has the firmware, so fix the new address. */ sr_dbg("Found an fx2lafw device."); sdi->status = SR_ST_INACTIVE; sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); } else { if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i], USB_CONFIGURATION, prof->firmware) == SR_OK) { /* Store when this device's FW was updated. */ devc->fw_updated = g_get_monotonic_time(); } else { sr_err("Firmware upload failed for " "device %d.%d (logical), name %s.", libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), prof->firmware); } sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), 0xff, NULL); } } libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); return std_scan_complete(di, devices); }
static int loadfile(struct sr_input *in, const char *filename) { struct sr_datafeed_header header; struct sr_datafeed_packet packet; struct sr_datafeed_logic logic; uint8_t buf[PACKET_SIZE], divcount; int i, fd, size, num_probes; uint64_t samplerate; /* TODO: Use glib functions! GIOChannel, g_fopen, etc. */ if ((fd = open(filename, O_RDONLY)) == -1) { sr_warn("la8input: %s: file open failed", __func__); return SR_ERR; } num_probes = g_slist_length(in->vdevice->probes); /* Seek to the end of the file, and read the divcount byte. */ divcount = 0x00; /* TODO: Don't hardcode! */ /* Convert the divcount value to a samplerate. */ samplerate = divcount_to_samplerate(divcount); if (samplerate == 0xffffffffffffffffULL) { close(fd); /* FIXME */ return SR_ERR; } sr_dbg("la8input: %s: samplerate is %" PRIu64, __func__, samplerate); /* Send header packet to the session bus. */ sr_dbg("la8input: %s: sending SR_DF_HEADER packet", __func__); packet.type = SR_DF_HEADER; packet.payload = &header; header.feed_version = 1; gettimeofday(&header.starttime, NULL); header.num_logic_probes = num_probes; header.num_analog_probes = 0; header.samplerate = samplerate; sr_session_bus(in->vdevice, &packet); /* TODO: Handle trigger point. */ /* Send data packets to the session bus. */ sr_dbg("la8input: %s: sending SR_DF_LOGIC data packets", __func__); packet.type = SR_DF_LOGIC; packet.payload = &logic; logic.unitsize = (num_probes + 7) / 8; logic.data = buf; /* Send 8MB of total data to the session bus in small chunks. */ for (i = 0; i < NUM_PACKETS; i++) { /* TODO: Handle errors, handle incomplete reads. */ size = read(fd, buf, PACKET_SIZE); logic.length = PACKET_SIZE; sr_session_bus(in->vdevice, &packet); } close(fd); /* FIXME */ /* Send end packet to the session bus. */ sr_dbg("la8input: %s: sending SR_DF_END", __func__); packet.type = SR_DF_END; packet.payload = NULL; sr_session_bus(in->vdevice, &packet); return SR_OK; }
static GSList *scan(const char *conn, const char *serialcomm, int dmm) { struct sr_dev_inst *sdi; struct drv_context *drvc; struct dev_context *devc; struct sr_probe *probe; struct sr_serial_dev_inst *serial; GSList *devices; int dropped, ret; size_t len; uint8_t buf[128]; if (!(serial = sr_serial_dev_inst_new(conn, serialcomm))) return NULL; if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) return NULL; sr_info("Probing serial port %s.", conn); drvc = dmms[dmm].di->priv; devices = NULL; serial_flush(serial); /* Request a packet if the DMM requires this. */ if (dmms[dmm].packet_request) { if ((ret = dmms[dmm].packet_request(serial)) < 0) { sr_err("Failed to request packet: %d.", ret); return FALSE; } } /* * There's no way to get an ID from the multimeter. It just sends data * periodically (or upon request), so the best we can do is check if * the packets match the expected format. */ /* Let's get a bit of data and see if we can find a packet. */ len = sizeof(buf); ret = serial_stream_detect(serial, buf, &len, dmms[dmm].packet_size, dmms[dmm].packet_valid, 1000, dmms[dmm].baudrate); if (ret != SR_OK) goto scan_cleanup; /* * If we dropped more than two packets worth of data, something is * wrong. We shouldn't quit however, since the dropped bytes might be * just zeroes at the beginning of the stream. Those can occur as a * combination of the nonstandard cable that ships with some devices * and the serial port or USB to serial adapter. */ dropped = len - dmms[dmm].packet_size; if (dropped > 2 * dmms[dmm].packet_size) sr_warn("Had to drop too much data."); sr_info("Found device on port %s.", conn); if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, dmms[dmm].vendor, dmms[dmm].device, ""))) goto scan_cleanup; if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { sr_err("Device context malloc failed."); goto scan_cleanup; } devc->serial = serial; sdi->priv = devc; sdi->driver = dmms[dmm].di; if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1"))) goto scan_cleanup; sdi->probes = g_slist_append(sdi->probes, probe); drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); scan_cleanup: serial_close(serial); return devices; }
SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data) { uint32_t cur_time, elapsed_time; uint64_t nrexpiration; struct sr_datafeed_packet packet, framep; struct sr_datafeed_analog_old analog; struct sr_dev_inst *sdi; struct sr_channel *ch; struct channel_priv *chp; struct dev_context *devc; GSList *chl, chonly; unsigned i; (void)fd; (void)revents; sdi = cb_data; if (!sdi) return TRUE; devc = sdi->priv; if (!devc) return TRUE; packet.type = SR_DF_ANALOG_OLD; packet.payload = &analog; memset(&analog, 0, sizeof(struct sr_datafeed_analog_old)); if (read(devc->timer_fd, &nrexpiration, sizeof(nrexpiration)) < 0) { sr_warn("Failed to read timer information"); return TRUE; } /* * We were not able to process the previous timer expiration, we are * overloaded. */ if (nrexpiration > 1) devc->samples_missed += nrexpiration - 1; /* * XXX This is a nasty workaround... * * At high sampling rates and maximum channels we are not able to * acquire samples fast enough, even though frontends still think * that samples arrive on time. This causes shifts in frontend * plots. * * To compensate for the delay we check if any clock events were * missed and - if so - don't really read the next value, but send * the same sample as fast as possible. We do it until we are back * on schedule. * * At high sampling rate this doesn't seem to visibly reduce the * accuracy. */ for (i = 0; i < nrexpiration; i++) { framep.type = SR_DF_FRAME_BEGIN; sr_session_send(cb_data, &framep); /* * Due to different units used in each channel we're sending * samples one-by-one. */ for (chl = sdi->channels; chl; chl = chl->next) { ch = chl->data; chp = ch->priv; if (!ch->enabled) continue; chonly.next = NULL; chonly.data = ch; analog.channels = &chonly; analog.num_samples = 1; analog.mq = channel_to_mq(chl->data); analog.unit = channel_to_unit(ch); if (i < 1) chp->val = read_sample(ch); analog.data = &chp->val; sr_session_send(cb_data, &packet); } framep.type = SR_DF_FRAME_END; sr_session_send(cb_data, &framep); } devc->samples_read++; if (devc->limit_samples > 0 && devc->samples_read >= devc->limit_samples) { sr_info("Requested number of samples reached."); sdi->driver->dev_acquisition_stop(sdi, cb_data); devc->last_sample_fin = g_get_monotonic_time(); return TRUE; } else if (devc->limit_msec > 0) { cur_time = g_get_monotonic_time(); elapsed_time = cur_time - devc->start_time; if (elapsed_time >= devc->limit_msec) { sr_info("Sampling time limit reached."); sdi->driver->dev_acquisition_stop(sdi, cb_data); devc->last_sample_fin = g_get_monotonic_time(); return TRUE; } } devc->last_sample_fin = g_get_monotonic_time(); return TRUE; }
static GSList *scan(struct sr_dev_driver *di, GSList *options) { GSList *usb_devices, *devices, *l; struct drv_context *drvc; struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_usb_dev_inst *usb; struct device_info dev_info; unsigned int i; int ret; (void)options; devices = NULL; drvc = di->context; drvc->instances = NULL; usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_VID_PID); if (!usb_devices) return NULL; for (l = usb_devices; l; l = l->next) { usb = l->data; if ((ret = sl2_get_device_info(*usb, &dev_info)) < 0) { sr_warn("Failed to get device information: %d.", ret); sr_usb_dev_inst_free(usb); continue; } devc = g_malloc0(sizeof(struct dev_context)); if (!(devc->xfer_in = libusb_alloc_transfer(0))) { sr_err("Transfer malloc failed."); sr_usb_dev_inst_free(usb); g_free(devc); continue; } if (!(devc->xfer_out = libusb_alloc_transfer(0))) { sr_err("Transfer malloc failed."); sr_usb_dev_inst_free(usb); libusb_free_transfer(devc->xfer_in); g_free(devc); continue; } sdi = g_malloc0(sizeof(struct sr_dev_inst)); sdi->status = SR_ST_INACTIVE; sdi->vendor = g_strdup(VENDOR_NAME); sdi->model = g_strdup(MODEL_NAME); sdi->version = g_strdup_printf("%u.%u", dev_info.fw_ver_major, dev_info.fw_ver_minor); sdi->serial_num = g_strdup_printf("%d", dev_info.serial); sdi->priv = devc; sdi->driver = di; sdi->inst_type = SR_INST_USB; sdi->conn = usb; for (i = 0; i < ARRAY_SIZE(channel_names); i++) devc->channels[i] = sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_names[i]); devc->state = STATE_IDLE; devc->next_state = STATE_IDLE; /* Set default samplerate. */ sl2_set_samplerate(sdi, DEFAULT_SAMPLERATE); /* Set default capture ratio. */ devc->capture_ratio = 0; /* Set default after trigger delay. */ devc->after_trigger_delay = 0; memset(devc->xfer_buf_in, 0, LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH); memset(devc->xfer_buf_out, 0, LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH); libusb_fill_control_setup(devc->xfer_buf_in, USB_REQUEST_TYPE_IN, USB_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, PACKET_LENGTH); libusb_fill_control_setup(devc->xfer_buf_out, USB_REQUEST_TYPE_OUT, USB_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, PACKET_LENGTH); devc->xfer_data_in = devc->xfer_buf_in + LIBUSB_CONTROL_SETUP_SIZE; devc->xfer_data_out = devc->xfer_buf_out + LIBUSB_CONTROL_SETUP_SIZE; drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); } g_slist_free(usb_devices); return devices; }
static GSList *scan(struct sr_dev_driver *di, GSList *options) { struct dmm_info *dmm; struct sr_config *src; GSList *l, *devices; const char *conn, *serialcomm; struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_serial_dev_inst *serial; int dropped, ret; size_t len; uint8_t buf[128]; dmm = (struct dmm_info *)di; 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 = dmm->conn; serial = sr_serial_dev_inst_new(conn, serialcomm); if (serial_open(serial, SERIAL_RDWR) != SR_OK) return NULL; sr_info("Probing serial port %s.", conn); devices = NULL; serial_flush(serial); /* Request a packet if the DMM requires this. */ if (dmm->packet_request) { if ((ret = dmm->packet_request(serial)) < 0) { sr_err("Failed to request packet: %d.", ret); return FALSE; } } /* * There's no way to get an ID from the multimeter. It just sends data * periodically (or upon request), so the best we can do is check if * the packets match the expected format. */ /* Let's get a bit of data and see if we can find a packet. */ len = sizeof(buf); ret = serial_stream_detect(serial, buf, &len, dmm->packet_size, dmm->packet_valid, 3000, dmm->baudrate); if (ret != SR_OK) goto scan_cleanup; /* * If we dropped more than two packets worth of data, something is * wrong. We shouldn't quit however, since the dropped bytes might be * just zeroes at the beginning of the stream. Those can occur as a * combination of the nonstandard cable that ships with some devices * and the serial port or USB to serial adapter. */ dropped = len - dmm->packet_size; if (dropped > 2 * dmm->packet_size) sr_warn("Had to drop too much data."); sr_info("Found device on port %s.", conn); sdi = g_malloc0(sizeof(struct sr_dev_inst)); sdi->status = SR_ST_INACTIVE; sdi->vendor = g_strdup(dmm->vendor); sdi->model = g_strdup(dmm->device); devc = g_malloc0(sizeof(struct dev_context)); sr_sw_limits_init(&devc->limits); sdi->inst_type = SR_INST_SERIAL; sdi->conn = serial; sdi->priv = devc; sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P1"); devices = g_slist_append(devices, sdi); scan_cleanup: serial_close(serial); return std_scan_complete(di, devices); }
static GSList *scan(struct sr_dev_driver *di, GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_usb_dev_inst *usb; struct sr_config *src; GSList *l, *devices, *conn_devices; struct libusb_device_descriptor des; libusb_device **devlist; int ret; unsigned int i, j; const char *conn; char connection_id[64]; drvc = di->priv; conn = 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; } } if (conn) conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); else conn_devices = NULL; /* Find all Logic16 devices and upload firmware to them. */ devices = NULL; libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if (conn) { usb = NULL; for (l = conn_devices; l; l = l->next) { usb = l->data; if (usb->bus == libusb_get_bus_number(devlist[i]) && usb->address == libusb_get_device_address(devlist[i])) break; } if (!l) /* This device matched none of the ones that * matched the conn specification. */ continue; } if ((ret = libusb_get_device_descriptor(devlist[i], &des)) != 0) { sr_warn("Failed to get device descriptor: %s.", libusb_error_name(ret)); continue; } usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)); if (des.idVendor != LOGIC16_VID || des.idProduct != LOGIC16_PID) continue; sdi = g_malloc0(sizeof(struct sr_dev_inst)); sdi->status = SR_ST_INITIALIZING; sdi->vendor = g_strdup("Saleae"); sdi->model = g_strdup("Logic16"); sdi->driver = di; sdi->connection_id = g_strdup(connection_id); for (j = 0; j < ARRAY_SIZE(channel_names); j++) sr_channel_new(sdi, j, SR_CHANNEL_LOGIC, TRUE, channel_names[j]); devc = g_malloc0(sizeof(struct dev_context)); devc->selected_voltage_range = VOLTAGE_RANGE_18_33_V; sdi->priv = devc; drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); if (check_conf_profile(devlist[i])) { /* Already has the firmware, so fix the new address. */ sr_dbg("Found a Logic16 device."); sdi->status = SR_ST_INACTIVE; sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new( libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); } else { if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION, FX2_FIRMWARE) == SR_OK) /* Store when this device's FW was updated. */ devc->fw_updated = g_get_monotonic_time(); else sr_err("Firmware upload failed."); sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new( libusb_get_bus_number(devlist[i]), 0xff, NULL); } } libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); return devices; }
/* Parse the data section of VCD */ static void parse_contents(FILE *file, const struct sr_dev_inst *sdi, struct context *ctx) { GString *token = g_string_sized_new(32); uint64_t prev_timestamp = 0; uint64_t prev_values = 0; /* Read one space-delimited token at a time. */ while (read_until(file, NULL, 'N') && read_until(file, token, 'W')) { if (token->str[0] == '#' && g_ascii_isdigit(token->str[1])) { /* Numeric value beginning with # is a new timestamp value */ uint64_t timestamp; timestamp = strtoull(token->str + 1, NULL, 10); if (ctx->downsample > 1) timestamp /= ctx->downsample; /* Skip < 0 => skip until first timestamp. * Skip = 0 => don't skip * Skip > 0 => skip until timestamp >= skip. */ if (ctx->skip < 0) { ctx->skip = timestamp; prev_timestamp = timestamp; } else if (ctx->skip > 0 && timestamp < (uint64_t)ctx->skip) { prev_timestamp = ctx->skip; } else if (timestamp == prev_timestamp) { /* Ignore repeated timestamps (e.g. sigrok outputs these) */ } else { if (ctx->compress != 0 && timestamp - prev_timestamp > ctx->compress) { /* Compress long idle periods */ prev_timestamp = timestamp - ctx->compress; } sr_dbg("New timestamp: %" PRIu64, timestamp); /* Generate samples from prev_timestamp up to timestamp - 1. */ send_samples(sdi, prev_values, timestamp - prev_timestamp); prev_timestamp = timestamp; } } else if (token->str[0] == '$' && token->len > 1) { /* This is probably a $dumpvars, $comment or similar. * $dump* contain useful data, but other tags will be skipped until $end. */ if (g_strcmp0(token->str, "$dumpvars") == 0 || g_strcmp0(token->str, "$dumpon") == 0 || g_strcmp0(token->str, "$dumpoff") == 0 || g_strcmp0(token->str, "$end") == 0) { /* Ignore, parse contents as normally. */ } else { /* Skip until $end */ read_until(file, NULL, '$'); } } else if (strchr("bBrR", token->str[0]) != NULL) { /* A vector value. Skip it and also the following identifier. */ read_until(file, NULL, 'N'); read_until(file, NULL, 'W'); } else if (strchr("01xXzZ", token->str[0]) != NULL) { /* A new 1-bit sample value */ int i, bit; GSList *l; struct probe *probe; bit = (token->str[0] == '1'); g_string_erase(token, 0, 1); if (token->len == 0) { /* There was a space between value and identifier. * Read in the rest. */ read_until(file, NULL, 'N'); read_until(file, token, 'W'); } for (i = 0, l = ctx->probes; i < ctx->probecount && l; i++, l = l->next) { probe = l->data; if (g_strcmp0(token->str, probe->identifier) == 0) { sr_dbg("Probe %d new value %d.", i, bit); /* Found our probe */ if (bit) prev_values |= (1 << i); else prev_values &= ~(1 << i); break; } } if (i == ctx->probecount) { sr_dbg("Did not find probe for identifier '%s'.", token->str); } } else { sr_warn("Skipping unknown token '%s'.", token->str); } g_string_truncate(token, 0); } g_string_free(token, TRUE); }
/* Parse VCD header to get values for context structure. * The context structure should be zeroed before calling this. */ static gboolean parse_header(FILE *file, struct context *ctx) { uint64_t p, q; gchar *name = NULL, *contents = NULL; gboolean status = FALSE; struct probe *probe; while (parse_section(file, &name, &contents)) { sr_dbg("Section '%s', contents '%s'.", name, contents); if (g_strcmp0(name, "enddefinitions") == 0) { status = TRUE; break; } else if (g_strcmp0(name, "timescale") == 0) { /* The standard allows for values 1, 10 or 100 * and units s, ms, us, ns, ps and fs. */ if (sr_parse_period(contents, &p, &q) == SR_OK) { ctx->samplerate = q / p; if (q % p != 0) { /* Does not happen unless time value is non-standard */ sr_warn("Inexact rounding of samplerate, %" PRIu64 " / %" PRIu64 " to %" PRIu64 " Hz.", q, p, ctx->samplerate); } sr_dbg("Samplerate: %" PRIu64, ctx->samplerate); } else { sr_err("Parsing timescale failed."); } } else if (g_strcmp0(name, "var") == 0) { /* Format: $var type size identifier reference $end */ gchar **parts = g_strsplit_set(contents, " \r\n\t", 0); remove_empty_parts(parts); if (g_strv_length(parts) != 4) { sr_warn("$var section should have 4 items"); } else if (g_strcmp0(parts[0], "reg") != 0 && g_strcmp0(parts[0], "wire") != 0) { sr_info("Unsupported signal type: '%s'", parts[0]); } else if (strtol(parts[1], NULL, 10) != 1) { sr_info("Unsupported signal size: '%s'", parts[1]); } else if (ctx->probecount >= ctx->maxprobes) { sr_warn("Skipping '%s' because only %d probes requested.", parts[3], ctx->maxprobes); } else { sr_info("Probe %d is '%s' identified by '%s'.", ctx->probecount, parts[3], parts[2]); probe = g_malloc(sizeof(struct probe)); probe->identifier = g_strdup(parts[2]); probe->name = g_strdup(parts[3]); ctx->probes = g_slist_append(ctx->probes, probe); ctx->probecount++; } g_strfreev(parts); } g_free(name); name = NULL; g_free(contents); contents = NULL; } g_free(name); g_free(contents); return status; }
static GSList *scan(GSList *options) { struct drv_context *drvc; struct dev_context *devc; struct sr_dev_inst *sdi; struct sr_usb_dev_inst *usb; struct sr_channel *ch; struct sr_config *src; const struct fx2lafw_profile *prof; GSList *l, *devices, *conn_devices; struct libusb_device_descriptor des; libusb_device **devlist; struct libusb_device_handle *hdl; int devcnt, num_logic_channels, ret, i, j; const char *conn; char manufacturer[64], product[64]; drvc = di->priv; conn = 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; } } if (conn) conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); else conn_devices = NULL; /* Find all fx2lafw compatible devices and upload firmware to them. */ devices = NULL; libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (i = 0; devlist[i]; i++) { if (conn) { usb = NULL; for (l = conn_devices; l; l = l->next) { usb = l->data; if (usb->bus == libusb_get_bus_number(devlist[i]) && usb->address == libusb_get_device_address(devlist[i])) break; } if (!l) /* This device matched none of the ones that * matched the conn specification. */ continue; } if ((ret = libusb_get_device_descriptor( devlist[i], &des)) != 0) { sr_warn("Failed to get device descriptor: %s.", libusb_error_name(ret)); continue; } if ((ret = libusb_open(devlist[i], &hdl)) < 0) continue; if (des.iManufacturer == 0) { manufacturer[0] = '\0'; } else if ((ret = libusb_get_string_descriptor_ascii(hdl, des.iManufacturer, (unsigned char *) manufacturer, sizeof(manufacturer))) < 0) { sr_warn("Failed to get manufacturer string descriptor: %s.", libusb_error_name(ret)); continue; } if (des.iProduct == 0) { product[0] = '\0'; } else if ((ret = libusb_get_string_descriptor_ascii(hdl, des.iProduct, (unsigned char *) product, sizeof(product))) < 0) { sr_warn("Failed to get product string descriptor: %s.", libusb_error_name(ret)); continue; } libusb_close(hdl); prof = NULL; for (j = 0; supported_fx2[j].vid; j++) { if (des.idVendor == supported_fx2[j].vid && des.idProduct == supported_fx2[j].pid && (!supported_fx2[j].usb_manufacturer || !strcmp(manufacturer, supported_fx2[j].usb_manufacturer)) && (!supported_fx2[j].usb_manufacturer || !strcmp(product, supported_fx2[j].usb_product))) { prof = &supported_fx2[j]; break; } } /* Skip if the device was not found. */ if (!prof) continue; devcnt = g_slist_length(drvc->instances); sdi = sr_dev_inst_new(devcnt, SR_ST_INITIALIZING, prof->vendor, prof->model, prof->model_version); if (!sdi) return NULL; sdi->driver = di; /* Fill in channellist according to this device's profile. */ num_logic_channels = prof->dev_caps & DEV_CAPS_16BIT ? 16 : 8; for (j = 0; j < num_logic_channels; j++) { if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE, channel_names[j]))) return NULL; sdi->channels = g_slist_append(sdi->channels, ch); } devc = fx2lafw_dev_new(); devc->profile = prof; sdi->priv = devc; drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); if (fx2lafw_check_conf_profile(devlist[i])) { /* Already has the firmware, so fix the new address. */ sr_dbg("Found an fx2lafw device."); sdi->status = SR_ST_INACTIVE; sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); } else { if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION, prof->firmware) == SR_OK) /* Store when this device's FW was updated. */ devc->fw_updated = g_get_monotonic_time(); else sr_err("Firmware upload failed for " "device %d.", devcnt); sdi->inst_type = SR_INST_USB; sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]), 0xff, NULL); } } libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); return devices; }
/** * Attempts to query sample data from the oscilloscope in order to send it * to the session bus for further processing. * * @param fd The file descriptor used as the event source. * @param revents The received events. * @param cb_data Callback data, in this case our device instance. * * @return TRUE in case of success or a recoverable error, * FALSE when a fatal error was encountered. */ SR_PRIV int dlm_data_receive(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; struct scope_state *model_state; struct dev_context *devc; struct sr_channel *ch; struct sr_datafeed_packet packet; int chunk_len, num_bytes; static GArray *data = NULL; (void)fd; (void)revents; if (!(sdi = cb_data)) return FALSE; if (!(devc = sdi->priv)) return FALSE; if (!(model_state = (struct scope_state*)devc->model_state)) return FALSE; /* Are we waiting for a response from the device? */ if (!devc->data_pending) return TRUE; /* Check if a new query response is coming our way. */ if (!data) { if (sr_scpi_read_begin(sdi->conn) == SR_OK) /* The 16 here accounts for the header and EOL. */ data = g_array_sized_new(FALSE, FALSE, sizeof(uint8_t), 16 + model_state->samples_per_frame); else return TRUE; } /* Store incoming data. */ chunk_len = sr_scpi_read_data(sdi->conn, devc->receive_buffer, RECEIVE_BUFFER_SIZE); if (chunk_len < 0) { sr_err("Error while reading data: %d", chunk_len); goto fail; } g_array_append_vals(data, devc->receive_buffer, chunk_len); /* Read the entire query response before processing. */ if (!sr_scpi_read_complete(sdi->conn)) return TRUE; /* We finished reading and are no longer waiting for data. */ devc->data_pending = FALSE; /* Signal the beginning of a new frame if this is the first channel. */ if (devc->current_channel == devc->enabled_channels) { packet.type = SR_DF_FRAME_BEGIN; sr_session_send(sdi, &packet); } if (dlm_block_data_header_process(data, &num_bytes) != SR_OK) { sr_err("Encountered malformed block data header."); goto fail; } if (num_bytes == 0) { sr_warn("Zero-length waveform data packet received. " \ "Live mode not supported yet, stopping " \ "acquisition and retrying."); /* Don't care about return value here. */ dlm_acquisition_stop(sdi->conn); g_array_free(data, TRUE); dlm_channel_data_request(sdi); return TRUE; } ch = devc->current_channel->data; switch (ch->type) { case SR_CHANNEL_ANALOG: if (dlm_analog_samples_send(data, &model_state->analog_states[ch->index], sdi) != SR_OK) goto fail; break; case SR_CHANNEL_LOGIC: if (dlm_digital_samples_send(data, sdi) != SR_OK) goto fail; break; default: sr_err("Invalid channel type encountered."); break; } g_array_free(data, TRUE); data = NULL; /* * Signal the end of this frame if this was the last enabled channel * and set the next enabled channel. Then, request its data. */ if (!devc->current_channel->next) { packet.type = SR_DF_FRAME_END; sr_session_send(sdi, &packet); devc->current_channel = devc->enabled_channels; /* * As of now we only support importing the current acquisition * data so we're going to stop at this point. */ sdi->driver->dev_acquisition_stop(sdi, cb_data); return TRUE; } else devc->current_channel = devc->current_channel->next; if (dlm_channel_data_request(sdi) != SR_OK) { sr_err("Failed to request acquisition data."); goto fail; } return TRUE; fail: if (data) { g_array_free(data, TRUE); data = NULL; } return FALSE; }