From: Bert Vermeulen Date: Sun, 22 Apr 2012 23:05:58 +0000 (+0200) Subject: sr: initial support for Hantek 2xxx/5200 USB oscilloscopes X-Git-Tag: dsupstream~952 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=3b533202c8b32fbe785906e9930959aae077aeff;p=libsigrok.git sr: initial support for Hantek 2xxx/5200 USB oscilloscopes --- diff --git a/configure.ac b/configure.ac index 1504780e..9f6422e1 100644 --- a/configure.ac +++ b/configure.ac @@ -152,6 +152,16 @@ if test "x$LA_ZEROPLUS_LOGIC_CUBE" = "xyes"; then AC_DEFINE(HAVE_LA_ZEROPLUS_LOGIC_CUBE, 1, [ZEROPLUS Logic Cube support]) fi +AC_ARG_ENABLE(hantek-dso, + AC_HELP_STRING([--enable-hantek-dso], + [enable Hantek DSO support [default=yes]]), + [HW_HANTEK_DSO="$enableval"], + [HW_HANTEK_DSO=yes]) +AM_CONDITIONAL(HW_HANTEK_DSO, test x$HW_HANTEK_DSO = xyes) +if test "x$HW_HANTEK_DSO" = "xyes"; then + AC_DEFINE(HAVE_HW_HANTEK_DSO, 1, [Hantek DSO support]) +fi + # Checks for libraries. # This variable collects the pkg-config names of all detected libs. @@ -265,6 +275,7 @@ AC_CONFIG_FILES([Makefile hardware/link-mso19/Makefile hardware/openbench-logic-sniffer/Makefile hardware/zeroplus-logic-cube/Makefile + hardware/hantek-dso/Makefile input/Makefile output/Makefile output/text/Makefile @@ -305,5 +316,6 @@ echo " - fx2lafw (for FX2 LAs)........... $LA_FX2LAFW" echo " - Link MSO-19..................... $LA_LINK_MSO19" echo " - Openbench Logic Sniffer......... $LA_OLS" echo " - ZEROPLUS Logic Cube............. $LA_ZEROPLUS_LOGIC_CUBE" +echo " - Hantek DSO...................... $HW_HANTEK_DSO" echo diff --git a/contrib/z60_libsigrok.rules b/contrib/z60_libsigrok.rules index ef8ce6ec..ea7ad294 100644 --- a/contrib/z60_libsigrok.rules +++ b/contrib/z60_libsigrok.rules @@ -199,4 +199,13 @@ ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700d", MODE="664", GROUP="plugdev" ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700e", MODE="664", GROUP="plugdev" ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7016", MODE="664", GROUP="plugdev" +# Hantek DSO-2xxx series USB oscilloscope +# http://www.hantek.com/english/produce.asp?classid=29 +# The DSO-2090 boots up with 04b4:2090 (VID belongs to Cypress), and +# after the firmware upload to the FX2 renumerates with 04b5:2090 (VID +# belongs to somebody else entirely). +ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2090", MODE="664", GROUP="plugdev" +ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2090", MODE="664", GROUP="plugdev" + + LABEL="libsigrok_rules_end" diff --git a/hardware/Makefile.am b/hardware/Makefile.am index 9bc5fc87..4b3d9965 100644 --- a/hardware/Makefile.am +++ b/hardware/Makefile.am @@ -26,7 +26,8 @@ SUBDIRS = \ fx2lafw \ link-mso19 \ openbench-logic-sniffer \ - zeroplus-logic-cube + zeroplus-logic-cube \ + hantek-dso noinst_LTLIBRARIES = libsigrokhardware.la @@ -67,3 +68,7 @@ if LA_ZEROPLUS_LOGIC_CUBE libsigrokhardware_la_LIBADD += zeroplus-logic-cube/libsigrokhwzeroplus.la endif +if HW_HANTEK_DSO +libsigrokhardware_la_LIBADD += hantek-dso/libsigrokhw_hantek_dso.la +endif + diff --git a/hardware/hantek-dso/Makefile.am b/hardware/hantek-dso/Makefile.am new file mode 100644 index 00000000..4bba3434 --- /dev/null +++ b/hardware/hantek-dso/Makefile.am @@ -0,0 +1,35 @@ +## +## This file is part of the sigrok project. +## +## Copyright (C) 2012 Bert Vermeulen +## +## 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 . +## + +if HW_HANTEK_DSO + +AM_CPPFLAGS = -DFIRMWARE_DIR='"$(FIRMWARE_DIR)"' + +# Local lib, this is NOT meant to be installed! +noinst_LTLIBRARIES = libsigrokhw_hantek_dso.la + +libsigrokhw_hantek_dso_la_SOURCES = \ + api.c \ + dso.c \ + dso.h + +libsigrokhw_hantek_dso_la_CFLAGS = \ + -I$(top_srcdir) + +endif diff --git a/hardware/hantek-dso/api.c b/hardware/hantek-dso/api.c new file mode 100644 index 00000000..fbfa9cbd --- /dev/null +++ b/hardware/hantek-dso/api.c @@ -0,0 +1,573 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2012 Bert Vermeulen + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sigrok.h" +#include "sigrok-internal.h" +#include "config.h" +#include "dso.h" + + +/* Max time in ms before we want to check on events */ +#define TICK 1 + +static int capabilities[] = { + SR_HWCAP_OSCILLOSCOPE, + SR_HWCAP_CONTINUOUS, + 0, +}; + +static const char *probe_names[] = { + "CH1", + "CH2", + NULL, +}; + +static struct dso_profile dev_profiles[] = { + { 0x04b4, 0x2090, + 0x04b5, 0x2090, + "Hantek", "DSO-2090", + NULL, 2, + FIRMWARE_DIR "/hantek-dso-2090.fw" }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + + +SR_PRIV libusb_context *usb_context = NULL; +SR_PRIV GSList *dev_insts = NULL; + + +static struct sr_dev_inst *dso_dev_new(int index, struct dso_profile *prof) +{ + struct sr_dev_inst *sdi; + struct context *ctx; + + sdi = sr_dev_inst_new(index, SR_ST_INITIALIZING, + prof->vendor, prof->model, prof->model_version); + if (!sdi) + return NULL; + + if (!(ctx = g_try_malloc0(sizeof(struct context)))) { + sr_err("hantek-dso: ctx malloc failed"); + return NULL; + } + ctx->profile = prof; + ctx->dev_state = IDLE; + ctx->timebase = DEFAULT_TIMEBASE; + ctx->ch1_enabled = TRUE; + ctx->ch2_enabled = TRUE; + ctx->voltage_ch1 = DEFAULT_VOLTAGE; + ctx->voltage_ch2 = DEFAULT_VOLTAGE; + ctx->coupling_ch1 = DEFAULT_COUPLING; + ctx->coupling_ch2 = DEFAULT_COUPLING; + ctx->voffset_ch1 = DEFAULT_VERT_OFFSET; + ctx->voffset_ch2 = DEFAULT_VERT_OFFSET; + ctx->voffset_trigger = DEFAULT_VERT_TRIGGERPOS; + ctx->selected_channel = DEFAULT_SELECTED_CHANNEL; + ctx->framesize = DEFAULT_FRAMESIZE; + ctx->triggerslope = SLOPE_POSITIVE; + ctx->triggersource = DEFAULT_TRIGGER_SOURCE; + ctx->triggerposition = DEFAULT_HORIZ_TRIGGERPOS; + sdi->priv = ctx; + dev_insts = g_slist_append(dev_insts, sdi); + + return sdi; +} + +static int configure_probes(struct context *ctx, GSList *probes) +{ + struct sr_probe *probe; + GSList *l; + + for (l = probes; l; l = l->next) { + probe = (struct sr_probe *)l->data; + if (probe->index == 0) + ctx->ch1_enabled = probe->enabled; + else if (probe->index == 1) + ctx->ch2_enabled = probe->enabled; + } + + return SR_OK; +} + +static int hw_init(const char *devinfo) +{ + struct sr_dev_inst *sdi; + struct libusb_device_descriptor des; + struct dso_profile *prof; + struct context *ctx; + libusb_device **devlist; + int err, devcnt, i, j; + + /* Avoid compiler warnings. */ + (void)devinfo; + + if (libusb_init(&usb_context) != 0) { + sr_err("hantek-dso: Failed to initialize USB."); + return 0; + } + + /* Find all Hantek DSO devices and upload firmware to all of them. */ + devcnt = 0; + libusb_get_device_list(usb_context, &devlist); + for (i = 0; devlist[i]; i++) { + if ((err = libusb_get_device_descriptor(devlist[i], &des))) { + sr_err("hantek-dso: failed to get device descriptor: %d", err); + continue; + } + + prof = NULL; + for (j = 0; dev_profiles[j].orig_vid; j++) { + if (des.idVendor == dev_profiles[j].orig_vid + && des.idProduct == dev_profiles[j].orig_pid) { + /* Device matches the pre-firmware profile. */ + prof = &dev_profiles[j]; + sr_dbg("hantek-dso: Found a %s %s.", prof->vendor, prof->model); + sdi = dso_dev_new(devcnt, prof); + ctx = sdi->priv; + if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION, + prof->firmware) == SR_OK) + /* Remember when the firmware on this device was updated */ + g_get_current_time(&ctx->fw_updated); + else + sr_err("hantek-dso: firmware upload failed for " + "device %d", devcnt); + /* Dummy USB address of 0xff will get overwritten later. */ + ctx->usb = sr_usb_dev_inst_new( + libusb_get_bus_number(devlist[i]), 0xff, NULL); + devcnt++; + break; + } else if (des.idVendor == dev_profiles[j].fw_vid + && des.idProduct == dev_profiles[j].fw_pid) { + /* Device matches the post-firmware profile. */ + prof = &dev_profiles[j]; + sr_dbg("hantek-dso: Found a %s %s.", prof->vendor, prof->model); + sdi = dso_dev_new(devcnt, prof); + sdi->status = SR_ST_INACTIVE; + ctx = sdi->priv; + ctx->usb = sr_usb_dev_inst_new( + libusb_get_bus_number(devlist[i]), + libusb_get_device_address(devlist[i]), NULL); + devcnt++; + break; + } + } + if (!prof) + /* not a supported VID/PID */ + continue; + } + libusb_free_device_list(devlist, 1); + + return devcnt; +} + +static int hw_dev_open(int dev_index) +{ + GTimeVal cur_time; + struct sr_dev_inst *sdi; + struct context *ctx; + int timediff, err; + + if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) + return SR_ERR_ARG; + ctx = sdi->priv; + + /* + * if the firmware was recently uploaded, wait up to MAX_RENUM_DELAY ms + * for the FX2 to renumerate + */ + err = 0; + if (GTV_TO_MSEC(ctx->fw_updated) > 0) { + sr_info("hantek-dso: waiting for device to reset"); + /* takes at least 300ms for the FX2 to be gone from the USB bus */ + g_usleep(300 * 1000); + timediff = 0; + while (timediff < MAX_RENUM_DELAY) { + if ((err = dso_open(dev_index)) == SR_OK) + break; + g_usleep(100 * 1000); + g_get_current_time(&cur_time); + timediff = GTV_TO_MSEC(cur_time) - GTV_TO_MSEC(ctx->fw_updated); + } + sr_info("hantek-dso: device came back after %d ms", timediff); + } else { + err = dso_open(dev_index); + } + + if (err != SR_OK) { + sr_err("hantek-dso: unable to open device"); + return SR_ERR; + } + + err = libusb_claim_interface(ctx->usb->devhdl, USB_INTERFACE); + if (err != 0) { + sr_err("hantek-dso: Unable to claim interface: %d", err); + return SR_ERR; + } + + return SR_OK; +} + +static int hw_dev_close(int dev_index) +{ + struct sr_dev_inst *sdi; + + if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) + return SR_ERR_ARG; + + dso_close(sdi); + + return SR_OK; +} + +static int hw_cleanup(void) +{ + GSList *l; + struct sr_dev_inst *sdi; + struct context *ctx; + + /* Properly close and free all devices. */ + for (l = dev_insts; l; l = l->next) { + if (!(sdi = l->data)) { + /* Log error, but continue cleaning up the rest. */ + sr_err("hantek-dso: %s: sdi was NULL, continuing", __func__); + continue; + } + if (!(ctx = sdi->priv)) { + /* Log error, but continue cleaning up the rest. */ + sr_err("hantek-dso: %s: sdi->priv was NULL, continuing", __func__); + continue; + } + dso_close(sdi); + sr_usb_dev_inst_free(ctx->usb); + sr_dev_inst_free(sdi); + } + + g_slist_free(dev_insts); + dev_insts = NULL; + + if (usb_context) + libusb_exit(usb_context); + usb_context = NULL; + + return SR_OK; +} + +static void *hw_get_device_info(int dev_index, int dev_info_id) +{ + struct sr_dev_inst *sdi; + struct context *ctx; + void *info; + uint64_t tmp; + + if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) + return NULL; + ctx = sdi->priv; + + info = NULL; + switch (dev_info_id) { + case SR_DI_INST: + info = sdi; + break; + case SR_DI_NUM_PROBES: + info = GINT_TO_POINTER(ctx->profile->num_probes); + break; + case SR_DI_PROBE_NAMES: + info = probe_names; + break; + /* TODO remove this */ + case SR_DI_CUR_SAMPLERATE: + info = &tmp; + break; + } + + return info; +} + +static int hw_get_status(int device_index) +{ + struct sr_dev_inst *sdi; + + if (!(sdi = sr_dev_inst_get(dev_insts, device_index))) + return SR_ST_NOT_FOUND; + + return sdi->status; +} + +static int *hwcap_get_all(void) +{ + + return capabilities; +} + +static int hw_dev_config_set(int dev_index, int hwcap, void *value) +{ + struct sr_dev_inst *sdi; + struct context *ctx; + int tmp, ret; + + if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) + return SR_ERR; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR; + + ctx = sdi->priv; + switch (hwcap) { + case SR_HWCAP_PROBECONFIG: + ret = configure_probes(ctx, (GSList *) value); + break; + case SR_HWCAP_TRIGGERSLOPE: + tmp = *(int *)value; + if (tmp != SLOPE_NEGATIVE && tmp != SLOPE_POSITIVE) + ret = SR_ERR_ARG; + ctx->triggerslope = tmp; + default: + ret = SR_ERR_ARG; + } + + return ret; +} + +/* Called by libusb (as triggered by handle_event()) when a transfer comes in. + * Only channel data comes in asynchronously, and all transfers for this are + * queued up beforehand, so this just needs so chuck the incoming data onto + * the libsigrok session bus. + */ +static void receive_transfer(struct libusb_transfer *transfer) +{ + struct sr_datafeed_packet packet; + struct sr_datafeed_analog analog; + struct context *ctx; + float ch1, ch2; + int i; + + ctx = transfer->user_data; + sr_dbg("hantek-dso: receive_transfer(): status %d received %d bytes", + transfer->status, transfer->actual_length); + + if (transfer->actual_length == 0) + /* Nothing to send to the bus. */ + return; + + ctx->current_transfer += transfer->actual_length; + sr_dbg("hantek-dso: got %d of %d in frame", ctx->current_transfer, ctx->framesize * 2); + if (ctx->current_transfer >= ctx->framesize * 2) { + ctx->current_transfer = 0; + ctx->dev_state = NEW_CAPTURE; + } + + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + analog.num_samples = transfer->actual_length / 2; + analog.data = g_try_malloc(analog.num_samples * sizeof(float) * ctx->profile->num_probes); + for (i = 0; i < analog.num_samples; i++) { + /* Hardcoded for two channels, since the order/encoding is specific. */ + /* TODO: support for 5xxx series 9-bit samples */ + ch2 = (*(transfer->buffer + i * 2) / 255.0); + ch1 = (*(transfer->buffer + i * 2 + 1) / 255.0); + analog.data[i * ctx->profile->num_probes] = ch1; + analog.data[i * ctx->profile->num_probes + 1] = ch2; + } + g_free(transfer->buffer); + libusb_free_transfer(transfer); + + sr_session_send(ctx->cb_data, &packet); + +} + +static int handle_event(int fd, int revents, void *cb_data) +{ + struct timeval tv; + struct context *ctx; + int capturestate; + + /* Avoid compiler warnings. */ + (void)fd; + (void)revents; + + /* Always handle pending libusb events. */ + tv.tv_sec = tv.tv_usec = 0; + libusb_handle_events_timeout(usb_context, &tv); + + ctx = cb_data; + /* TODO: ugh */ + if (ctx->dev_state == NEW_CAPTURE) { + if (dso_capture_start(ctx) != SR_OK) + return TRUE; + if (dso_enable_trigger(ctx) != SR_OK) + return TRUE; + if (dso_force_trigger(ctx) != SR_OK) + return TRUE; + sr_dbg("hantek-dso: successfully requested next chunk"); + ctx->dev_state = CAPTURE; + return TRUE; + } + if (ctx->dev_state != CAPTURE) + return TRUE; + + if ((capturestate = dso_get_capturestate(ctx)) == CAPTURE_UNKNOWN) { + /* Generated by the function, not the hardware. */ + return TRUE; + } + + sr_dbg("hantek-dso: capturestate %d", capturestate); + switch (capturestate) { + case CAPTURE_EMPTY: + if (++ctx->capture_empty_count >= MAX_CAPTURE_EMPTY) { + ctx->capture_empty_count = 0; + if (dso_capture_start(ctx) != SR_OK) + break; + if (dso_enable_trigger(ctx) != SR_OK) + break; + if (dso_force_trigger(ctx) != SR_OK) + break; + sr_dbg("hantek-dso: successfully requested next chunk"); + } + break; + case CAPTURE_FILLING: + /* no data yet */ + break; + case CAPTURE_READY_8BIT: + /* Tell the scope to send us the first frame. */ + if (dso_get_channeldata(ctx, receive_transfer) != SR_OK) + break; +// /* Current frame is on the way, make sure the scope +// * sends us the next one. */ +// if (dso_capture_start(ctx) != SR_OK) +// break; +// if (dso_enable_trigger(ctx) != SR_OK) +// break; +// if (dso_force_trigger(ctx) != SR_OK) +// break; + ctx->dev_state = FETCH_DATA; + break; + case CAPTURE_READY_9BIT: + /* TODO */ + sr_err("not yet supported"); + break; + case CAPTURE_TIMEOUT: + /* Doesn't matter, we'll try again next time. */ + break; + default: + sr_dbg("unknown capture state"); + } + + return TRUE; +} + +static int hw_start_acquisition(int device_index, void *cb_data) +{ + const struct libusb_pollfd **lupfd; + struct sr_datafeed_packet packet; + struct sr_datafeed_header header; + struct sr_datafeed_meta_analog meta; + struct sr_dev_inst *sdi; + struct context *ctx; + int i; + + if (!(sdi = sr_dev_inst_get(dev_insts, device_index))) + return SR_ERR; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR; + + ctx = sdi->priv; + ctx->cb_data = cb_data; + + if (dso_init(ctx) != SR_OK) + return SR_ERR; + + if (dso_capture_start(ctx) != SR_OK) + return SR_ERR; + + ctx->dev_state = CAPTURE; + lupfd = libusb_get_pollfds(usb_context); + for (i = 0; lupfd[i]; i++) + sr_source_add(lupfd[i]->fd, lupfd[i]->events, TICK, handle_event, + ctx); + free(lupfd); + + /* Send header packet to the session bus. */ + packet.type = SR_DF_HEADER; + packet.payload = (unsigned char *)&header; + header.feed_version = 1; + gettimeofday(&header.starttime, NULL); + sr_session_send(cb_data, &packet); + + /* Send metadata about the SR_DF_ANALOG packets to come. */ + packet.type = SR_DF_META_ANALOG; + packet.payload = &meta; + meta.num_probes = ctx->profile->num_probes; + sr_session_send(cb_data, &packet); + + return SR_OK; +} + +/* TODO: doesn't really cancel pending transfers so they might come in after + * SR_DF_END is sent. + */ +static int hw_stop_acquisition(int device_index, gpointer session_device_id) +{ + struct sr_datafeed_packet packet; + struct sr_dev_inst *sdi; + struct context *ctx; + + if (!(sdi = sr_dev_inst_get(dev_insts, device_index))) + return SR_ERR; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR; + + ctx = sdi->priv; + ctx->dev_state = IDLE; + + packet.type = SR_DF_END; + sr_session_send(session_device_id, &packet); + + return SR_OK; +} + +SR_PRIV struct sr_dev_driver hantek_dso_plugin_info = { + .name = "hantek-dso", + .longname = "Hantek DSO", + .api_version = 1, + .init = hw_init, + .cleanup = hw_cleanup, + .dev_open = hw_dev_open, + .dev_close = hw_dev_close, + .dev_info_get = hw_get_device_info, + .dev_status_get = hw_get_status, + .hwcap_get_all = hwcap_get_all, + .dev_config_set = hw_dev_config_set, + .dev_acquisition_start = hw_start_acquisition, + .dev_acquisition_stop = hw_stop_acquisition, +}; diff --git a/hardware/hantek-dso/dso.c b/hardware/hantek-dso/dso.c new file mode 100644 index 00000000..278b2ebe --- /dev/null +++ b/hardware/hantek-dso/dso.c @@ -0,0 +1,609 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2012 Bert Vermeulen + * With protocol information from the hantekdso project, + * Copyright (C) 2008 Oleg Khudyakov + * + * 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 . + */ + +#include "sigrok.h" +#include "sigrok-internal.h" +#include "config.h" +#include "dso.h" +#include +#include +#include + +extern libusb_context *usb_context; +extern GSList *dev_insts; + + +static int send_begin(struct context *ctx) +{ + int ret; + unsigned char buffer[] = {0x0f, 0x03, 0x03, 0x03, 0x68, 0xac, 0xfe, + 0x00, 0x01, 0x00}; + + sr_dbg("hantek-dso: sending CTRL_BEGINCOMMAND"); + + if ((ret = libusb_control_transfer(ctx->usb->devhdl, + LIBUSB_REQUEST_TYPE_VENDOR, CTRL_BEGINCOMMAND, + 0, 0, buffer, sizeof(buffer), 200)) != sizeof(buffer)) { + sr_err("failed to send begincommand: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +static int send_bulkcmd(struct context *ctx, uint8_t *cmdstring, int cmdlen) +{ + int ret, tmp; + + if (send_begin(ctx) != SR_OK) + return SR_ERR; + + if ((ret = libusb_bulk_transfer(ctx->usb->devhdl, + DSO_EP_OUT | LIBUSB_ENDPOINT_OUT, + cmdstring, cmdlen, &tmp, 200)) != 0) + return SR_ERR; + + return SR_OK; +} + +SR_PRIV int dso_getmps(libusb_device *dev) +{ + struct libusb_device_descriptor des; + struct libusb_config_descriptor *conf_dsc; + const struct libusb_interface_descriptor *intf_dsc; + int mps; + + if (libusb_get_device_descriptor(dev, &des) != 0) + return 0; + + if (des.bNumConfigurations != 1) + return 0; + + if (libusb_get_config_descriptor(dev, 0, &conf_dsc) != 0) + return 0; + + mps = 0; + intf_dsc = &(conf_dsc->interface[0].altsetting[0]); + if (intf_dsc->bNumEndpoints != 2) + goto err; + + if ((intf_dsc->endpoint[0].bEndpointAddress & 0x8f) != + (2 | LIBUSB_ENDPOINT_OUT)) + /* The first endpoint should be 2 (outbound). */ + goto err; + + if ((intf_dsc->endpoint[1].bEndpointAddress & 0x8f) != + (6 | LIBUSB_ENDPOINT_IN)) + /* The second endpoint should be 6 (inbound). */ + goto err; + + mps = intf_dsc->endpoint[1].wMaxPacketSize; + +err: + if (conf_dsc) + libusb_free_config_descriptor(conf_dsc); + + return mps; +} + +SR_PRIV int dso_open(int dev_index) +{ + libusb_device **devlist; + struct libusb_device_descriptor des; + struct sr_dev_inst *sdi; + struct context *ctx; + int err, skip, i; + + if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) + return SR_ERR_ARG; + ctx = sdi->priv; + + if (sdi->status == SR_ST_ACTIVE) + /* already in use */ + return SR_ERR; + + skip = 0; + libusb_get_device_list(usb_context, &devlist); + for (i = 0; devlist[i]; i++) { + if ((err = libusb_get_device_descriptor(devlist[i], &des))) { + sr_err("hantek-dso: failed to get device descriptor: %d", err); + continue; + } + + if (des.idVendor != ctx->profile->fw_vid + || des.idProduct != ctx->profile->fw_pid) + continue; + + if (sdi->status == SR_ST_INITIALIZING) { + if (skip != dev_index) { + /* Skip devices of this type that aren't the one we want. */ + skip += 1; + continue; + } + } else if (sdi->status == SR_ST_INACTIVE) { + /* + * This device is fully enumerated, so we need to find + * this device by vendor, product, bus and address. + */ + if (libusb_get_bus_number(devlist[i]) != ctx->usb->bus + || libusb_get_device_address(devlist[i]) != ctx->usb->address) + /* this is not the one */ + continue; + } + + if (!(err = libusb_open(devlist[i], &ctx->usb->devhdl))) { + if (ctx->usb->address == 0xff) + /* + * first time we touch this device after firmware upload, + * so we don't know the address yet. + */ + ctx->usb->address = libusb_get_device_address(devlist[i]); + + if(!(ctx->epin_maxpacketsize = dso_getmps(devlist[i]))) + sr_err("hantek-dso: wrong endpoint profile"); + else { + sdi->status = SR_ST_ACTIVE; + sr_info("hantek-dso: opened device %d on %d.%d interface %d", + sdi->index, ctx->usb->bus, + ctx->usb->address, USB_INTERFACE); + } + } else { + sr_err("hantek-dso: failed to open device: %d", err); + } + + /* if we made it here, we handled the device one way or another */ + break; + } + libusb_free_device_list(devlist, 1); + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR; + + return SR_OK; +} + +SR_PRIV void dso_close(struct sr_dev_inst *sdi) +{ + struct context *ctx; + + ctx = sdi->priv; + + if (ctx->usb->devhdl == NULL) + return; + + sr_info("hantek-dso: closing device %d on %d.%d interface %d", sdi->index, + ctx->usb->bus, ctx->usb->address, USB_INTERFACE); + libusb_release_interface(ctx->usb->devhdl, USB_INTERFACE); + libusb_close(ctx->usb->devhdl); + ctx->usb->devhdl = NULL; + sdi->status = SR_ST_INACTIVE; + +} + +static int get_channel_offsets(struct context *ctx) +{ + int ret; + + sr_dbg("hantek-dso: getting channel offsets"); + + ret = libusb_control_transfer(ctx->usb->devhdl, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR, + CTRL_READ_EEPROM, EEPROM_CHANNEL_OFFSETS, 0, + (unsigned char *)&ctx->channel_levels, + sizeof(ctx->channel_levels), 200); + if (ret != sizeof(ctx->channel_levels)) { + sr_err("failed to get channel offsets: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dso_set_trigger_samplerate(struct context *ctx) +{ + int ret, tmp; + uint8_t cmdstring[12]; + uint8_t timebasefast_small[] = {1, 2, 3, 4}; + uint8_t timebasefast_large[] = {0, 0, 2, 3}; + uint16_t timebase_small[] = { 0xffff, 0xfffc, 0xfff7, 0xffe8, 0xffce, + 0xff9c, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79, 0xd8f1 }; + uint16_t timebase_large[] = { 0xffff, 0x0000, 0xfffc, 0xfff7, 0xffe8, + 0xffce, 0xff9d, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79 }; + + sr_dbg("hantek-dso: sending CMD_SET_TRIGGER_SAMPLERATE"); + + memset(cmdstring, 0, sizeof(cmdstring)); + /* Command */ + cmdstring[0] = CMD_SET_TRIGGER_SAMPLERATE; + + /* Trigger source */ + cmdstring[2] = (ctx->triggersource & 0x03) << 6; + + /* Frame size */ + cmdstring[2] |= (ctx->framesize == FRAMESIZE_SMALL ? 0x01 : 0x02) << 3; + + /* Timebase fast (no idea what this means) */ + if (ctx->timebase < TIME_20us) + tmp = 0; + else if (ctx->timebase > TIME_200us) + tmp = 4; + else { + if (ctx->framesize == FRAMESIZE_SMALL) + tmp = timebasefast_small[ctx->timebase - 1]; + else + tmp = timebasefast_large[ctx->timebase - 1]; + } + cmdstring[2] |= tmp & 0x07; +cmdstring[2] = 0x45; + /* Selected channel */ + cmdstring[3] = (ctx->selected_channel & 0x03) << 6; +cmdstring[3] = 0x02; + + /* TODO: Fast rates channel */ + cmdstring[3] |= 0 << 5; + + /* Trigger slope */ + cmdstring[3] |= (ctx->triggerslope ? 1 : 0) << 4; + + /* Timebase */ + if (ctx->timebase < TIME_100us) + tmp = 0; + else if (ctx->timebase > TIME_400ms) + tmp = 0xffed; + else { + if (ctx->framesize == FRAMESIZE_SMALL) + tmp = timebase_small[ctx->timebase - 3]; + else + tmp = timebase_large[ctx->timebase - 3]; + } +tmp = 0xebff; + cmdstring[6] = tmp & 0xff; + cmdstring[7] = (tmp >> 8) & 0xff; + + /* Trigger position (time) */ + tmp = 0x77660 + ctx->triggerposition; +tmp = 0x7006f; + cmdstring[8] = tmp & 0xff; + cmdstring[9] = (tmp >> 8) & 0xff; + cmdstring[10] = (tmp >> 16) & 0xff; + + if (send_begin(ctx) != SR_OK) + return SR_ERR; + + if ((ret = libusb_bulk_transfer(ctx->usb->devhdl, + DSO_EP_OUT | LIBUSB_ENDPOINT_OUT, + cmdstring, sizeof(cmdstring), + &tmp, 100)) != 0) { + sr_err("Failed to set trigger/samplerate: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dso_set_filters(struct context *ctx) +{ + int ret, tmp; + uint8_t cmdstring[8]; + + sr_dbg("hantek-dso: sending CMD_SET_FILTERS"); + + memset(cmdstring, 0, sizeof(cmdstring)); + cmdstring[0] = CMD_SET_FILTERS; + cmdstring[1] = 0x0f; + if (ctx->filter_ch1) + cmdstring[2] |= 0x80; + if (ctx->filter_ch2) + cmdstring[2] |= 0x40; + if (ctx->filter_trigger) + cmdstring[2] |= 0x20; + + if (send_begin(ctx) != SR_OK) + return SR_ERR; + + if ((ret = libusb_bulk_transfer(ctx->usb->devhdl, + DSO_EP_OUT | LIBUSB_ENDPOINT_OUT, + cmdstring, sizeof(cmdstring), + &tmp, 100)) != 0) { + sr_err("Failed to set filters: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dso_set_voltage(struct context *ctx) +{ + int ret, tmp; + uint8_t cmdstring[8]; + + sr_dbg("hantek-dso: sending CMD_SET_VOLTAGE"); + + memset(cmdstring, 0, sizeof(cmdstring)); + cmdstring[0] = CMD_SET_VOLTAGE; + cmdstring[1] = 0x0f; + cmdstring[2] = 0x03; + cmdstring[2] |= ((2 - ctx->voltage_ch1 % 3) << 6); + cmdstring[2] |= ((2 - ctx->voltage_ch2 % 3) << 4); +cmdstring[2] = 0x30; + + if (send_begin(ctx) != SR_OK) + return SR_ERR; + + if ((ret = libusb_bulk_transfer(ctx->usb->devhdl, + DSO_EP_OUT | LIBUSB_ENDPOINT_OUT, + cmdstring, sizeof(cmdstring), + &tmp, 100)) != 0) { + sr_err("Failed to set voltage: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dso_set_relays(struct context *ctx) +{ + int ret, cv1, cv2; + uint8_t relays[] = { 0x00, 0x04, 0x08, 0x02, 0x20, 0x40, 0x10, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + sr_dbg("hantek-dso: sending CTRL_SETRELAYS"); + + cv1 = ctx->voltage_ch1 / 3; + cv2 = ctx->voltage_ch2 / 3; +relays[0] = 0x01; + if (cv1 > 0) + relays[1] = ~relays[1]; + + if (cv1 > 1) + relays[2] = ~relays[2]; + + if (ctx->coupling_ch1 != COUPLING_AC) + relays[3] = ~relays[3]; + + if (cv2 > 0) + relays[4] = ~relays[4]; + + if (cv2 > 1) + relays[5] = ~relays[5]; + + if (ctx->coupling_ch2 != COUPLING_AC) + relays[6] = ~relays[6]; + + if (ctx->triggersource == TRIGGER_EXT || ctx->triggersource == TRIGGER_EXT10) + relays[7] = ~relays[7]; + + if ((ret = libusb_control_transfer(ctx->usb->devhdl, + LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETRELAYS, + 0, 0, relays, sizeof(relays), 100)) != sizeof(relays)) { + sr_err("failed to set relays: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dso_set_voffsets(struct context *ctx) +{ + int offset, ret; + uint16_t *ch_levels; +// uint8_t offsets[17]; +uint8_t offsets[] = {0x20,0x75,0x30,0x3f,0x20,0xbd,0x3f,0x02,0x20,0x00,0x71,0x01,0x2e,0x0b,0x3f,0x02,0x50}; +//uint8_t offsets[] = {0xff, 0x75, 0x30, 0x3f, 0x20, 0xbd, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +//}; + + sr_dbg("hantek-dso: sending CTRL_SETOFFSET"); + +// memset(offsets, 0, sizeof(offsets)); +// /* Channel 1 */ +// ch_levels = ctx->channel_levels[0][VOLTAGE_10mV - ctx->voltage_ch1]; +// offset = (ch_levels[1] - ch_levels[0]) * ctx->voffset_ch1 + ch_levels[0]; +// offsets[0] = (offset >> 8) | 0x20; +// offsets[1] = offset & 0xff; +// +// /* Channel 2 */ +// ch_levels = ctx->channel_levels[1][VOLTAGE_10mV - ctx->voltage_ch2]; +// offset = (ch_levels[1] - ch_levels[0]) * ctx->voffset_ch2 + ch_levels[0]; +// offsets[2] = (offset >> 8) | 0x20; +// offsets[3] = offset & 0xff; +// +// /* Trigger */ +// offset = MAX_VERT_TRIGGER * ctx->voffset_trigger; +// offsets[4] = (offset >> 8) | 0x20; +// offsets[5] = offset & 0xff; + + if ((ret = libusb_control_transfer(ctx->usb->devhdl, + LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETOFFSET, + 0, 0, offsets, sizeof(offsets), 100)) != sizeof(offsets)) { + sr_err("failed to set offsets: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dso_enable_trigger(struct context *ctx) +{ + int ret, tmp; + uint8_t cmdstring[2]; + + sr_dbg("hantek-dso: sending CMD_ENABLE_TRIGGER"); + + memset(cmdstring, 0, sizeof(cmdstring)); + cmdstring[0] = CMD_ENABLE_TRIGGER; + cmdstring[1] = 0x00; + + if (send_begin(ctx) != SR_OK) + return SR_ERR; + + if ((ret = libusb_bulk_transfer(ctx->usb->devhdl, + DSO_EP_OUT | LIBUSB_ENDPOINT_OUT, + cmdstring, sizeof(cmdstring), + &tmp, 100)) != 0) { + sr_err("Failed to enable trigger: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dso_force_trigger(struct context *ctx) +{ + int ret, tmp; + uint8_t cmdstring[2]; + + sr_dbg("hantek-dso: sending CMD_FORCE_TRIGGER"); + + memset(cmdstring, 0, sizeof(cmdstring)); + cmdstring[0] = CMD_FORCE_TRIGGER; + cmdstring[1] = 0x00; + + if (send_begin(ctx) != SR_OK) + return SR_ERR; + + if ((ret = libusb_bulk_transfer(ctx->usb->devhdl, + DSO_EP_OUT | LIBUSB_ENDPOINT_OUT, + cmdstring, sizeof(cmdstring), + &tmp, 100)) != 0) { + sr_err("Failed to force trigger: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dso_init(struct context *ctx) +{ + + sr_dbg("hantek-dso: initializing dso"); + + if (get_channel_offsets(ctx) != SR_OK) + return SR_ERR; + + if (dso_set_trigger_samplerate(ctx) != SR_OK) + return SR_ERR; + + if (dso_set_filters(ctx) != SR_OK) + return SR_ERR; + + if (dso_set_voltage(ctx) != SR_OK) + return SR_ERR; + + if (dso_set_relays(ctx) != SR_OK) + return SR_ERR; + + if (dso_set_voffsets(ctx) != SR_OK) + return SR_ERR; + + if (dso_enable_trigger(ctx) != SR_OK) + return SR_ERR; + + if (dso_force_trigger(ctx) != SR_OK) + return SR_ERR; + + return SR_OK; +} + +SR_PRIV uint8_t dso_get_capturestate(struct context *ctx) +{ + int ret, tmp; + uint8_t cmdstring[2], inbuf[512]; + + sr_dbg("hantek-dso: sending CMD_GET_CAPTURESTATE"); + + cmdstring[0] = CMD_GET_CAPTURESTATE; + cmdstring[1] = 0; + + if ((ret = send_bulkcmd(ctx, cmdstring, sizeof(cmdstring))) != SR_OK) { + sr_dbg("Failed to send get_capturestate command: %d", ret); + return CAPTURE_UNKNOWN; + } + + if ((ret = libusb_bulk_transfer(ctx->usb->devhdl, + DSO_EP_IN | LIBUSB_ENDPOINT_IN, + inbuf, 512, &tmp, 100)) != 0) { + sr_dbg("Failed to get capturestate: %d", ret); + return CAPTURE_UNKNOWN; + } + + return inbuf[0]; +} + +SR_PRIV uint8_t dso_capture_start(struct context *ctx) +{ + int ret; + uint8_t cmdstring[2]; + + sr_dbg("hantek-dso: sending CMD_CAPTURE_START"); + + cmdstring[0] = CMD_CAPTURE_START; + cmdstring[1] = 0; + + if ((ret = send_bulkcmd(ctx, cmdstring, sizeof(cmdstring))) != SR_OK) { + sr_err("Failed to send capture_start command: %d", ret); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int dso_get_channeldata(struct context *ctx, libusb_transfer_cb_fn cb) +{ + struct libusb_transfer *transfer; + int num_transfers, ret, i; + uint8_t cmdstring[2]; + unsigned char *buf; + + sr_dbg("hantek-dso: sending CMD_GET_CHANNELDATA"); + + cmdstring[0] = CMD_GET_CHANNELDATA; + cmdstring[1] = 0; + + if ((ret = send_bulkcmd(ctx, cmdstring, sizeof(cmdstring))) != SR_OK) { + sr_err("Failed to get channel data: %d", ret); + return SR_ERR; + } + + /* TODO: dso-2xxx only */ + num_transfers = ctx->framesize * sizeof(unsigned short) / ctx->epin_maxpacketsize; + sr_dbg("hantek-dso: queueing up %d transfers", num_transfers); + for (i = 0; i < num_transfers; i++) { + if (!(buf = g_try_malloc(ctx->epin_maxpacketsize))) { + sr_err("hantek-dso: %s: buf malloc failed", __func__); + return SR_ERR_MALLOC; + } + transfer = libusb_alloc_transfer(0); + libusb_fill_bulk_transfer(transfer, ctx->usb->devhdl, + DSO_EP_IN | LIBUSB_ENDPOINT_IN, buf, + ctx->epin_maxpacketsize, cb, ctx, 40); + if ((ret = libusb_submit_transfer(transfer)) != 0) { + sr_err("failed to submit transfer: %d", ret); + /* TODO: Free them all. */ + libusb_free_transfer(transfer); + g_free(buf); + return SR_ERR; + } + } + + return SR_OK; +} + diff --git a/hardware/hantek-dso/dso.h b/hardware/hantek-dso/dso.h new file mode 100644 index 00000000..6e35a985 --- /dev/null +++ b/hardware/hantek-dso/dso.h @@ -0,0 +1,215 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2012 Bert Vermeulen + * With protocol information from the hantekdso project, + * Copyright (C) 2008 Oleg Khudyakov + * + * 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 . + */ + +#ifndef LIBSIGROK_HARDWARE_HANTEK_DSO_H +#define LIBSIGROK_HARDWARE_HANTEK_DSO_H + +#define USB_INTERFACE 0 +#define USB_CONFIGURATION 1 +#define DSO_EP_IN 0x86 +#define DSO_EP_OUT 0x02 + +/* FX2 renumeration delay in ms */ +#define MAX_RENUM_DELAY 3000 + +#define MAX_CAPTURE_EMPTY 3 + +#define DEFAULT_VOLTAGE VOLTAGE_2V +#define DEFAULT_FRAMESIZE FRAMESIZE_SMALL +#define DEFAULT_TIMEBASE TIME_1ms +#define DEFAULT_TRIGGER_SOURCE TRIGGER_CH1 +#define DEFAULT_COUPLING COUPLING_AC +#define DEFAULT_SELECTED_CHANNEL SELECT_CH1CH2 +/* Halfway between min and max = 0V */ +#define DEFAULT_HORIZ_TRIGGERPOS 0x1400 + +#define DEFAULT_VERT_OFFSET 0.5 +#define DEFAULT_VERT_TRIGGERPOS 0.0 + +#define MAX_VERT_TRIGGER 0xfe + +/* Hantek DSO-specific protocol values */ +#define EEPROM_CHANNEL_OFFSETS 0x08 + +#define FRAMESIZE_SMALL 10240 +#define FRAMESIZE_LARGE 32768 + + +enum control_requests { + CTRL_READ_EEPROM = 0xa2, + CTRL_GETSPEED = 0xb2, + CTRL_BEGINCOMMAND = 0xb3, + CTRL_SETOFFSET = 0xb4, + CTRL_SETRELAYS = 0xb5 +}; + +enum dso_commands { + CMD_SET_FILTERS = 0, + CMD_SET_TRIGGER_SAMPLERATE, + CMD_FORCE_TRIGGER, + CMD_CAPTURE_START, + CMD_ENABLE_TRIGGER, + CMD_GET_CHANNELDATA, + CMD_GET_CAPTURESTATE, + CMD_SET_VOLTAGE, + cmdSetLogicalData, + cmdGetLogicalData +}; + +enum voltages { + VOLTAGE_5V = 0, + VOLTAGE_2V, + VOLTAGE_1V, + VOLTAGE_500mV, + VOLTAGE_200mV, + VOLTAGE_100mV, + VOLTAGE_50mV, + VOLTAGE_20mV, + VOLTAGE_10mV +}; + +enum couplings { + COUPLING_AC = 0, + COUPLING_DC, + COUPLING_OFF +}; + +enum time_bases { + TIME_10us = 0, + TIME_20us, + TIME_40us, + TIME_100us, + TIME_200us, + TIME_400us, + TIME_1ms, + TIME_2ms, + TIME_4ms, + TIME_10ms, + TIME_20ms, + TIME_40ms, + TIME_100ms, + TIME_200ms, + TIME_400ms +}; + +enum trigger_slopes { + SLOPE_POSITIVE = 0, + SLOPE_NEGATIVE +}; + +enum trigger_sources { + TRIGGER_CH2 = 0, + TRIGGER_CH1, + TRIGGER_ALT, + TRIGGER_EXT, + TRIGGER_EXT10 +}; + +enum selected_channels { + SELECT_CH1 = 0, + SELECT_CH2, + SELECT_CH1CH2 +}; + +enum capturestates { + CAPTURE_EMPTY = 0, + CAPTURE_FILLING = 1, + CAPTURE_READY_8BIT = 2, + CAPTURE_READY_9BIT = 7, + CAPTURE_TIMEOUT = 127, + CAPTURE_UNKNOWN = 255 +}; + +enum triggermodes { + TRIGGERMODE_AUTO, + TRIGGERMODE_NORMAL, + TRIGGERMODE_SINGLE +}; + +enum states { + IDLE, + NEW_CAPTURE, + CAPTURE, + FETCH_DATA +}; + +struct dso_profile { + /* VID/PID after cold boot */ + uint16_t orig_vid; + uint16_t orig_pid; + /* VID/PID after firmware upload */ + uint16_t fw_vid; + uint16_t fw_pid; + char *vendor; + char *model; + char *model_version; + int num_probes; + char *firmware; +}; + +struct context { + struct dso_profile *profile; + struct sr_usb_dev_inst *usb; + void *cb_data; + /* We can't keep track of an FX2-based device after upgrading + * the firmware (it re-enumerates into a different device address + * after the upgrade) this is like a global lock. No device will open + * until a proper delay after the last device was upgraded. + */ + GTimeVal fw_updated; + int epin_maxpacketsize; + int capture_empty_count; + int current_transfer; + int dev_state; + + int timebase; + gboolean ch1_enabled; + gboolean ch2_enabled; + int voltage_ch1; + int voltage_ch2; + int coupling_ch1; + int coupling_ch2; + // voltage offset (vertical position) + float voffset_ch1; + float voffset_ch2; + float voffset_trigger; + uint16_t channel_levels[2][9][2]; + int selected_channel; + int framesize; + gboolean filter_ch1; + gboolean filter_ch2; + gboolean filter_trigger; + int triggerslope; + int triggersource; + int triggerposition; + int triggermode; +}; + +SR_PRIV int dso_open(int dev_index); +SR_PRIV void dso_close(struct sr_dev_inst *sdi); +SR_PRIV int dso_enable_trigger(struct context *ctx); +SR_PRIV int dso_force_trigger(struct context *ctx); +SR_PRIV int dso_init(struct context *ctx); +SR_PRIV uint8_t dso_get_capturestate(struct context *ctx); +SR_PRIV uint8_t dso_capture_start(struct context *ctx); +SR_PRIV int dso_get_channeldata(struct context *ctx, libusb_transfer_cb_fn cb); + +#endif diff --git a/hwdriver.c b/hwdriver.c index c265b1be..41e99ded 100644 --- a/hwdriver.c +++ b/hwdriver.c @@ -63,6 +63,9 @@ extern SR_PRIV struct sr_dev_driver alsa_driver_info; #ifdef HAVE_LA_FX2LAFW extern SR_PRIV struct sr_dev_driver fx2lafw_driver_info; #endif +#ifdef HAVE_HW_HANTEK_DSO +extern SR_PRIV struct sr_dev_driver hantek_dso_plugin_info; +#endif static struct sr_dev_driver *drivers_list[] = { #ifdef HAVE_LA_DEMO @@ -88,6 +91,9 @@ static struct sr_dev_driver *drivers_list[] = { #endif #ifdef HAVE_LA_FX2LAFW &fx2lafw_driver_info, +#endif +#ifdef HAVE_HW_HANTEK_DSO + &hantek_dso_plugin_info, #endif NULL, };