Hello, this driver is for the above mentioned oscilloscope series. The patches in the attachment should apply to master.
The driver puts the trigger system into single-mode, and retrieves the acquired waveform data for each frame for each selected channel. I have tested it with the serial port of my "Voltcraft DSO 6060C" alias "GW Instek GDS-810C". Note that I was not able to use the USB port of the oscilloscope. It seems to contain an serial to USB converter, but I was unable to establish a connection. Information can be found on the vendor's web site, see http://www.gwinstek.com.cn/en/product/productdetail.aspx?id=51&mid=7&pid=3 - especially the programming manual, which can be found on the download tab. Please integrate the driver into Sigrok. Let me know if you need a photograph from the scope - for example for the web page - I do not want to post it to the mailing list, because the image is rather big. Greetings, Martin
>From da2583ca18bab3d0741450cd8ed487adfb15198f Mon Sep 17 00:00:00 2001 From: Martin Lederhilger <martin.lederhil...@gmx.at> Date: Sun, 16 Aug 2015 14:52:49 +0200 Subject: [PATCH 1/2] gwinstek-gds-800: Initial driver skeleton. --- Makefile.am | 6 + configure.ac | 1 + src/drivers.c | 6 + src/hardware/gwinstek-gds-800/api.c | 190 +++++++++++++++++++++++++++++++ src/hardware/gwinstek-gds-800/protocol.c | 40 +++++++ src/hardware/gwinstek-gds-800/protocol.h | 44 +++++++ 6 files changed, 287 insertions(+) create mode 100644 src/hardware/gwinstek-gds-800/api.c create mode 100644 src/hardware/gwinstek-gds-800/protocol.c create mode 100644 src/hardware/gwinstek-gds-800/protocol.h diff --git a/Makefile.am b/Makefile.am index c866213..bde3b2c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -262,6 +262,12 @@ libsigrok_la_SOURCES += \ src/hardware/gmc-mh-1x-2x/protocol.c \ src/hardware/gmc-mh-1x-2x/api.c endif +if HW_GWINSTEK_GDS_800 +libsigrok_la_SOURCES += \ + src/hardware/gwinstek-gds-800/protocol.h \ + src/hardware/gwinstek-gds-800/protocol.c \ + src/hardware/gwinstek-gds-800/api.c +endif if HW_HAMEG_HMO libsigrok_la_SOURCES += \ src/hardware/hameg-hmo/protocol.h \ diff --git a/configure.ac b/configure.ac index 5b89465..3eb0486 100644 --- a/configure.ac +++ b/configure.ac @@ -229,6 +229,7 @@ SR_DRIVER([demo], [demo]) SR_DRIVER([Fluke DMM], [fluke-dmm], [libserialport]) SR_DRIVER([fx2lafw], [fx2lafw], [libusb]) SR_DRIVER([GMC MH 1x/2x], [gmc-mh-1x-2x], [libserialport]) +SR_DRIVER([gwinstek gds-800], [gwinstek-gds-800], [libserialport]) SR_DRIVER([Hameg HMO], [hameg-hmo], [libserialport]) SR_DRIVER([Hantek DSO], [hantek-dso], [libusb]) SR_DRIVER([Hung-Chang DSO-2100], [hung-chang-dso-2100], [libieee1284]) diff --git a/src/drivers.c b/src/drivers.c index d2ad9f8..2cc367f 100644 --- a/src/drivers.c +++ b/src/drivers.c @@ -78,6 +78,9 @@ extern SR_PRIV struct sr_dev_driver fx2lafw_driver_info; extern SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info; extern SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info; #endif +#ifdef HAVE_HW_GWINSTEK_GDS_800 +extern SR_PRIV struct sr_dev_driver gwinstek_gds_800_driver_info; +#endif #ifdef HAVE_HW_HAMEG_HMO extern SR_PRIV struct sr_dev_driver hameg_hmo_driver_info; #endif @@ -172,6 +175,9 @@ extern SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info; SR_PRIV struct sr_dev_driver **drivers_lists[] = { #ifdef HAVE_HW_AGILENT_DMM +#ifdef HAVE_HW_GWINSTEK_GDS_800 + (DRVS) {&gwinstek_gds_800_driver_info, NULL}, +#endif (DRVS) {&agdmm_driver_info, NULL}, #endif #ifdef HAVE_HW_APPA_55II diff --git a/src/hardware/gwinstek-gds-800/api.c b/src/hardware/gwinstek-gds-800/api.c new file mode 100644 index 0000000..1a444b0 --- /dev/null +++ b/src/hardware/gwinstek-gds-800/api.c @@ -0,0 +1,190 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2015 Martin Lederhilger <martin.lederhil...@gmx.at> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "protocol.h" + +SR_PRIV struct sr_dev_driver gwinstek_gds_800_driver_info; + +static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx) +{ + return std_init(sr_ctx, di, LOG_PREFIX); +} + +static GSList *scan(struct sr_dev_driver *di, GSList *options) +{ + struct drv_context *drvc; + GSList *devices; + + (void)options; + + devices = NULL; + drvc = di->context; + drvc->instances = NULL; + + /* TODO: scan for devices, either based on a SR_CONF_CONN option + * or on a USB scan. */ + + return devices; +} + +static GSList *dev_list(const struct sr_dev_driver *di) +{ + return ((struct drv_context *)(di->context))->instances; +} + +static int dev_clear(const struct sr_dev_driver *di) +{ + return std_dev_clear(di, NULL); +} + +static int dev_open(struct sr_dev_inst *sdi) +{ + (void)sdi; + + /* TODO: get handle from sdi->conn and open it. */ + + sdi->status = SR_ST_ACTIVE; + + return SR_OK; +} + +static int dev_close(struct sr_dev_inst *sdi) +{ + (void)sdi; + + /* TODO: get handle from sdi->conn and close it. */ + + sdi->status = SR_ST_INACTIVE; + + return SR_OK; +} + +static int cleanup(const struct sr_dev_driver *di) +{ + dev_clear(di); + + /* TODO: free other driver resources, if any. */ + + return SR_OK; +} + +static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) +{ + int ret; + + (void)sdi; + (void)data; + (void)cg; + + ret = SR_OK; + switch (key) { + /* TODO */ + default: + return SR_ERR_NA; + } + + return ret; +} + +static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) +{ + int ret; + + (void)data; + (void)cg; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; + + ret = SR_OK; + switch (key) { + /* TODO */ + default: + ret = SR_ERR_NA; + } + + return ret; +} + +static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) +{ + int ret; + + (void)sdi; + (void)data; + (void)cg; + + ret = SR_OK; + switch (key) { + /* TODO */ + default: + return SR_ERR_NA; + } + + return ret; +} + +static int dev_acquisition_start(const struct sr_dev_inst *sdi, + void *cb_data) +{ + (void)sdi; + (void)cb_data; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; + + /* TODO: configure hardware, reset acquisition state, set up + * callbacks and send header packet. */ + + return SR_OK; +} + +static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) +{ + (void)cb_data; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; + + /* TODO: stop acquisition. */ + + return SR_OK; +} + +SR_PRIV struct sr_dev_driver gwinstek_gds_800_driver_info = { + .name = "gwinstek-gds-800", + .longname = "gwinstek gds-800", + .api_version = 1, + .init = init, + .cleanup = cleanup, + .scan = scan, + .dev_list = dev_list, + .dev_clear = dev_clear, + .config_get = config_get, + .config_set = config_set, + .config_list = config_list, + .dev_open = dev_open, + .dev_close = dev_close, + .dev_acquisition_start = dev_acquisition_start, + .dev_acquisition_stop = dev_acquisition_stop, + .context = NULL, +}; diff --git a/src/hardware/gwinstek-gds-800/protocol.c b/src/hardware/gwinstek-gds-800/protocol.c new file mode 100644 index 0000000..8c5a102 --- /dev/null +++ b/src/hardware/gwinstek-gds-800/protocol.c @@ -0,0 +1,40 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2015 Martin Lederhilger <martin.lederhil...@gmx.at> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "protocol.h" + +SR_PRIV int gwinstek_gds_800_receive_data(int fd, int revents, void *cb_data) +{ + const struct sr_dev_inst *sdi; + struct dev_context *devc; + + (void)fd; + + if (!(sdi = cb_data)) + return TRUE; + + if (!(devc = sdi->priv)) + return TRUE; + + if (revents == G_IO_IN) { + /* TODO */ + } + + return TRUE; +} diff --git a/src/hardware/gwinstek-gds-800/protocol.h b/src/hardware/gwinstek-gds-800/protocol.h new file mode 100644 index 0000000..5ee467f --- /dev/null +++ b/src/hardware/gwinstek-gds-800/protocol.h @@ -0,0 +1,44 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2015 Martin Lederhilger <martin.lederhil...@gmx.at> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LIBSIGROK_HARDWARE_GWINSTEK_GDS_800_PROTOCOL_H +#define LIBSIGROK_HARDWARE_GWINSTEK_GDS_800_PROTOCOL_H + +#include <stdint.h> +#include <glib.h> +#include "libsigrok.h" +#include "libsigrok-internal.h" + +#define LOG_PREFIX "gwinstek-gds-800" + +/** Private, per-device-instance driver context. */ +struct dev_context { + /* Model-specific information */ + + /* Acquisition settings */ + + /* Operational state */ + + /* Temporary state across callbacks */ + +}; + +SR_PRIV int gwinstek_gds_800_receive_data(int fd, int revents, void *cb_data); + +#endif -- 2.3.6
>From de01ba722cbd9cba685933cf6ce2f213fc5123df Mon Sep 17 00:00:00 2001 From: Martin Lederhilger <martin.lederhil...@gmx.at> Date: Sun, 16 Aug 2015 19:52:02 +0200 Subject: [PATCH 2/2] gwinstek-gds-800: Initial driver implementation. --- src/hardware/gwinstek-gds-800/api.c | 182 +++++++++++++++++----- src/hardware/gwinstek-gds-800/protocol.c | 258 ++++++++++++++++++++++++++++++- src/hardware/gwinstek-gds-800/protocol.h | 39 +++-- 3 files changed, 426 insertions(+), 53 deletions(-) diff --git a/src/hardware/gwinstek-gds-800/api.c b/src/hardware/gwinstek-gds-800/api.c index 1a444b0..1d86705 100644 --- a/src/hardware/gwinstek-gds-800/api.c +++ b/src/hardware/gwinstek-gds-800/api.c @@ -17,8 +17,20 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <string.h> #include "protocol.h" +static const uint32_t scanopts[] = { + SR_CONF_CONN, + SR_CONF_SERIALCOMM +}; + +static const uint32_t devopts[] = { + SR_CONF_OSCILLOSCOPE, + SR_CONF_LIMIT_FRAMES | SR_CONF_SET, + SR_CONF_SAMPLERATE | SR_CONF_GET +}; + SR_PRIV struct sr_dev_driver gwinstek_gds_800_driver_info; static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx) @@ -26,21 +38,60 @@ static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx) return std_init(sr_ctx, di, LOG_PREFIX); } -static GSList *scan(struct sr_dev_driver *di, GSList *options) +static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi) { - struct drv_context *drvc; - GSList *devices; - - (void)options; - - devices = NULL; - drvc = di->context; - drvc->instances = NULL; - - /* TODO: scan for devices, either based on a SR_CONF_CONN option - * or on a USB scan. */ + struct dev_context *devc; + struct sr_dev_inst *sdi; + struct sr_scpi_hw_info *hw_info; + struct sr_channel_group *cg; + + if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) { + sr_info("Couldn't get IDN response."); + return NULL; + } + + if(strcmp(hw_info->manufacturer, "GW") != 0 || + strncmp(hw_info->model, "GDS-8", 5) != 0) { + sr_scpi_hw_info_free(hw_info); + return NULL; + } + + sdi = g_malloc0(sizeof(struct sr_dev_inst)); + sdi->status = SR_ST_ACTIVE; + sdi->vendor = g_strdup(hw_info->manufacturer); + sdi->model = g_strdup(hw_info->model); + sdi->version = g_strdup(hw_info->firmware_version); + sdi->conn = scpi; + sdi->driver = &gwinstek_gds_800_driver_info; + sdi->inst_type = SR_INST_SCPI; + sdi->serial_num = g_strdup(hw_info->serial_number); + sdi->channels = NULL; + sdi->channel_groups = NULL; + + sr_scpi_hw_info_free(hw_info); + + devc = g_malloc0(sizeof(struct dev_context)); + devc->frame_limit = 1; + devc->sample_rate = 0.; + devc->df_started = FALSE; + sdi->priv = devc; + + sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "CH1"); + sr_channel_new(sdi, 1, SR_CHANNEL_ANALOG, TRUE, "CH2"); + + cg = g_malloc0(sizeof(struct sr_channel_group)); + cg->name = g_strdup(""); + cg->channels = g_slist_append(cg->channels, g_slist_nth_data(sdi->channels, 0)); + cg->channels = g_slist_append(cg->channels, g_slist_nth_data(sdi->channels, 1)); + cg->priv = NULL; + sdi->channel_groups = g_slist_append(NULL, cg); + + return sdi; +} - return devices; +static GSList *scan(struct sr_dev_driver *di, GSList *options) +{ + return sr_scpi_scan(di->context, options, probe_device); } static GSList *dev_list(const struct sr_dev_driver *di) @@ -55,9 +106,13 @@ static int dev_clear(const struct sr_dev_driver *di) static int dev_open(struct sr_dev_inst *sdi) { - (void)sdi; + int ret; + struct sr_scpi_dev_inst *scpi = sdi->conn; - /* TODO: get handle from sdi->conn and open it. */ + if ((ret = sr_scpi_open(scpi)) < 0) { + sr_err("Failed to open SCPI device: %s.", sr_strerror(ret)); + return SR_ERR; + } sdi->status = SR_ST_ACTIVE; @@ -66,11 +121,17 @@ static int dev_open(struct sr_dev_inst *sdi) static int dev_close(struct sr_dev_inst *sdi) { - (void)sdi; - - /* TODO: get handle from sdi->conn and close it. */ + struct sr_scpi_dev_inst *scpi; + + if (sdi->status != SR_ST_ACTIVE) + return SR_ERR_DEV_CLOSED; - sdi->status = SR_ST_INACTIVE; + scpi = sdi->conn; + if (scpi) { + if (sr_scpi_close(scpi) < 0) + return SR_ERR; + sdi->status = SR_ST_INACTIVE; + } return SR_OK; } @@ -79,8 +140,6 @@ static int cleanup(const struct sr_dev_driver *di) { dev_clear(di); - /* TODO: free other driver resources, if any. */ - return SR_OK; } @@ -88,14 +147,19 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s const struct sr_channel_group *cg) { int ret; - - (void)sdi; + struct dev_context *devc; + (void)data; (void)cg; + + if (!sdi || !(devc = sdi->priv)) + return SR_ERR_ARG; ret = SR_OK; switch (key) { - /* TODO */ + case SR_CONF_SAMPLERATE: + *data = g_variant_new_uint64(devc->sample_rate); + break; default: return SR_ERR_NA; } @@ -107,16 +171,22 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd const struct sr_channel_group *cg) { int ret; - + struct dev_context *devc; + (void)data; (void)cg; + + if (!sdi || !(devc = sdi->priv)) + return SR_ERR_ARG; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; ret = SR_OK; switch (key) { - /* TODO */ + case SR_CONF_LIMIT_FRAMES: + devc->frame_limit = g_variant_get_uint64(data); + break; default: ret = SR_ERR_NA; } @@ -128,14 +198,20 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst * const struct sr_channel_group *cg) { int ret; - + (void)sdi; - (void)data; (void)cg; - + ret = SR_OK; switch (key) { - /* TODO */ + case SR_CONF_SCAN_OPTIONS: + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t)); + return SR_OK; + case SR_CONF_DEVICE_OPTIONS: + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + devopts, ARRAY_SIZE(devopts), sizeof(uint32_t)); + return SR_OK; default: return SR_ERR_NA; } @@ -146,26 +222,54 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst * static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) { - (void)sdi; + struct sr_scpi_dev_inst *scpi; + struct dev_context *devc; + (void)cb_data; - + + scpi = sdi->conn; + devc = sdi->priv; + if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; - - /* TODO: configure hardware, reset acquisition state, set up - * callbacks and send header packet. */ - + + /* Initialize device context; */ + devc->state = START_AQUISITION; + devc->cur_acq_frame = 0; + + sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 50, + gwinstek_gds_800_receive_data, (void *)sdi); + return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) { + struct sr_scpi_dev_inst *scpi; + struct dev_context *devc; + struct sr_datafeed_packet packet; + (void)cb_data; - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; + scpi = sdi->conn; + devc = sdi->priv; + + if (sdi->status != SR_ST_ACTIVE) { + sr_err("Device inactive, can't stop acquisition."); + return SR_ERR; + } + + if(devc->df_started) { + packet.type = SR_DF_FRAME_END; + sr_session_send(sdi, &packet); + + packet.type = SR_DF_END; + sr_session_send(sdi, &packet); + + devc->df_started = FALSE; + } - /* TODO: stop acquisition. */ + sr_scpi_source_remove(sdi->session, scpi); return SR_OK; } diff --git a/src/hardware/gwinstek-gds-800/protocol.c b/src/hardware/gwinstek-gds-800/protocol.c index 8c5a102..0285703 100644 --- a/src/hardware/gwinstek-gds-800/protocol.c +++ b/src/hardware/gwinstek-gds-800/protocol.c @@ -18,22 +18,270 @@ */ #include "protocol.h" +#include <string.h> + +static int read_data(struct sr_dev_inst *sdi, void *cb_data, struct sr_scpi_dev_inst *scpi, struct dev_context *devc, int data_size) +{ + int len; + + len = sr_scpi_read_data(scpi, &devc->rcv_buffer[devc->cur_rcv_buffer_position], data_size - devc->cur_rcv_buffer_position); + if(len < 0) { + sr_err("Read data error."); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + devc->cur_rcv_buffer_position = 0; + return SR_ERR; + } + + devc->cur_rcv_buffer_position += len; + + /* handle the case where sr_scpi_read_data has stopped at the newline */ + if(len < data_size && sr_scpi_read_complete(scpi)) { + devc->rcv_buffer[devc->cur_rcv_buffer_position] = '\n'; + devc->cur_rcv_buffer_position++; + } + + if(devc->cur_rcv_buffer_position < data_size) + return SR_ERR; //not finished yet + else if(devc->cur_rcv_buffer_position == data_size) { + devc->cur_rcv_buffer_position = 0; + return SR_OK; + } + else { + sr_err("Too many bytes read."); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + devc->cur_rcv_buffer_position = 0; + return SR_ERR; + } +} SR_PRIV int gwinstek_gds_800_receive_data(int fd, int revents, void *cb_data) { - const struct sr_dev_inst *sdi; + struct sr_dev_inst *sdi; + struct sr_scpi_dev_inst *scpi; struct dev_context *devc; - + struct sr_datafeed_packet packet; + struct sr_datafeed_analog analog; + char command[32]; + char *response; + float volts_per_division; + int num_samples, i; + float samples[MAX_SAMPLES]; + uint32_t sample_rate; + char *end_ptr; + (void)fd; - + if (!(sdi = cb_data)) return TRUE; if (!(devc = sdi->priv)) return TRUE; - if (revents == G_IO_IN) { - /* TODO */ + scpi = sdi->conn; + + if (!(revents == G_IO_IN || revents == 0)) + return TRUE; + + switch(devc->state) + { + case START_AQUISITION: + if (sr_scpi_send(scpi, ":TRIG:MOD 3") != SR_OK) { + sr_err("Failed to set trigger mode to SINGLE."); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + if (sr_scpi_send(scpi, ":STOP") != SR_OK) { + sr_err("Failed to put the trigger system into STOP state."); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + if (sr_scpi_send(scpi, ":RUN") != SR_OK) { + sr_err("Failed to put the trigger system into RUN state."); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + + devc->cur_acq_channel = 0; + devc->state = START_TRANSFER_OF_CHANNEL_DATA; + break; + case START_TRANSFER_OF_CHANNEL_DATA: + if(((struct sr_channel*)g_slist_nth_data(sdi->channels, devc->cur_acq_channel))->enabled) { + if (sr_scpi_send(scpi, ":ACQ%d:MEM?", devc->cur_acq_channel+1) != SR_OK) { + sr_err("Failed to acquire memory."); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + if(sr_scpi_read_begin(scpi) != SR_OK) { + sr_err("Could not begin reading SCPI response."); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + devc->state = WAIT_FOR_TRANSFER_OF_BEGIN_TRANSMISSION_COMPLETE; + devc->cur_rcv_buffer_position = 0; + } else { + /* All channels acquired. */ + if(devc->cur_acq_channel == ANALOG_CHANNELS - 1) { + sr_spew("All channels acquired."); + + /* All frames accquired. */ + if(devc->cur_acq_frame == devc->frame_limit - 1) { + sr_spew("All frames acquired."); + + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + /* Start acquiring next frame. */ + else { + if(devc->df_started) { + packet.type = SR_DF_FRAME_END; + sr_session_send(sdi, &packet); + + packet.type = SR_DF_FRAME_BEGIN; + sr_session_send(sdi, &packet); + } + + devc->cur_acq_frame++; + devc->state = START_AQUISITION; + } + } + /* Start acquiring next channel. */ + else + devc->cur_acq_channel++; + } + break; + case WAIT_FOR_TRANSFER_OF_BEGIN_TRANSMISSION_COMPLETE: + if(read_data(sdi, cb_data, scpi, devc, 1) == SR_OK) + { + if(devc->rcv_buffer[0] == '#') + devc->state = WAIT_FOR_TRANSFER_OF_DATA_SIZE_DIGIT_COMPLETE; + } + break; + case WAIT_FOR_TRANSFER_OF_DATA_SIZE_DIGIT_COMPLETE: + if(read_data(sdi, cb_data, scpi, devc, 1) == SR_OK) + { + if(devc->rcv_buffer[0] != '4' && + devc->rcv_buffer[0] != '5' && + devc->rcv_buffer[0] != '6') + { + sr_err("Data size digits is not 4, 5 or 6 but '%c'.", devc->rcv_buffer[0]); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + else + { + devc->data_size_digits = devc->rcv_buffer[0] - '0'; + devc->state = WAIT_FOR_TRANSFER_OF_DATA_SIZE_COMPLETE; + } + } + break; + case WAIT_FOR_TRANSFER_OF_DATA_SIZE_COMPLETE: + if(read_data(sdi, cb_data, scpi, devc, devc->data_size_digits) == SR_OK) + { + devc->rcv_buffer[devc->data_size_digits] = 0; + if(sr_atoi(devc->rcv_buffer, &devc->data_size) != SR_OK) + { + sr_err("Could not parse data size '%s'", devc->rcv_buffer); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + else + devc->state = WAIT_FOR_TRANSFER_OF_SAMPLE_RATE_COMPLETE; + } + break; + case WAIT_FOR_TRANSFER_OF_SAMPLE_RATE_COMPLETE: + if(read_data(sdi, cb_data, scpi, devc, sizeof(float)) == SR_OK) + { + //contrary to the documentation, this field is transfered with most + //significant byte first! + sample_rate = RB32(devc->rcv_buffer); + memcpy(&devc->sample_rate, &sample_rate, sizeof(float)); + devc->state = WAIT_FOR_TRANSFER_OF_CHANNEL_INDICATOR_COMPLETE; + + if(!devc->df_started) { + std_session_send_df_header(sdi, LOG_PREFIX); + + packet.type = SR_DF_FRAME_BEGIN; + sr_session_send(sdi, &packet); + + devc->df_started = TRUE; + } + } + break; + case WAIT_FOR_TRANSFER_OF_CHANNEL_INDICATOR_COMPLETE: + if(read_data(sdi, cb_data, scpi, devc, 1) == SR_OK) + devc->state = WAIT_FOR_TRANSFER_OF_RESERVED_DATA_COMPLETE; + break; + case WAIT_FOR_TRANSFER_OF_RESERVED_DATA_COMPLETE: + if(read_data(sdi, cb_data, scpi, devc, 3) == SR_OK) + devc->state = WAIT_FOR_TRANSFER_OF_CHANNEL_DATA_COMPLETE; + break; + case WAIT_FOR_TRANSFER_OF_CHANNEL_DATA_COMPLETE: + if(read_data(sdi, cb_data, scpi, devc, devc->data_size - 8) == SR_OK) + { + /* Fetch data needed for conversion from device */ + snprintf(command, sizeof(command), ":CHAN%d:SCAL?", devc->cur_acq_channel+1); + if(sr_scpi_get_string(scpi, command, &response) != SR_OK) { + sr_err("Failed to get volts per division."); + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + volts_per_division = g_ascii_strtod(response, &end_ptr); + if(strcmp(end_ptr, "mV") == 0) + volts_per_division *= 1.e-3; + g_free(response); + + num_samples = (devc->data_size - 8) / 2; + sr_spew("Received %d number of samples from channel %d.", num_samples, devc->cur_acq_channel+1); + + /* Convert data */ + for(i = 0; i < num_samples; i++) + samples[i] = ((float) ((int16_t) (RB16(&devc->rcv_buffer[i*2])))) / 256. * VERTICAL_DIVISIONS * volts_per_division; + + /* Fill frame */ + analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, devc->cur_acq_channel)); + analog.num_samples = num_samples; + analog.data = samples; + analog.mq = SR_MQ_VOLTAGE; + analog.unit = SR_UNIT_VOLT; + analog.mqflags = 0; + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + sr_session_send(cb_data, &packet); + g_slist_free(analog.channels); + + /* All channels acquired. */ + if(devc->cur_acq_channel == ANALOG_CHANNELS - 1) { + sr_spew("All channels acquired."); + + /* All frames accquired. */ + if(devc->cur_acq_frame == devc->frame_limit - 1) { + sr_spew("All frames acquired."); + + sdi->driver->dev_acquisition_stop(sdi, cb_data); + return TRUE; + } + /* Start acquiring next frame. */ + else { + if(devc->df_started) { + packet.type = SR_DF_FRAME_END; + sr_session_send(sdi, &packet); + + packet.type = SR_DF_FRAME_BEGIN; + sr_session_send(sdi, &packet); + } + + devc->cur_acq_frame++; + devc->state = START_AQUISITION; + } + } + /* Start acquiring next channel. */ + else { + devc->state = START_TRANSFER_OF_CHANNEL_DATA; + devc->cur_acq_channel++; + return TRUE; + } + } + break; } return TRUE; diff --git a/src/hardware/gwinstek-gds-800/protocol.h b/src/hardware/gwinstek-gds-800/protocol.h index 5ee467f..e312dac 100644 --- a/src/hardware/gwinstek-gds-800/protocol.h +++ b/src/hardware/gwinstek-gds-800/protocol.h @@ -22,21 +22,42 @@ #include <stdint.h> #include <glib.h> -#include "libsigrok.h" +#include <libsigrok/libsigrok.h> #include "libsigrok-internal.h" +#include "scpi.h" #define LOG_PREFIX "gwinstek-gds-800" -/** Private, per-device-instance driver context. */ -struct dev_context { - /* Model-specific information */ - - /* Acquisition settings */ - - /* Operational state */ +#define ANALOG_CHANNELS 2 +#define VERTICAL_DIVISIONS 10 +#define MAX_SAMPLES 125000 +#define MAX_RCV_BUFFER_SIZE (MAX_SAMPLES*2) - /* Temporary state across callbacks */ +enum gds_state +{ + START_AQUISITION, + START_TRANSFER_OF_CHANNEL_DATA, + WAIT_FOR_TRANSFER_OF_BEGIN_TRANSMISSION_COMPLETE, + WAIT_FOR_TRANSFER_OF_DATA_SIZE_DIGIT_COMPLETE, + WAIT_FOR_TRANSFER_OF_DATA_SIZE_COMPLETE, + WAIT_FOR_TRANSFER_OF_SAMPLE_RATE_COMPLETE, + WAIT_FOR_TRANSFER_OF_CHANNEL_INDICATOR_COMPLETE, + WAIT_FOR_TRANSFER_OF_RESERVED_DATA_COMPLETE, + WAIT_FOR_TRANSFER_OF_CHANNEL_DATA_COMPLETE +}; +/** Private, per-device-instance driver context. */ +struct dev_context { + enum gds_state state; + guint64 cur_acq_frame; + guint64 frame_limit; + int cur_acq_channel; + int cur_rcv_buffer_position; + char rcv_buffer[MAX_RCV_BUFFER_SIZE]; + int data_size_digits; + int data_size; + float sample_rate; + gboolean df_started; }; SR_PRIV int gwinstek_gds_800_receive_data(int fd, int revents, void *cb_data); -- 2.3.6
------------------------------------------------------------------------------
_______________________________________________ sigrok-devel mailing list sigrok-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/sigrok-devel