scpi-pps: Create one channel per MQ/output combination.
This allows frontends to trivially select which MQs on which channels they want to see; others won't even be fetched.
This commit is contained in:
parent
379d260965
commit
01b0257aef
|
@ -30,6 +30,12 @@ static const int32_t scanopts[] = {
|
|||
SR_CONF_SERIALCOMM,
|
||||
};
|
||||
|
||||
static struct pps_channel_instance pci[] = {
|
||||
{ SR_MQ_VOLTAGE, SCPI_CMD_GET_MEAS_VOLTAGE, "V" },
|
||||
{ SR_MQ_CURRENT, SCPI_CMD_GET_MEAS_CURRENT, "I" },
|
||||
{ SR_MQ_POWER, SCPI_CMD_GET_MEAS_POWER, "P" },
|
||||
};
|
||||
|
||||
static int init(struct sr_context *sr_ctx)
|
||||
{
|
||||
return std_init(sr_ctx, di, LOG_PREFIX);
|
||||
|
@ -43,13 +49,16 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
|
|||
struct sr_channel_group *cg;
|
||||
struct sr_channel *ch;
|
||||
const struct scpi_pps *device;
|
||||
struct pps_channel *pch;
|
||||
const struct channel_group_spec *cgs;
|
||||
struct pps_channel_group *pcg;
|
||||
GRegex *model_re;
|
||||
GMatchInfo *model_mi;
|
||||
GSList *l;
|
||||
uint64_t mask;
|
||||
unsigned int i, j;
|
||||
unsigned int ch_num, ch_idx, old_idx, i, j;
|
||||
const char *vendor;
|
||||
char ch_name[16];
|
||||
|
||||
if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
|
||||
sr_info("Couldn't get IDN response.");
|
||||
|
@ -83,10 +92,31 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
|
|||
devc->device = device;
|
||||
sdi->priv = devc;
|
||||
|
||||
for (i = 0; i < device->num_channels; i++) {
|
||||
ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
|
||||
device->channels[i].name);
|
||||
sdi->channels = g_slist_append(sdi->channels, ch);
|
||||
ch_idx = 0;
|
||||
for (ch_num = 0; ch_num < device->num_channels; ch_num++) {
|
||||
/* Create one channel per measurable output unit. */
|
||||
old_idx = ch_idx;
|
||||
for (i = 0; i < ARRAY_SIZE(pci); i++) {
|
||||
if (!scpi_cmd_get(sdi, pci[i].command))
|
||||
continue;
|
||||
g_snprintf(ch_name, 16, "%s%s", pci[i].prefix,
|
||||
device->channels[ch_num].name);
|
||||
ch = sr_channel_new(ch_idx++, SR_CHANNEL_ANALOG, TRUE, ch_name);
|
||||
pch = g_malloc0(sizeof(struct pps_channel));
|
||||
pch->hw_output_idx = ch_num;
|
||||
pch->hwname = device->channels[ch_num].name;
|
||||
pch->mq = pci[i].mq;
|
||||
ch->priv = pch;
|
||||
sdi->channels = g_slist_append(sdi->channels, ch);
|
||||
}
|
||||
if (ch_idx == old_idx) {
|
||||
/*
|
||||
* Didn't create any channels for this hardware output.
|
||||
* This can happen if the device has no measurement capability.
|
||||
*/
|
||||
g_free(pch);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < device->num_channel_groups; i++) {
|
||||
|
@ -95,8 +125,12 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
|
|||
cg->name = g_strdup(cgs->name);
|
||||
for (j = 0, mask = 1; j < 64; j++, mask <<= 1) {
|
||||
if (cgs->channel_index_mask & mask) {
|
||||
ch = g_slist_nth_data(sdi->channels, j);
|
||||
cg->channels = g_slist_append(cg->channels, ch);
|
||||
for (l = sdi->channels; l; l = l->next) {
|
||||
ch = l->data;
|
||||
pch = ch->priv;
|
||||
if (pch->hw_output_idx == j)
|
||||
cg->channels = g_slist_append(cg->channels, ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
pcg = g_malloc0(sizeof(struct pps_channel_group));
|
||||
|
@ -171,6 +205,7 @@ static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
|
|||
struct dev_context *devc;
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
struct sr_channel *ch;
|
||||
struct pps_channel *pch;
|
||||
const GVariantType *gvtype;
|
||||
unsigned int i;
|
||||
int cmd, ret;
|
||||
|
@ -187,8 +222,6 @@ static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
|
|||
* These options only apply to channel groups with a single
|
||||
* channel -- they're per-channel settings for the device.
|
||||
*/
|
||||
if (g_slist_length(cg->channels) > 1)
|
||||
return SR_ERR_NA;
|
||||
|
||||
/*
|
||||
* Config keys are handled below depending on whether a channel
|
||||
|
@ -204,6 +237,7 @@ static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
|
|||
}
|
||||
|
||||
ch = cg->channels->data;
|
||||
pch = ch->priv;
|
||||
}
|
||||
|
||||
gvtype = NULL;
|
||||
|
@ -260,14 +294,14 @@ static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
|
|||
}
|
||||
if (gvtype) {
|
||||
if (cg)
|
||||
ret = scpi_cmd_resp(sdi, data, gvtype, cmd, ch->name);
|
||||
ret = scpi_cmd_resp(sdi, data, gvtype, cmd, pch->hwname);
|
||||
else
|
||||
ret = scpi_cmd_resp(sdi, data, gvtype, cmd);
|
||||
} else if (cg) {
|
||||
switch (key) {
|
||||
case SR_CONF_OUTPUT_REGULATION:
|
||||
ret = SR_ERR;
|
||||
if (scpi_cmd(sdi, SCPI_CMD_GET_OUTPUT_REGULATION, ch->name) == SR_OK) {
|
||||
if (scpi_cmd(sdi, SCPI_CMD_GET_OUTPUT_REGULATION, pch->hwname) == SR_OK) {
|
||||
if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
|
||||
if (strcmp(s, "CC") && strcmp(s, "CV") && strcmp(s, "UR")) {
|
||||
sr_dbg("Unknown response to SCPI_CMD_GET_OUTPUT_REGULATION: %s", s);
|
||||
|
@ -292,6 +326,7 @@ static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
|
|||
const struct sr_channel_group *cg)
|
||||
{
|
||||
struct sr_channel *ch;
|
||||
struct pps_channel *pch;
|
||||
double d;
|
||||
int ret;
|
||||
const char *s;
|
||||
|
@ -329,38 +364,39 @@ static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
|
|||
if (g_slist_length(cg->channels) > 1)
|
||||
return SR_ERR_NA;
|
||||
ch = cg->channels->data;
|
||||
pch = ch->priv;
|
||||
switch (key) {
|
||||
case SR_CONF_OUTPUT_ENABLED:
|
||||
s = g_variant_get_boolean(data) ? "ON" : "OFF";
|
||||
ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_ENABLED, ch->name, s);
|
||||
ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_ENABLED, pch->hwname, s);
|
||||
break;
|
||||
case SR_CONF_OUTPUT_VOLTAGE_MAX:
|
||||
d = g_variant_get_double(data);
|
||||
ret = scpi_cmd(sdi, SCPI_CMD_SET_VOLTAGE_MAX, ch->name, d);
|
||||
ret = scpi_cmd(sdi, SCPI_CMD_SET_VOLTAGE_MAX, pch->hwname, d);
|
||||
break;
|
||||
case SR_CONF_OUTPUT_CURRENT_MAX:
|
||||
d = g_variant_get_double(data);
|
||||
ret = scpi_cmd(sdi, SCPI_CMD_SET_CURRENT_MAX, ch->name, d);
|
||||
ret = scpi_cmd(sdi, SCPI_CMD_SET_CURRENT_MAX, pch->hwname, d);
|
||||
break;
|
||||
case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
|
||||
s = g_variant_get_boolean(data) ? "ON" : "OFF";
|
||||
ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_ENABLED,
|
||||
ch->name, s);
|
||||
pch->hwname, s);
|
||||
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,
|
||||
ch->name, d);
|
||||
pch->hwname, d);
|
||||
break;
|
||||
case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
|
||||
s = g_variant_get_boolean(data) ? "ON" : "OFF";
|
||||
ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLED,
|
||||
ch->name, s);
|
||||
pch->hwname, s);
|
||||
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,
|
||||
ch->name, d);
|
||||
pch->hwname, d);
|
||||
break;
|
||||
default:
|
||||
ret = SR_ERR_NA;
|
||||
|
@ -424,17 +460,12 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
|
|||
}
|
||||
} else {
|
||||
/* Channel group specified. */
|
||||
if (!sdi)
|
||||
return SR_ERR_ARG;
|
||||
/*
|
||||
* Per-channel-group options depending on a channel are actually
|
||||
* done with the first channel. Channel groups in PPS can have
|
||||
* more than one channel, but they will typically be of equal
|
||||
* specification for use in series or parallel mode. Drop requests
|
||||
* for groups with more than one channel just to make sure.
|
||||
* specification for use in series or parallel mode.
|
||||
*/
|
||||
if (g_slist_length(cg->channels) > 1)
|
||||
return SR_ERR_NA;
|
||||
ch = cg->channels->data;
|
||||
|
||||
switch (key) {
|
||||
|
@ -477,7 +508,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi,
|
|||
struct dev_context *devc;
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
struct sr_channel *ch;
|
||||
int ret;
|
||||
struct pps_channel *pch;
|
||||
int cmd, ret;
|
||||
|
||||
if (sdi->status != SR_ST_ACTIVE)
|
||||
return SR_ERR_DEV_CLOSED;
|
||||
|
@ -486,23 +518,30 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi,
|
|||
scpi = sdi->conn;
|
||||
devc->cb_data = cb_data;
|
||||
|
||||
if ((ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 100,
|
||||
if ((ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 10,
|
||||
scpi_pps_receive_data, (void *)sdi)) != SR_OK)
|
||||
return ret;
|
||||
std_session_send_df_header(sdi, LOG_PREFIX);
|
||||
|
||||
/* Prime the pipe. */
|
||||
devc->state = STATE_VOLTAGE;
|
||||
/* Prime the pipe with the first channel's fetch. */
|
||||
ch = sdi->channels->data;
|
||||
pch = ch->priv;
|
||||
devc->cur_channel = ch;
|
||||
scpi_cmd(sdi, SCPI_CMD_GET_MEAS_VOLTAGE, ch->name);
|
||||
if (pch->mq == SR_MQ_VOLTAGE)
|
||||
cmd = SCPI_CMD_GET_MEAS_VOLTAGE;
|
||||
else if (pch->mq == SR_MQ_CURRENT)
|
||||
cmd = SCPI_CMD_GET_MEAS_CURRENT;
|
||||
else if (pch->mq == SR_MQ_POWER)
|
||||
cmd = SCPI_CMD_GET_MEAS_POWER;
|
||||
else
|
||||
return SR_ERR;
|
||||
scpi_cmd(sdi, cmd, pch->hwname);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
|
||||
{
|
||||
struct dev_context *devc;
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
float f;
|
||||
|
||||
|
@ -511,7 +550,6 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
|
|||
if (sdi->status != SR_ST_ACTIVE)
|
||||
return SR_ERR_DEV_CLOSED;
|
||||
|
||||
devc = sdi->priv;
|
||||
scpi = sdi->conn;
|
||||
|
||||
/*
|
||||
|
@ -522,9 +560,6 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
|
|||
sr_scpi_get_float(scpi, NULL, &f);
|
||||
sr_scpi_source_remove(sdi->session, scpi);
|
||||
|
||||
/* Just in case something is queued up. */
|
||||
devc->state = STATE_STOP;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -107,8 +107,10 @@ SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data)
|
|||
struct sr_datafeed_analog analog;
|
||||
const struct sr_dev_inst *sdi;
|
||||
struct sr_scpi_dev_inst *scpi;
|
||||
struct pps_channel *pch;
|
||||
GSList *l;
|
||||
float f;
|
||||
int cmd;
|
||||
|
||||
(void)fd;
|
||||
(void)revents;
|
||||
|
@ -119,51 +121,47 @@ SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data)
|
|||
if (!(devc = sdi->priv))
|
||||
return TRUE;
|
||||
|
||||
if (devc->state == STATE_STOP)
|
||||
return TRUE;
|
||||
|
||||
scpi = sdi->conn;
|
||||
|
||||
/* Retrieve requested value for this state. */
|
||||
if (sr_scpi_get_float(scpi, NULL, &f) == SR_OK) {
|
||||
pch = devc->cur_channel->priv;
|
||||
packet.type = SR_DF_ANALOG;
|
||||
packet.payload = &analog;
|
||||
analog.channels = g_slist_append(NULL, devc->cur_channel);
|
||||
analog.num_samples = 1;
|
||||
if (devc->state == STATE_VOLTAGE) {
|
||||
analog.mq = SR_MQ_VOLTAGE;
|
||||
analog.mq = pch->mq;
|
||||
if (pch->mq == SR_MQ_VOLTAGE)
|
||||
analog.unit = SR_UNIT_VOLT;
|
||||
} else {
|
||||
analog.mq = SR_MQ_CURRENT;
|
||||
else if (pch->mq == SR_MQ_CURRENT)
|
||||
analog.unit = SR_UNIT_AMPERE;
|
||||
}
|
||||
else if (pch->mq == SR_MQ_POWER)
|
||||
analog.unit = SR_UNIT_WATT;
|
||||
analog.mqflags = SR_MQFLAG_DC;
|
||||
analog.data = &f;
|
||||
sr_session_send(sdi, &packet);
|
||||
g_slist_free(analog.channels);
|
||||
}
|
||||
|
||||
if (devc->state == STATE_VOLTAGE) {
|
||||
/* Just got voltage, request current for this channel. */
|
||||
devc->state = STATE_CURRENT;
|
||||
scpi_cmd(sdi, SCPI_CMD_GET_MEAS_CURRENT, devc->cur_channel->name);
|
||||
} else if (devc->state == STATE_CURRENT) {
|
||||
/*
|
||||
* Done with voltage and current for this channel, switch to
|
||||
* the next enabled channel.
|
||||
*/
|
||||
do {
|
||||
l = g_slist_find(sdi->channels, devc->cur_channel);
|
||||
if (l->next)
|
||||
devc->cur_channel = l->next->data;
|
||||
else
|
||||
devc->cur_channel = sdi->channels->data;
|
||||
} while (!devc->cur_channel->enabled);
|
||||
/* Find next enabled channel. */
|
||||
do {
|
||||
l = g_slist_find(sdi->channels, devc->cur_channel);
|
||||
if (l->next)
|
||||
devc->cur_channel = l->next->data;
|
||||
else
|
||||
devc->cur_channel = sdi->channels->data;
|
||||
} while (!devc->cur_channel->enabled);
|
||||
|
||||
/* Request voltage. */
|
||||
devc->state = STATE_VOLTAGE;
|
||||
scpi_cmd(sdi, SCPI_CMD_GET_MEAS_VOLTAGE, devc->cur_channel->name);
|
||||
}
|
||||
pch = devc->cur_channel->priv;
|
||||
if (pch->mq == SR_MQ_VOLTAGE)
|
||||
cmd = SCPI_CMD_GET_MEAS_VOLTAGE;
|
||||
else if (pch->mq == SR_MQ_CURRENT)
|
||||
cmd = SCPI_CMD_GET_MEAS_CURRENT;
|
||||
else if (pch->mq == SR_MQ_POWER)
|
||||
cmd = SCPI_CMD_GET_MEAS_POWER;
|
||||
else
|
||||
return SR_ERR;
|
||||
scpi_cmd(sdi, cmd, pch->hwname);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -101,6 +101,18 @@ struct channel_group_spec {
|
|||
uint64_t features;
|
||||
};
|
||||
|
||||
struct pps_channel {
|
||||
int mq;
|
||||
unsigned int hw_output_idx;
|
||||
char *hwname;
|
||||
};
|
||||
|
||||
struct pps_channel_instance {
|
||||
int mq;
|
||||
int command;
|
||||
char *prefix;
|
||||
};
|
||||
|
||||
struct pps_channel_group {
|
||||
uint64_t features;
|
||||
};
|
||||
|
@ -122,7 +134,6 @@ struct dev_context {
|
|||
/* Operational state */
|
||||
|
||||
/* Temporary state across callbacks */
|
||||
int state;
|
||||
struct sr_channel *cur_channel;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue