From: Bert Vermeulen Date: Sun, 16 Aug 2015 13:12:34 +0000 (+0200) Subject: scpi: Make helper functions from scpi-pps available library-wide. X-Git-Tag: libsigrok-0.4.0~397 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=91ef511db2370904f8765a13e315fbddaf5ffe07;p=libsigrok.git scpi: Make helper functions from scpi-pps available library-wide. --- diff --git a/Makefile.am b/Makefile.am index 95190567..c6f61a15 100644 --- a/Makefile.am +++ b/Makefile.am @@ -92,6 +92,7 @@ libsigrok_la_SOURCES += \ # SCPI support libsigrok_la_SOURCES += \ src/scpi/scpi.c \ + src/scpi/helpers.c \ src/scpi/scpi_tcp.c if NEED_RPC libsigrok_la_SOURCES += \ diff --git a/src/hardware/scpi-pps/api.c b/src/hardware/scpi-pps/api.c index e2c15ac8..58e14f6e 100644 --- a/src/hardware/scpi-pps/api.c +++ b/src/hardware/scpi-pps/api.c @@ -19,6 +19,7 @@ #include #include +#include "scpi.h" #include "protocol.h" SR_PRIV struct sr_dev_driver scpi_pps_driver_info; @@ -72,7 +73,7 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi) device = NULL; for (i = 0; i < num_pps_profiles; i++) { - vendor = get_vendor(hw_info->manufacturer); + vendor = sr_vendor_alias(hw_info->manufacturer); if (strcasecmp(vendor, pps_profiles[i].vendor)) continue; model_re = g_regex_new(pps_profiles[i].model, 0, 0, NULL); @@ -128,7 +129,7 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi) for (ch_num = 0; ch_num < num_channels; ch_num++) { /* Create one channel per measurable output unit. */ for (i = 0; i < ARRAY_SIZE(pci); i++) { - if (!scpi_cmd_get(sdi, pci[i].command)) + if (!scpi_cmd_get(devc->device->commands, pci[i].command)) continue; g_snprintf(ch_name, 16, "%s%s", pci[i].prefix, channels[ch_num].name); @@ -165,7 +166,7 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi) sr_scpi_hw_info_free(hw_info); hw_info = NULL; - scpi_cmd(sdi, SCPI_CMD_LOCAL); + scpi_cmd(sdi, devc->device->commands, SCPI_CMD_LOCAL); sr_scpi_close(scpi); return sdi; @@ -201,13 +202,15 @@ static int dev_open(struct sr_dev_inst *sdi) sdi->status = SR_ST_ACTIVE; - scpi_cmd(sdi, SCPI_CMD_REMOTE); + devc = sdi->priv; + scpi_cmd(sdi, devc->device->commands, SCPI_CMD_REMOTE); devc = sdi->priv; devc->beeper_was_set = FALSE; - if (scpi_cmd_resp(sdi, &beeper, G_VARIANT_TYPE_BOOLEAN, SCPI_CMD_BEEPER) == SR_OK) { + if (scpi_cmd_resp(sdi, devc->device->commands, &beeper, + G_VARIANT_TYPE_BOOLEAN, SCPI_CMD_BEEPER) == SR_OK) { if (g_variant_get_boolean(beeper)) { devc->beeper_was_set = TRUE; - scpi_cmd(sdi, SCPI_CMD_BEEPER_DISABLE); + scpi_cmd(sdi, devc->device->commands, SCPI_CMD_BEEPER_DISABLE); } g_variant_unref(beeper); } @@ -227,8 +230,8 @@ static int dev_close(struct sr_dev_inst *sdi) scpi = sdi->conn; if (scpi) { if (devc->beeper_was_set) - scpi_cmd(sdi, SCPI_CMD_BEEPER_ENABLE); - scpi_cmd(sdi, SCPI_CMD_LOCAL); + scpi_cmd(sdi, devc->device->commands, SCPI_CMD_BEEPER_ENABLE); + scpi_cmd(sdi, devc->device->commands, SCPI_CMD_LOCAL); sr_scpi_close(scpi); sdi->status = SR_ST_INACTIVE; } @@ -258,6 +261,7 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s const GVariantType *gvtype; unsigned int i; int cmd, ret; + char *s; if (!sdi) return SR_ERR_ARG; @@ -347,12 +351,33 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s gvtype = G_VARIANT_TYPE_STRING; cmd = SCPI_CMD_GET_OUTPUT_REGULATION; } - if (gvtype) { - if (cg) - select_channel(sdi, cg->channels->data); - ret = scpi_cmd_resp(sdi, data, gvtype, cmd); - } else - ret = SR_ERR_NA; + if (!gvtype) + return SR_ERR_NA; + + if (cg) + select_channel(sdi, cg->channels->data); + ret = scpi_cmd_resp(sdi, devc->device->commands, data, gvtype, cmd); + + if (cmd == SCPI_CMD_GET_OUTPUT_REGULATION) { + /* + * The Rigol DP800 series return CV/CC/UR, Philips PM2800 + * return VOLT/CURR. We always return a GVariant string in + * the Rigol notation. + */ + if ((ret = sr_scpi_get_string(sdi->conn, NULL, &s)) != SR_OK) + return ret; + if (!strcmp(s, "CV") || !strcmp(s, "VOLT")) { + *data = g_variant_new_string("CV"); + } else if (!strcmp(s, "CC") || !strcmp(s, "CURR")) { + *data = g_variant_new_string("CC"); + } else if (!strcmp(s, "UR")) { + *data = g_variant_new_string("UR"); + } else { + sr_dbg("Unknown response to SCPI_CMD_GET_OUTPUT_REGULATION: %s", s); + ret = SR_ERR_DATA; + } + g_free(s); + } return ret; } @@ -360,6 +385,7 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { + struct dev_context *devc; double d; int ret; @@ -373,51 +399,65 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd /* Channel group specified. */ select_channel(sdi, cg->channels->data); + devc = sdi->priv; ret = SR_OK; switch (key) { case SR_CONF_ENABLED: if (g_variant_get_boolean(data)) - ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_ENABLE); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OUTPUT_ENABLE); else - ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_DISABLE); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OUTPUT_DISABLE); break; case SR_CONF_VOLTAGE_TARGET: d = g_variant_get_double(data); - ret = scpi_cmd(sdi, SCPI_CMD_SET_VOLTAGE_TARGET, d); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_VOLTAGE_TARGET, d); break; case SR_CONF_OUTPUT_FREQUENCY_TARGET: d = g_variant_get_double(data); - ret = scpi_cmd(sdi, SCPI_CMD_SET_FREQUENCY_TARGET, d); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_FREQUENCY_TARGET, d); break; case SR_CONF_CURRENT_LIMIT: d = g_variant_get_double(data); - ret = scpi_cmd(sdi, SCPI_CMD_SET_CURRENT_LIMIT, d); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_CURRENT_LIMIT, d); break; case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED: if (g_variant_get_boolean(data)) - ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_ENABLE); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_ENABLE); else - ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_DISABLE); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_DISABLE); break; case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD: d = g_variant_get_double(data); - ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, d); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, d); break; case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED: if (g_variant_get_boolean(data)) - ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLE); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLE); else - ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE); break; case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD: d = g_variant_get_double(data); - ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD, d); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD, d); break; case SR_CONF_OVER_TEMPERATURE_PROTECTION: if (g_variant_get_boolean(data)) - ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_ENABLE); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_ENABLE); else - ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_DISABLE); + ret = scpi_cmd(sdi, devc->device->commands, + SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_DISABLE); break; default: ret = SR_ERR_NA; @@ -536,8 +576,7 @@ static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst * return ret; } -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) { struct dev_context *devc; struct sr_scpi_dev_inst *scpi; @@ -572,7 +611,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, cmd = SCPI_CMD_GET_MEAS_POWER; else return SR_ERR; - scpi_cmd(sdi, cmd, pch->hwname); + scpi_cmd(sdi, devc->device->commands, cmd, pch->hwname); return SR_OK; } diff --git a/src/hardware/scpi-pps/profiles.c b/src/hardware/scpi-pps/profiles.c index c8c7e372..cc5c0ce3 100644 --- a/src/hardware/scpi-pps/profiles.c +++ b/src/hardware/scpi-pps/profiles.c @@ -26,27 +26,6 @@ #define CH_IDX(x) (1 << x) #define FREQ_DC_ONLY {0, 0, 0} -static const char *pps_vendors[][2] = { - { "RIGOL TECHNOLOGIES", "Rigol" }, - { "HEWLETT-PACKARD", "HP" }, - { "PHILIPS", "Philips" }, - { "CHROMA", "Chroma" }, - { "Chroma ATE", "Chroma" }, - { "Agilent Technologies", "Agilent" }, -}; - -SR_PRIV const char *get_vendor(const char *raw_vendor) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(pps_vendors); i++) { - if (!strcasecmp(raw_vendor, pps_vendors[i][0])) - return pps_vendors[i][1]; - } - - return raw_vendor; -} - static const uint32_t devopts_none[] = { }; /* Agilent/Keysight N5700A series */ @@ -96,6 +75,7 @@ static const struct scpi_command agilent_n5700a_cmd[] = { /* Current limit (CC mode) and OCP are set using the same command. */ { SCPI_CMD_GET_OVER_CURRENT_PROTECTION_THRESHOLD, ":SOUR:CURR?" }, { SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD, ":SOUR:CURR %.6f" }, + ALL_ZERO }; /* Chroma 61600 series AC source */ @@ -141,6 +121,7 @@ static const struct scpi_command chroma_61604_cmd[] = { /* This is not a current limit mode. It is overcurrent protection. */ { SCPI_CMD_GET_OVER_CURRENT_PROTECTION_THRESHOLD, ":SOUR:CURR:LIM?" }, { SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD, ":SOUR:CURR:LIM %.2f" }, + ALL_ZERO }; /* Chroma 62000 series DC source */ @@ -183,6 +164,7 @@ static const struct scpi_command chroma_62000_cmd[] = { { SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":SOUR:VOLT:PROT:HIGH %.6f" }, { SCPI_CMD_GET_OVER_CURRENT_PROTECTION_THRESHOLD, ":SOUR:CURR:PROT:HIGH?" }, { SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD, ":SOUR:CURR:PROT:HIGH %.6f" }, + ALL_ZERO }; static int chroma_62000p_probe_channels(struct sr_dev_inst *sdi, @@ -307,6 +289,7 @@ static const struct scpi_command rigol_dp800_cmd[] = { { SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE, ":OUTP:OCP:QUES?" }, { SCPI_CMD_GET_OVER_CURRENT_PROTECTION_THRESHOLD, ":OUTP:OCP:VAL?" }, { SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD, ":OUTP:OCP:VAL %.6f" }, + ALL_ZERO }; /* HP 663xx series */ @@ -337,6 +320,7 @@ static const struct scpi_command hp_6632b_cmd[] = { { SCPI_CMD_SET_VOLTAGE_TARGET, ":SOUR:VOLT %.6f" }, { SCPI_CMD_GET_CURRENT_LIMIT, ":SOUR:CURR?" }, { SCPI_CMD_SET_CURRENT_LIMIT, ":SOUR:CURR %.6f" }, + ALL_ZERO }; /* Philips/Fluke PM2800 series */ @@ -483,6 +467,7 @@ static const struct scpi_command philips_pm2800_cmd[] = { { SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLE, ":SOUR:CURR:PROT:STAT ON" }, { SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE, ":SOUR:CURR:PROT:STAT OFF" }, { SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE, ":SOUR:CURR:PROT:TRIP?" }, + ALL_ZERO }; SR_PRIV const struct scpi_pps pps_profiles[] = { @@ -492,7 +477,7 @@ SR_PRIV const struct scpi_pps pps_profiles[] = { ARRAY_AND_SIZE(agilent_n5700a_devopts_cg), ARRAY_AND_SIZE(agilent_n5767a_ch), ARRAY_AND_SIZE(agilent_n5767a_cg), - ARRAY_AND_SIZE(agilent_n5700a_cmd), + agilent_n5700a_cmd, .probe_channels = NULL, }, /* Chroma 61604 */ @@ -501,7 +486,7 @@ SR_PRIV const struct scpi_pps pps_profiles[] = { ARRAY_AND_SIZE(chroma_61604_devopts_cg), ARRAY_AND_SIZE(chroma_61604_ch), ARRAY_AND_SIZE(chroma_61604_cg), - ARRAY_AND_SIZE(chroma_61604_cmd), + chroma_61604_cmd, .probe_channels = NULL, }, /* Chroma 62000 series */ @@ -510,7 +495,7 @@ SR_PRIV const struct scpi_pps pps_profiles[] = { ARRAY_AND_SIZE(chroma_62000_devopts_cg), NULL, 0, NULL, 0, - ARRAY_AND_SIZE(chroma_62000_cmd), + chroma_62000_cmd, .probe_channels = chroma_62000p_probe_channels, }, /* HP 6632B */ @@ -519,7 +504,7 @@ SR_PRIV const struct scpi_pps pps_profiles[] = { ARRAY_AND_SIZE(devopts_none), ARRAY_AND_SIZE(hp_6632b_ch), ARRAY_AND_SIZE(hp_6632b_cg), - ARRAY_AND_SIZE(hp_6632b_cmd), + hp_6632b_cmd, .probe_channels = NULL, }, @@ -529,7 +514,7 @@ SR_PRIV const struct scpi_pps pps_profiles[] = { ARRAY_AND_SIZE(rigol_dp800_devopts_cg), ARRAY_AND_SIZE(rigol_dp821a_ch), ARRAY_AND_SIZE(rigol_dp820_cg), - ARRAY_AND_SIZE(rigol_dp800_cmd), + rigol_dp800_cmd, .probe_channels = NULL, }, { "Rigol", "^DP831A$", PPS_OTP, @@ -537,7 +522,7 @@ SR_PRIV const struct scpi_pps pps_profiles[] = { ARRAY_AND_SIZE(rigol_dp800_devopts_cg), ARRAY_AND_SIZE(rigol_dp831_ch), ARRAY_AND_SIZE(rigol_dp830_cg), - ARRAY_AND_SIZE(rigol_dp800_cmd), + rigol_dp800_cmd, .probe_channels = NULL, }, { "Rigol", "^(DP832|DP832A)$", PPS_OTP, @@ -545,7 +530,7 @@ SR_PRIV const struct scpi_pps pps_profiles[] = { ARRAY_AND_SIZE(rigol_dp800_devopts_cg), ARRAY_AND_SIZE(rigol_dp832_ch), ARRAY_AND_SIZE(rigol_dp830_cg), - ARRAY_AND_SIZE(rigol_dp800_cmd), + rigol_dp800_cmd, .probe_channels = NULL, }, @@ -555,7 +540,7 @@ SR_PRIV const struct scpi_pps pps_profiles[] = { ARRAY_AND_SIZE(philips_pm2800_devopts_cg), NULL, 0, NULL, 0, - ARRAY_AND_SIZE(philips_pm2800_cmd), + philips_pm2800_cmd, philips_pm2800_probe_channels, }, }; diff --git a/src/hardware/scpi-pps/protocol.c b/src/hardware/scpi-pps/protocol.c index a27089f5..c4b73add 100644 --- a/src/hardware/scpi-pps/protocol.c +++ b/src/hardware/scpi-pps/protocol.c @@ -20,112 +20,9 @@ #include #include #include +#include "scpi.h" #include "protocol.h" -SR_PRIV const char *scpi_cmd_get(const struct sr_dev_inst *sdi, int command) -{ - struct dev_context *devc; - unsigned int i; - const char *cmd; - - devc = sdi->priv; - cmd = NULL; - for (i = 0; i < devc->device->num_commands; i++) { - if (devc->device->commands[i].command == command) { - cmd = devc->device->commands[i].string; - break; - } - } - - return cmd; -} - -SR_PRIV int scpi_cmd(const struct sr_dev_inst *sdi, int command, ...) -{ - struct sr_scpi_dev_inst *scpi; - va_list args; - int ret; - const char *cmd; - - if (!(cmd = scpi_cmd_get(sdi, command))) { - /* Device does not implement this command, that's OK. */ - return SR_OK_CONTINUE; - } - - scpi = sdi->conn; - va_start(args, command); - ret = sr_scpi_send_variadic(scpi, cmd, args); - va_end(args); - - return ret; -} - -SR_PRIV int scpi_cmd_resp(const struct sr_dev_inst *sdi, GVariant **gvar, - const GVariantType *gvtype, int command, ...) -{ - struct sr_scpi_dev_inst *scpi; - va_list args; - double d; - int ret; - char *s; - const char *cmd; - - if (!(cmd = scpi_cmd_get(sdi, command))) { - /* Device does not implement this command, that's OK. */ - return SR_OK_CONTINUE; - } - - scpi = sdi->conn; - va_start(args, command); - ret = sr_scpi_send_variadic(scpi, cmd, args); - va_end(args); - if (ret != SR_OK) - return ret; - - /* Non-standard data type responses. */ - if (command == SCPI_CMD_GET_OUTPUT_REGULATION) { - /* - * The Rigol DP800 series return CV/CC/UR, Philips PM2800 - * return VOLT/CURR. We always return a GVariant string in - * the Rigol notation. - */ - if ((ret = sr_scpi_get_string(scpi, NULL, &s)) != SR_OK) - return ret; - if (!strcmp(s, "CV") || !strcmp(s, "VOLT")) { - *gvar = g_variant_new_string("CV"); - } else if (!strcmp(s, "CC") || !strcmp(s, "CURR")) { - *gvar = g_variant_new_string("CC"); - } else if (!strcmp(s, "UR")) { - *gvar = g_variant_new_string("UR"); - } else { - sr_dbg("Unknown response to SCPI_CMD_GET_OUTPUT_REGULATION: %s", s); - ret = SR_ERR_DATA; - } - g_free(s); - } else { - /* Straight SCPI getters to GVariant types. */ - if (g_variant_type_equal(gvtype, G_VARIANT_TYPE_BOOLEAN)) { - if ((ret = sr_scpi_get_string(scpi, NULL, &s)) != SR_OK) - return ret; - if (!strcasecmp(s, "ON") || !strcasecmp(s, "1") || !strcasecmp(s, "YES")) - *gvar = g_variant_new_boolean(TRUE); - else if (!strcasecmp(s, "OFF") || !strcasecmp(s, "0") || !strcasecmp(s, "NO")) - *gvar = g_variant_new_boolean(FALSE); - else - ret = SR_ERR; - g_free(s); - } if (g_variant_type_equal(gvtype, G_VARIANT_TYPE_DOUBLE)) { - if ((ret = sr_scpi_get_double(scpi, NULL, &d)) == SR_OK) - *gvar = g_variant_new_double(d); - } if (g_variant_type_equal(gvtype, G_VARIANT_TYPE_STRING)) { - if ((ret = sr_scpi_get_string(scpi, NULL, &s)) == SR_OK) - *gvar = g_variant_new_string(s); - } - } - - return ret; -} - SR_PRIV int select_channel(const struct sr_dev_inst *sdi, struct sr_channel *ch) { struct dev_context *devc; @@ -149,7 +46,8 @@ SR_PRIV int select_channel(const struct sr_dev_inst *sdi, struct sr_channel *ch) } } - if ((ret = scpi_cmd(sdi, SCPI_CMD_SELECT_CHANNEL, new_pch->hwname)) >= 0) + if ((ret = scpi_cmd(sdi, devc->device->commands, SCPI_CMD_SELECT_CHANNEL, + new_pch->hwname)) >= 0) devc->cur_channel = ch; return ret; @@ -235,7 +133,7 @@ SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data) cmd = SCPI_CMD_GET_MEAS_POWER; else return SR_ERR; - scpi_cmd(sdi, cmd); + scpi_cmd(sdi, devc->device->commands, cmd); return TRUE; } diff --git a/src/hardware/scpi-pps/protocol.h b/src/hardware/scpi-pps/protocol.h index 063fddc1..77589245 100644 --- a/src/hardware/scpi-pps/protocol.h +++ b/src/hardware/scpi-pps/protocol.h @@ -24,6 +24,7 @@ #include #include #include "libsigrok-internal.h" +#include "scpi.h" #define LOG_PREFIX "scpi-pps" @@ -92,7 +93,6 @@ struct scpi_pps { const struct channel_group_spec *channel_groups; unsigned int num_channel_groups; const struct scpi_command *commands; - unsigned int num_commands; int (*probe_channels) (struct sr_dev_inst *sdi, struct sr_scpi_hw_info *hwinfo, struct channel_spec **channels, unsigned int *num_channels, struct channel_group_spec **channel_groups, unsigned int *num_channel_groups); @@ -106,11 +106,6 @@ struct channel_spec { float frequency[3]; }; -struct scpi_command { - int command; - const char *string; -}; - struct channel_group_spec { const char *name; uint64_t channel_index_mask; @@ -160,10 +155,6 @@ SR_PRIV extern unsigned int num_pps_profiles; SR_PRIV extern const struct scpi_pps pps_profiles[]; SR_PRIV const char *get_vendor(const char *raw_vendor); -SR_PRIV const char *scpi_cmd_get(const struct sr_dev_inst *sdi, int command); -SR_PRIV int scpi_cmd(const struct sr_dev_inst *sdi, int command, ...); -SR_PRIV int scpi_cmd_resp(const struct sr_dev_inst *sdi, GVariant **gvar, - const GVariantType *gvtype, int command, ...); SR_PRIV int select_channel(const struct sr_dev_inst *sdi, struct sr_channel *ch); SR_PRIV struct sr_channel *next_enabled_channel(const struct sr_dev_inst *sdi, struct sr_channel *cur_channel); diff --git a/src/scpi.h b/src/scpi.h index 36bc1627..28b33287 100644 --- a/src/scpi.h +++ b/src/scpi.h @@ -58,6 +58,11 @@ enum { SCPI_CMD_GET_SAMPLE_RATE_LIVE, }; +struct scpi_command { + int command; + const char *string; +}; + struct sr_scpi_hw_info { char *manufacturer; char *model; @@ -125,4 +130,12 @@ SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi, struct sr_scpi_hw_info **scpi_response); SR_PRIV void sr_scpi_hw_info_free(struct sr_scpi_hw_info *hw_info); +SR_PRIV const char *sr_vendor_alias(const char *raw_vendor); +SR_PRIV const char *scpi_cmd_get(const struct scpi_command *cmdtable, int command); +SR_PRIV int scpi_cmd(const struct sr_dev_inst *sdi, + const struct scpi_command *cmdtable, int command, ...); +SR_PRIV int scpi_cmd_resp(const struct sr_dev_inst *sdi, + const struct scpi_command *cmdtable, + GVariant **gvar, const GVariantType *gvtype, int command, ...); + #endif diff --git a/src/scpi/helpers.c b/src/scpi/helpers.c new file mode 100644 index 00000000..d93d9e24 --- /dev/null +++ b/src/scpi/helpers.c @@ -0,0 +1,136 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2015 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 "libsigrok-internal.h" +#include "scpi.h" + +#define LOG_PREFIX "scpi/helpers" + +static const char *scpi_vendors[][2] = { + { "HEWLETT-PACKARD", "HP" }, + { "Agilent Technologies", "Agilent" }, + { "RIGOL TECHNOLOGIES", "Rigol" }, + { "PHILIPS", "Philips" }, + { "CHROMA", "Chroma" }, + { "Chroma ATE", "Chroma" }, +}; + +SR_PRIV const char *sr_vendor_alias(const char *raw_vendor) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(scpi_vendors); i++) { + if (!strcasecmp(raw_vendor, scpi_vendors[i][0])) + return scpi_vendors[i][1]; + } + + return raw_vendor; +} + +SR_PRIV const char *scpi_cmd_get(const struct scpi_command *cmdtable, int command) +{ + unsigned int i; + const char *cmd; + + if (!cmdtable) + return NULL; + + cmd = NULL; + for (i = 0; cmdtable[i].command; i++) { + if (cmdtable[i].command == command) { + cmd = cmdtable[i].string; + break; + } + } + + return cmd; +} + +SR_PRIV int scpi_cmd(const struct sr_dev_inst *sdi, const struct scpi_command *cmdtable, + int command, ...) +{ + struct sr_scpi_dev_inst *scpi; + va_list args; + int ret; + const char *cmd; + + if (!(cmd = scpi_cmd_get(cmdtable, command))) { + /* Device does not implement this command, that's OK. */ + /* TODO: deprecate SR_OK_CONTINUE */ + return SR_OK_CONTINUE; + } + + scpi = sdi->conn; + va_start(args, command); + ret = sr_scpi_send_variadic(scpi, cmd, args); + va_end(args); + + return ret; +} + +SR_PRIV int scpi_cmd_resp(const struct sr_dev_inst *sdi, const struct scpi_command *cmdtable, + GVariant **gvar, const GVariantType *gvtype, int command, ...) +{ + struct sr_scpi_dev_inst *scpi; + va_list args; + double d; + int ret; + char *s; + const char *cmd; + + if (!(cmd = scpi_cmd_get(cmdtable, command))) { + /* Device does not implement this command, that's OK. */ + return SR_OK_CONTINUE; + } + + scpi = sdi->conn; + va_start(args, command); + ret = sr_scpi_send_variadic(scpi, cmd, args); + va_end(args); + if (ret != SR_OK) + return ret; + + /* Straight SCPI getters to GVariant types. */ + if (g_variant_type_equal(gvtype, G_VARIANT_TYPE_BOOLEAN)) { + if ((ret = sr_scpi_get_string(scpi, NULL, &s)) != SR_OK) + return ret; + if (!strcasecmp(s, "ON") || !strcasecmp(s, "1") + || !strcasecmp(s, "YES")) + *gvar = g_variant_new_boolean(TRUE); + else if (!strcasecmp(s, "OFF") || !strcasecmp(s, "0") + || !strcasecmp(s, "NO")) + *gvar = g_variant_new_boolean(FALSE); + else + ret = SR_ERR; + g_free(s); + } if (g_variant_type_equal(gvtype, G_VARIANT_TYPE_DOUBLE)) { + if ((ret = sr_scpi_get_double(scpi, NULL, &d)) == SR_OK) + *gvar = g_variant_new_double(d); + } if (g_variant_type_equal(gvtype, G_VARIANT_TYPE_STRING)) { + if ((ret = sr_scpi_get_string(scpi, NULL, &s)) == SR_OK) + *gvar = g_variant_new_string(s); + } else { + sr_err("Unable to convert to desired GVariant type."); + ret = SR_ERR_NA; + } + + return ret; +}