X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=hardware%2Fcommon%2Fscpi.c;h=beb33423934224df8287378a2dad942ccf783162;hb=e22aa87808624c86ec52ea8d57d0a6f35c9e018e;hp=10218ba9820379ebcead81f896e59a019b508270;hpb=504f40a5749b34f2d0932868188e7d94da929be4;p=libsigrok.git diff --git a/hardware/common/scpi.c b/hardware/common/scpi.c index 10218ba9..beb33423 100644 --- a/hardware/common/scpi.c +++ b/hardware/common/scpi.c @@ -22,15 +22,8 @@ #include #include -#include -/* Message logging helpers with subsystem-specific prefix string. */ -#define LOG_PREFIX "scpi: " -#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args) -#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args) -#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args) -#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args) -#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) +#define LOG_PREFIX "scpi" #define SCPI_READ_RETRIES 100 #define SCPI_READ_RETRY_TIMEOUT 10000 @@ -72,6 +65,53 @@ static int parse_strict_bool(const char *str, gboolean *ret) return SR_ERR; } +SR_PRIV extern const struct sr_scpi_dev_inst scpi_serial_dev; +SR_PRIV extern const struct sr_scpi_dev_inst scpi_tcp_raw_dev; +SR_PRIV extern const struct sr_scpi_dev_inst scpi_tcp_rigol_dev; +SR_PRIV extern const struct sr_scpi_dev_inst scpi_usbtmc_dev; +SR_PRIV extern const struct sr_scpi_dev_inst scpi_vxi_dev; + +static const struct sr_scpi_dev_inst *scpi_devs[] = { + &scpi_tcp_raw_dev, + &scpi_tcp_rigol_dev, + &scpi_usbtmc_dev, +#ifdef HAVE_RPC + &scpi_vxi_dev, +#endif +#ifdef HAVE_LIBSERIALPORT + &scpi_serial_dev, /* must be last as it matches any resource */ +#endif +}; + +SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(const char *resource, + const char *serialcomm) +{ + struct sr_scpi_dev_inst *scpi = NULL; + const struct sr_scpi_dev_inst *scpi_dev; + gchar **params; + unsigned i; + + for (i = 0; i < ARRAY_SIZE(scpi_devs); i++) { + scpi_dev = scpi_devs[i]; + if (!strncmp(resource, scpi_dev->prefix, strlen(scpi_dev->prefix))) { + sr_dbg("Opening %s device %s.", scpi_dev->name, resource); + scpi = g_malloc(sizeof(*scpi)); + *scpi = *scpi_dev; + scpi->priv = g_malloc0(scpi->priv_size); + params = g_strsplit(resource, "/", 0); + if (scpi->dev_inst_new(scpi->priv, resource, + params, serialcomm) != SR_OK) { + sr_scpi_free(scpi); + scpi = NULL; + } + g_strfreev(params); + break; + } + } + + return scpi; +} + /** * Open SCPI device. * @@ -127,22 +167,40 @@ SR_PRIV int sr_scpi_source_remove(struct sr_scpi_dev_inst *scpi) SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi, const char *format, ...) { - va_list args1, args2; + va_list args; + int ret; + + va_start(args, format); + ret = sr_scpi_send_variadic(scpi, format, args); + va_end(args); + + return ret; +} + +/** + * Send a SCPI command with a variadic argument list. + * + * @param scpi Previously initialized SCPI device structure. + * @param format Format string. + * @param args Argument list. + * + * @return SR_OK on success, SR_ERR on failure. + */ +SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi, + const char *format, va_list args) +{ + va_list args_copy; char *buf; int len, ret; - /* Copy arguments since we need to make two variadic calls. */ - va_start(args1, format); - va_copy(args2, args1); - /* Get length of buffer required. */ - len = vsnprintf(NULL, 0, format, args1); - va_end(args1); + va_copy(args_copy, args); + len = vsnprintf(NULL, 0, format, args_copy); + va_end(args_copy); /* Allocate buffer and write out command. */ buf = g_malloc(len + 1); - vsprintf(buf, format, args2); - va_end(args2); + vsprintf(buf, format, args); /* Send command. */ ret = scpi->send(scpi->priv, buf); @@ -154,20 +212,15 @@ SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi, } /** - * Receive an SCPI reply and store the reply in scpi_response. + * Begin receiving an SCPI reply. * * @param scpi Previously initialised SCPI device structure. - * @param scpi_response Pointer where to store the SCPI response. * - * @return SR_OK upon fetching a full SCPI response, SR_ERR upon fetching an - * incomplete or no response. The allocated response must be freed by - * the caller in the case of a full response as well in the case of - * an incomplete. + * @return SR_OK on success, SR_ERR on failure. */ -SR_PRIV int sr_scpi_receive(struct sr_scpi_dev_inst *scpi, - char **scpi_response) +SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi) { - return scpi->receive(scpi->priv, scpi_response); + return scpi->read_begin(scpi->priv); } /** @@ -179,10 +232,22 @@ SR_PRIV int sr_scpi_receive(struct sr_scpi_dev_inst *scpi, * * @return Number of bytes read, or SR_ERR upon failure. */ -SR_PRIV int sr_scpi_read(struct sr_scpi_dev_inst *scpi, +SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi, char *buf, int maxlen) { - return scpi->read(scpi->priv, buf, maxlen); + return scpi->read_data(scpi->priv, buf, maxlen); +} + +/** + * Check whether a complete SCPI response has been received. + * + * @param scpi Previously initialised SCPI device structure. + * + * @return 1 if complete, 0 otherwise. + */ +SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi) +{ + return scpi->read_complete(scpi->priv); } /** @@ -207,6 +272,7 @@ SR_PRIV int sr_scpi_close(struct sr_scpi_dev_inst *scpi) SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi) { scpi->free(scpi->priv); + g_free(scpi->priv); g_free(scpi); } @@ -217,19 +283,39 @@ SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi) * @param command The SCPI command to send to the device (can be NULL). * @param scpi_response Pointer where to store the SCPI response. * - * @return SR_OK upon fetching a full SCPI response, SR_ERR upon fetching an - * incomplete or no response. The allocated response must be freed by - * the caller in the case of a full response as well in the case of - * an incomplete. + * @return SR_OK on success, SR_ERR on failure. */ SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi, const char *command, char **scpi_response) { + char buf[256]; + int len; + GString *response; + if (command) if (sr_scpi_send(scpi, command) != SR_OK) return SR_ERR; - return sr_scpi_receive(scpi, scpi_response); + if (sr_scpi_read_begin(scpi) != SR_OK) + return SR_ERR; + + response = g_string_new(""); + + *scpi_response = NULL; + + while (!sr_scpi_read_complete(scpi)) { + len = sr_scpi_read_data(scpi, buf, sizeof(buf)); + if (len < 0) { + g_string_free(response, TRUE); + return SR_ERR; + } + g_string_append_len(response, buf, len); + } + + *scpi_response = response->str; + g_string_free(response, FALSE); + + return SR_OK; } /** @@ -514,6 +600,7 @@ SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi, { int num_tokens; char *response; + char *newline; gchar **tokens; struct sr_scpi_hw_info *hw_info; @@ -524,6 +611,12 @@ SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi, if (!response) return SR_ERR; + sr_info("Got IDN string: '%s'", response); + + /* Remove trailing newline if present. */ + if ((newline = g_strrstr(response, "\n"))) + newline[0] = '\0'; + /* * The response to a '*IDN?' is specified by the SCPI spec. It contains * a comma-separated list containing the manufacturer name, instrument