From bb2a4ed407fe2986dce404244b4f2096536e2dac Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Fri, 5 Sep 2014 10:34:04 +0100 Subject: [PATCH] Add GPIB SCPI backend using linux-gpib and libgpib. --- Makefile.am | 4 ++ configure.ac | 8 +++ src/scpi/scpi.c | 4 ++ src/scpi/scpi_gpib.c | 166 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 src/scpi/scpi_gpib.c diff --git a/Makefile.am b/Makefile.am index 73a67b93..f5ccd0e3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -91,6 +91,10 @@ if NEED_VISA libsigrok_la_SOURCES += \ src/scpi/scpi_visa.c endif +if NEED_GPIB +libsigrok_la_SOURCES += \ + src/scpi/scpi_gpib.c +endif # Hardware (DMM chip parsers) libsigrok_la_SOURCES += \ diff --git a/configure.ac b/configure.ac index 798128ef..bd8b7964 100644 --- a/configure.ac +++ b/configure.ac @@ -316,6 +316,14 @@ if test "x$have_librevisa" != "xno"; then [Specifies whether we have librevisa.]) fi +# GPIB backend is only compiled in if libgpib headers found. +AC_CHECK_HEADERS([gpib/ib.h], [LIBS="$LIBS -lgpib"], [have_libgpib="no"]) +AM_CONDITIONAL(NEED_GPIB, test "x$have_libgpib" != xno) +if test "x$have_libgpib" != "xno"; then + AC_DEFINE_UNQUOTED(HAVE_LIBGPIB, [1], + [Specifies whether we have libgpib.]) +fi + # libusb-1.0 is only needed for some hardware drivers. Disable the respective # drivers if it is not found. if test "x$enable_libusb" != "xno"; then diff --git a/src/scpi/scpi.c b/src/scpi/scpi.c index ac7cdb57..84db9dac 100644 --- a/src/scpi/scpi.c +++ b/src/scpi/scpi.c @@ -71,6 +71,7 @@ SR_PRIV extern const struct sr_scpi_dev_inst scpi_tcp_rigol_dev; SR_PRIV extern const struct sr_scpi_dev_inst scpi_usbtmc_libusb_dev; SR_PRIV extern const struct sr_scpi_dev_inst scpi_vxi_dev; SR_PRIV extern const struct sr_scpi_dev_inst scpi_visa_dev; +SR_PRIV extern const struct sr_scpi_dev_inst scpi_gpib_dev; static const struct sr_scpi_dev_inst *scpi_devs[] = { &scpi_tcp_raw_dev, @@ -84,6 +85,9 @@ static const struct sr_scpi_dev_inst *scpi_devs[] = { #ifdef HAVE_LIBREVISA &scpi_visa_dev, #endif +#ifdef HAVE_LIBGPIB + &scpi_gpib_dev, +#endif #ifdef HAVE_LIBSERIALPORT &scpi_serial_dev, /* must be last as it matches any resource */ #endif diff --git a/src/scpi/scpi_gpib.c b/src/scpi/scpi_gpib.c new file mode 100644 index 00000000..06ae1dd2 --- /dev/null +++ b/src/scpi/scpi_gpib.c @@ -0,0 +1,166 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2014 Martin Ling + * + * 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 "libsigrok.h" +#include "libsigrok-internal.h" + +#include +#include + +#define LOG_PREFIX "scpi_gpib" + +struct scpi_gpib { + char *name; + int descriptor; + int read_started; +}; + +static int scpi_gpib_dev_inst_new(void *priv, struct drv_context *drvc, + const char *resource, char **params, const char *serialcomm) +{ + struct scpi_gpib *gscpi = priv; + + (void)drvc; + (void)resource; + (void)serialcomm; + + if (!params || !params[1]) + return SR_ERR; + + gscpi->name = g_strdup(params[1]); + + return SR_OK; +} + +static int scpi_gpib_open(void *priv) +{ + struct scpi_gpib *gscpi = priv; + + if ((gscpi->descriptor = ibfind(gscpi->name)) < 0) + return SR_ERR; + + return SR_OK; +} + +static int scpi_gpib_source_add(struct sr_session *session, void *priv, + int events, int timeout, sr_receive_data_callback cb, void *cb_data) +{ + (void) priv; + + /* Hook up a dummy handler to receive data from the device. */ + return sr_session_source_add(session, -1, events, timeout, cb, cb_data); +} + +static int scpi_gpib_source_remove(struct sr_session *session, void *priv) +{ + (void) priv; + + return sr_session_source_remove(session, -1); +} + +static int scpi_gpib_send(void *priv, const char *command) +{ + struct scpi_gpib *gscpi = priv; + int len = strlen(command); + + ibwrt(gscpi->descriptor, command, len); + + if (ibsta & ERR) + { + sr_err("Error while sending SCPI command: '%s': iberr = %d.", + command, iberr); + return SR_ERR; + } + + if (ibcnt < len) + { + sr_err("Failed to send all of SCPI command: '%s': " + "len = %d, ibcnt = .", command, len, ibcnt); + return SR_ERR; + } + + sr_spew("Successfully sent SCPI command: '%s'.", command); + + return SR_OK; +} + +static int scpi_gpib_read_begin(void *priv) +{ + struct scpi_gpib *gscpi = priv; + + gscpi->read_started = 0; + + return SR_OK; +} + +static int scpi_gpib_read_data(void *priv, char *buf, int maxlen) +{ + struct scpi_gpib *gscpi = priv; + + ibrd(gscpi->descriptor, buf, maxlen); + + if (ibsta & ERR) + { + sr_err("Error while reading SCPI response: iberr = %d.", iberr); + return SR_ERR; + } + + gscpi->read_started = 1; + + return ibcnt; +} + +static int scpi_gpib_read_complete(void *priv) +{ + struct scpi_gpib *gscpi = priv; + + return gscpi->read_started && (ibsta & END); +} + +static int scpi_gpib_close(void *priv) +{ + struct scpi_gpib *gscpi = priv; + + ibonl(gscpi->descriptor, 0); + + return SR_OK; +} + +static void scpi_gpib_free(void *priv) +{ + struct scpi_gpib *gscpi = priv; + + g_free(gscpi->name); +} + +SR_PRIV const struct sr_scpi_dev_inst scpi_gpib_dev = { + .name = "GPIB", + .prefix = "gpib", + .priv_size = sizeof(struct scpi_gpib), + .dev_inst_new = scpi_gpib_dev_inst_new, + .open = scpi_gpib_open, + .source_add = scpi_gpib_source_add, + .source_remove = scpi_gpib_source_remove, + .send = scpi_gpib_send, + .read_begin = scpi_gpib_read_begin, + .read_data = scpi_gpib_read_data, + .read_complete = scpi_gpib_read_complete, + .close = scpi_gpib_close, + .free = scpi_gpib_free, +};