* 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)
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;
+ 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;
+ }
- devices = NULL;
- drvc = di->context;
- drvc->instances = 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;
+ }
- /* TODO: scan for devices, either based on a SR_CONF_CONN option
- * or on a USB scan. */
+ 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)
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;
static int dev_close(struct sr_dev_inst *sdi)
{
- (void)sdi;
+ struct sr_scpi_dev_inst *scpi;
- /* TODO: get handle from sdi->conn and close it. */
+ 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;
}
{
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;
+ struct dev_context *devc;
- (void)sdi;
- (void)data;
(void)cg;
- ret = SR_OK;
+ if (!sdi || !(devc = sdi->priv))
+ return SR_ERR_ARG;
+
switch (key) {
- /* TODO */
+ case SR_CONF_SAMPLERATE:
+ *data = g_variant_new_uint64(devc->sample_rate);
+ break;
default:
return SR_ERR_NA;
}
- return ret;
+ return SR_OK;
}
static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
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;
+ return SR_ERR_NA;
}
- return ret;
+ return SR_OK;
}
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 */
+ 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;
}
- return ret;
+ return SR_OK;
}
-static int dev_acquisition_start(const struct sr_dev_inst *sdi,
- void *cb_data)
+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. */
+ devc->state = START_ACQUISITION;
+ 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;
}
SR_PRIV struct sr_dev_driver gwinstek_gds_800_driver_info = {
.name = "gwinstek-gds-800",
- .longname = "gwinstek gds-800",
+ .longname = "GW Instek GDS-800 series",
.api_version = 1,
.init = init,
.cleanup = cleanup,
*/
#include "protocol.h"
+#include <string.h>
+
+#define ANALOG_CHANNELS 2
+#define VERTICAL_DIVISIONS 10
+
+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 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 (!(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_ACQUISITION:
+ 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.");
+
+ if (devc->cur_acq_frame == devc->frame_limit - 1) {
+ /* All frames accquired. */
+ sr_spew("All frames acquired.");
+
+ sdi->driver->dev_acquisition_stop(sdi, cb_data);
+ return TRUE;
+ } else {
+ /* Start acquiring next frame. */
+ 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_ACQUISITION;
+ }
+ } else {
+ /* Start acquiring next channel. */
+ 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"))
+ 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.");
+
+ if (devc->cur_acq_frame == devc->frame_limit - 1) {
+ /* All frames acquired. */
+ sr_spew("All frames acquired.");
+ sdi->driver->dev_acquisition_stop(sdi, cb_data);
+ return TRUE;
+ } else {
+ /* Start acquiring next frame. */
+ 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_ACQUISITION;
+ }
+ } else {
+ /* Start acquiring next channel. */
+ devc->state = START_TRANSFER_OF_CHANNEL_DATA;
+ devc->cur_acq_channel++;
+ return TRUE;
+ }
+ }
+ break;
}
return TRUE;