scpi-dmm: add support to get/set range on Agilent protocol using meters
Add support to get and set the auto/manual range on Agilent protocol speaking devices (34405A, 34465A). The range values are mere numbers without a unit or MQ associated with them. Support to list available ranges is prepared but not used (not needed on these meters). Common logic could open code the lists of ranges from the model description if desired in a future implementation.
This commit is contained in:
parent
7fcdc35e17
commit
a0418c20d8
|
@ -39,6 +39,15 @@ static const uint32_t devopts_generic[] = {
|
|||
SR_CONF_MEASURED_QUANTITY | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
};
|
||||
|
||||
static const uint32_t devopts_generic_range[] = {
|
||||
SR_CONF_CONTINUOUS,
|
||||
SR_CONF_CONN | SR_CONF_GET,
|
||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||
SR_CONF_MEASURED_QUANTITY | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
SR_CONF_RANGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||
};
|
||||
|
||||
static const struct scpi_command cmdset_agilent[] = {
|
||||
{ DMM_CMD_SETUP_REMOTE, "\n", },
|
||||
{ DMM_CMD_SETUP_FUNC, "CONF:%s", },
|
||||
|
@ -47,6 +56,10 @@ static const struct scpi_command cmdset_agilent[] = {
|
|||
{ DMM_CMD_STOP_ACQ, "ABORT", },
|
||||
{ DMM_CMD_QUERY_VALUE, "READ?", },
|
||||
{ DMM_CMD_QUERY_PREC, "CONF?", },
|
||||
{ DMM_CMD_QUERY_RANGE_AUTO, "%s:RANGE:AUTO?", },
|
||||
{ DMM_CMD_QUERY_RANGE, "%s:RANGE?", },
|
||||
{ DMM_CMD_SETUP_RANGE_AUTO, "%s:RANGE:AUTO ON", },
|
||||
{ DMM_CMD_SETUP_RANGE, "%s:RANGE %s", },
|
||||
ALL_ZERO,
|
||||
};
|
||||
|
||||
|
@ -190,8 +203,9 @@ SR_PRIV const struct scpi_dmm_model models[] = {
|
|||
"Agilent", "34405A",
|
||||
1, 5, cmdset_agilent, ARRAY_AND_SIZE(mqopts_agilent_34405a),
|
||||
scpi_dmm_get_meas_agilent,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
ARRAY_AND_SIZE(devopts_generic_range),
|
||||
0, 0, FALSE,
|
||||
scpi_dmm_get_range_text, scpi_dmm_set_range_from_text, NULL,
|
||||
},
|
||||
{
|
||||
"Agilent", "34410A",
|
||||
|
@ -199,6 +213,7 @@ SR_PRIV const struct scpi_dmm_model models[] = {
|
|||
scpi_dmm_get_meas_agilent,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
0, 0, FALSE,
|
||||
NULL, NULL, NULL,
|
||||
},
|
||||
{
|
||||
"GW", "GDM8251A",
|
||||
|
@ -206,6 +221,7 @@ SR_PRIV const struct scpi_dmm_model models[] = {
|
|||
scpi_dmm_get_meas_gwinstek,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
1000 * 2500, 0, FALSE,
|
||||
NULL, NULL, NULL,
|
||||
},
|
||||
{
|
||||
"GW", "GDM8255A",
|
||||
|
@ -213,6 +229,7 @@ SR_PRIV const struct scpi_dmm_model models[] = {
|
|||
scpi_dmm_get_meas_gwinstek,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
1000 * 2500, 0, FALSE,
|
||||
NULL, NULL, NULL,
|
||||
},
|
||||
{
|
||||
"GWInstek", "GDM9060",
|
||||
|
@ -220,6 +237,7 @@ SR_PRIV const struct scpi_dmm_model models[] = {
|
|||
scpi_dmm_get_meas_agilent,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
0, 0, FALSE,
|
||||
NULL, NULL, NULL,
|
||||
},
|
||||
{
|
||||
"GWInstek", "GDM9061",
|
||||
|
@ -227,6 +245,7 @@ SR_PRIV const struct scpi_dmm_model models[] = {
|
|||
scpi_dmm_get_meas_agilent,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
0, 0, FALSE,
|
||||
NULL, NULL, NULL,
|
||||
},
|
||||
{
|
||||
"HP", "34401A",
|
||||
|
@ -235,13 +254,15 @@ SR_PRIV const struct scpi_dmm_model models[] = {
|
|||
ARRAY_AND_SIZE(devopts_generic),
|
||||
/* 34401A: typ. 1020ms for AC readings (default is 1000ms). */
|
||||
1000 * 1500, 0, FALSE,
|
||||
NULL, NULL, NULL,
|
||||
},
|
||||
{
|
||||
"Keysight", "34465A",
|
||||
1, 6, cmdset_agilent, ARRAY_AND_SIZE(mqopts_agilent_34405a),
|
||||
scpi_dmm_get_meas_agilent,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
ARRAY_AND_SIZE(devopts_generic_range),
|
||||
0, 0, FALSE,
|
||||
scpi_dmm_get_range_text, scpi_dmm_set_range_from_text, NULL,
|
||||
},
|
||||
{
|
||||
"OWON", "XDM2041",
|
||||
|
@ -249,6 +270,7 @@ SR_PRIV const struct scpi_dmm_model models[] = {
|
|||
scpi_dmm_get_meas_gwinstek,
|
||||
ARRAY_AND_SIZE(devopts_generic),
|
||||
0, 1e9, TRUE,
|
||||
NULL, NULL, NULL,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -413,6 +435,7 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
enum sr_mqflag mqflag;
|
||||
GVariant *arr[2];
|
||||
int ret;
|
||||
const char *range;
|
||||
|
||||
(void)cg;
|
||||
|
||||
|
@ -435,6 +458,14 @@ static int config_get(uint32_t key, GVariant **data,
|
|||
arr[1] = g_variant_new_uint64(mqflag);
|
||||
*data = g_variant_new_tuple(arr, ARRAY_SIZE(arr));
|
||||
return SR_OK;
|
||||
case SR_CONF_RANGE:
|
||||
if (!devc || !devc->model->get_range_text)
|
||||
return SR_ERR_NA;
|
||||
range = devc->model->get_range_text(sdi);
|
||||
if (!range || !*range)
|
||||
return SR_ERR_NA;
|
||||
*data = g_variant_new_string(range);
|
||||
return SR_OK;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
@ -447,6 +478,7 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
enum sr_mq mq;
|
||||
enum sr_mqflag mqflag;
|
||||
GVariant *tuple_child;
|
||||
const char *range;
|
||||
|
||||
(void)cg;
|
||||
|
||||
|
@ -464,6 +496,11 @@ static int config_set(uint32_t key, GVariant *data,
|
|||
mqflag = g_variant_get_uint64(tuple_child);
|
||||
g_variant_unref(tuple_child);
|
||||
return scpi_dmm_set_mq(sdi, mq, mqflag);
|
||||
case SR_CONF_RANGE:
|
||||
if (!devc || !devc->model->set_range_from_text)
|
||||
return SR_ERR_NA;
|
||||
range = g_variant_get_string(data, NULL);
|
||||
return devc->model->set_range_from_text(sdi, range);
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
@ -503,6 +540,11 @@ static int config_list(uint32_t key, GVariant **data,
|
|||
}
|
||||
*data = g_variant_builder_end(&gvb);
|
||||
return SR_OK;
|
||||
case SR_CONF_RANGE:
|
||||
if (!devc || !devc->model->get_range_text_list)
|
||||
return SR_ERR_NA;
|
||||
*data = devc->model->get_range_text_list(sdi);
|
||||
return SR_OK;
|
||||
default:
|
||||
(void)devc;
|
||||
return SR_ERR_NA;
|
||||
|
|
|
@ -154,6 +154,114 @@ SR_PRIV int scpi_dmm_set_mq(const struct sr_dev_inst *sdi,
|
|||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV const char *scpi_dmm_get_range_text(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
int ret;
|
||||
const struct mqopt_item *mqitem;
|
||||
gboolean is_auto;
|
||||
char *response, *pos;
|
||||
double range;
|
||||
int digits;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
ret = scpi_dmm_get_mq(sdi, NULL, NULL, NULL, &mqitem);
|
||||
if (ret != SR_OK)
|
||||
return NULL;
|
||||
if (!mqitem || !mqitem->scpi_func_setup)
|
||||
return NULL;
|
||||
|
||||
scpi_dmm_cmd_delay(sdi->conn);
|
||||
ret = sr_scpi_cmd(sdi, devc->cmdset, 0, NULL,
|
||||
DMM_CMD_QUERY_RANGE_AUTO, mqitem->scpi_func_setup);
|
||||
if (ret != SR_OK)
|
||||
return NULL;
|
||||
ret = sr_scpi_get_bool(sdi->conn, NULL, &is_auto);
|
||||
if (ret != SR_OK)
|
||||
return NULL;
|
||||
if (is_auto)
|
||||
return "auto";
|
||||
|
||||
/*
|
||||
* Get the response into a text buffer. The range value may be
|
||||
* followed by a precision value separated by comma. Common text
|
||||
* to number conversion support code may assume that the input
|
||||
* text spans to the end of the text, need not accept trailing
|
||||
* text which is not part of a number.
|
||||
*/
|
||||
scpi_dmm_cmd_delay(sdi->conn);
|
||||
ret = sr_scpi_cmd(sdi, devc->cmdset, 0, NULL,
|
||||
DMM_CMD_QUERY_RANGE, mqitem->scpi_func_setup);
|
||||
if (ret != SR_OK)
|
||||
return NULL;
|
||||
response = NULL;
|
||||
ret = sr_scpi_get_string(sdi->conn, NULL, &response);
|
||||
if (ret != SR_OK) {
|
||||
g_free(response);
|
||||
return NULL;
|
||||
}
|
||||
pos = strchr(response, ',');
|
||||
if (pos)
|
||||
*pos = '\0';
|
||||
ret = sr_atod_ascii_digits(response, &range, &digits);
|
||||
g_free(response);
|
||||
if (ret != SR_OK)
|
||||
return NULL;
|
||||
snprintf(devc->range_text, sizeof(devc->range_text), "%lf", range);
|
||||
return devc->range_text;
|
||||
}
|
||||
|
||||
SR_PRIV int scpi_dmm_set_range_from_text(const struct sr_dev_inst *sdi,
|
||||
const char *range)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
int ret;
|
||||
const struct mqopt_item *item;
|
||||
gboolean is_auto;
|
||||
|
||||
devc = sdi->priv;
|
||||
|
||||
if (!range || !*range)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
ret = scpi_dmm_get_mq(sdi, NULL, NULL, NULL, &item);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
if (!item || !item->scpi_func_setup)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
is_auto = g_ascii_strcasecmp(range, "auto") == 0;
|
||||
scpi_dmm_cmd_delay(sdi->conn);
|
||||
ret = sr_scpi_cmd(sdi, devc->cmdset, 0, NULL,
|
||||
is_auto ? DMM_CMD_SETUP_RANGE_AUTO : DMM_CMD_SETUP_RANGE,
|
||||
item->scpi_func_setup, is_auto ? "" : range);
|
||||
if (ret != SR_OK)
|
||||
return ret;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV GVariant *scpi_dmm_get_range_text_list(const struct sr_dev_inst *sdi)
|
||||
{
|
||||
GVariantBuilder gvb;
|
||||
GVariant *list;
|
||||
|
||||
(void)sdi;
|
||||
|
||||
g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
|
||||
/* TODO
|
||||
* Add more items _when_ the connected device supports a fixed
|
||||
* or known set of ranges. The Agilent protocol is flexible and
|
||||
* tolerant, set requests accept any value, and the device will
|
||||
* use an upper limit which is at least the specified value.
|
||||
* The values are communicated as mere numbers without units.
|
||||
*/
|
||||
list = g_variant_builder_end(&gvb);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
SR_PRIV int scpi_dmm_get_meas_agilent(const struct sr_dev_inst *sdi, size_t ch)
|
||||
{
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
|
|
|
@ -41,6 +41,10 @@ enum scpi_dmm_cmdcode {
|
|||
DMM_CMD_QUERY_VALUE,
|
||||
DMM_CMD_QUERY_PREC,
|
||||
DMM_CMD_SETUP_LOCAL,
|
||||
DMM_CMD_QUERY_RANGE_AUTO,
|
||||
DMM_CMD_QUERY_RANGE,
|
||||
DMM_CMD_SETUP_RANGE_AUTO,
|
||||
DMM_CMD_SETUP_RANGE,
|
||||
};
|
||||
|
||||
struct mqopt_item {
|
||||
|
@ -66,6 +70,10 @@ struct scpi_dmm_model {
|
|||
unsigned int read_timeout_us; /* If zero, use default from src/scpi/scpi.c. */
|
||||
float infinity_limit; /* If zero, use default from protocol.c */
|
||||
gboolean check_opc;
|
||||
const char *(*get_range_text)(const struct sr_dev_inst *sdi);
|
||||
int (*set_range_from_text)(const struct sr_dev_inst *sdi,
|
||||
const char *range);
|
||||
GVariant *(*get_range_text_list)(const struct sr_dev_inst *sdi);
|
||||
};
|
||||
|
||||
struct dev_context {
|
||||
|
@ -87,6 +95,7 @@ struct dev_context {
|
|||
struct sr_analog_spec spec[SCPI_DMM_MAX_CHANNELS];
|
||||
} run_acq_info;
|
||||
gchar *precision;
|
||||
char range_text[32];
|
||||
};
|
||||
|
||||
SR_PRIV void scpi_dmm_cmd_delay(struct sr_scpi_dev_inst *scpi);
|
||||
|
@ -99,6 +108,10 @@ SR_PRIV int scpi_dmm_get_mq(const struct sr_dev_inst *sdi,
|
|||
const struct mqopt_item **mqitem);
|
||||
SR_PRIV int scpi_dmm_set_mq(const struct sr_dev_inst *sdi,
|
||||
enum sr_mq mq, enum sr_mqflag flag);
|
||||
SR_PRIV const char *scpi_dmm_get_range_text(const struct sr_dev_inst *sdi);
|
||||
SR_PRIV int scpi_dmm_set_range_from_text(const struct sr_dev_inst *sdi,
|
||||
const char *range);
|
||||
SR_PRIV GVariant *scpi_dmm_get_range_text_list(const struct sr_dev_inst *sdi);
|
||||
SR_PRIV int scpi_dmm_get_meas_agilent(const struct sr_dev_inst *sdi, size_t ch);
|
||||
SR_PRIV int scpi_dmm_get_meas_gwinstek(const struct sr_dev_inst *sdi, size_t ch);
|
||||
SR_PRIV int scpi_dmm_receive_data(int fd, int revents, void *cb_data);
|
||||
|
|
Loading…
Reference in New Issue