scpi-pps: Use only standard SCPI for Rigol DP800 series.
diff --git a/src/hardware/scpi-pps/api.c b/src/hardware/scpi-pps/api.c
index addf610..e025152 100644
--- a/src/hardware/scpi-pps/api.c
+++ b/src/hardware/scpi-pps/api.c
@@ -130,8 +130,7 @@
 		sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
 	}
 
-	/* SCPI devices commonly lock the panel keys when accessed remotely. */
-	scpi_cmd(sdi, SCPI_CMD_KEY_UNLOCK);
+	scpi_cmd(sdi, SCPI_CMD_LOCAL);
 	sr_scpi_close(scpi);
 
 	return sdi;
@@ -165,6 +164,8 @@
 
 	sdi->status = SR_ST_ACTIVE;
 
+	scpi_cmd(sdi, SCPI_CMD_REMOTE);
+
 	return SR_OK;
 }
 
@@ -177,7 +178,7 @@
 
 	scpi = sdi->conn;
 	if (scpi) {
-		scpi_cmd(sdi, SCPI_CMD_KEY_UNLOCK);
+		scpi_cmd(sdi, SCPI_CMD_LOCAL);
 		sr_scpi_close(scpi);
 		sdi->status = SR_ST_INACTIVE;
 	}
@@ -194,19 +195,15 @@
 		const struct sr_channel_group *cg)
 {
 	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;
-	char *s;
+	const char *s;
 
 	if (!sdi)
 		return SR_ERR_ARG;
 
 	devc = sdi->priv;
-	scpi = sdi->conn;
 
 	if (cg) {
 		/*
@@ -226,9 +223,6 @@
 				break;
 			}
 		}
-
-		ch = cg->channels->data;
-		pch = ch->priv;
 	}
 
 	gvtype = NULL;
@@ -282,30 +276,32 @@
 		gvtype = G_VARIANT_TYPE_BOOLEAN;
 		cmd = SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION;
 		break;
+	case SR_CONF_OUTPUT_REGULATION:
+		gvtype = G_VARIANT_TYPE_STRING;
+		cmd = SCPI_CMD_GET_OUTPUT_REGULATION;
 	}
 	if (gvtype) {
 		if (cg)
-			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, 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);
-					} else {
-						*data = g_variant_new_string(s);
-						g_free(s);
-						ret = SR_OK;
-					}
+			select_channel(sdi, cg->channels->data);
+		ret = scpi_cmd_resp(sdi, data, gvtype, cmd);
+
+		if (gvtype == G_VARIANT_TYPE_STRING && ret == SR_OK) {
+			/* Non-standard data type responses. */
+			switch (key) {
+			case SCPI_CMD_GET_OUTPUT_REGULATION:
+				/*
+				 * This is specific to the Rigol DP800 series.
+				 * We return the same string for now until more
+				 * models with this key are supported. Do a check
+				 * just for the hell of it.
+				 */
+				s = g_variant_get_string(*data, NULL);
+				if (strcmp(s, "CC") && strcmp(s, "CV") && strcmp(s, "UR")) {
+					sr_dbg("Unknown response to SCPI_CMD_GET_OUTPUT_REGULATION: %s", s);
+					ret = SR_ERR_DATA;
 				}
+				break;
 			}
-			break;
-		default:
-			ret = SR_ERR_NA;
 		}
 	} else
 		ret = SR_ERR_NA;
@@ -316,8 +312,6 @@
 static int config_set(uint32_t 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;
 
@@ -327,81 +321,54 @@
 	if (sdi->status != SR_ST_ACTIVE)
 		return SR_ERR_DEV_CLOSED;
 
-	ret = SR_OK;
-	if (!cg) {
-		switch (key) {
-		/* No channel group: global options. */
-		case SR_CONF_OUTPUT_ENABLED:
-			if (g_variant_get_boolean(data))
-				ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_ENABLE);
-			else
-				ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_DISABLE);
-			break;
-		case SR_CONF_OUTPUT_VOLTAGE_TARGET:
-			d = g_variant_get_double(data);
-			ret = scpi_cmd(sdi, SCPI_CMD_SET_VOLTAGE_TARGET, d);
-			break;
-		case SR_CONF_OUTPUT_CURRENT_LIMIT:
-			d = g_variant_get_double(data);
-			ret = scpi_cmd(sdi, SCPI_CMD_SET_CURRENT_LIMIT, 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);
-			else
-				ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_DISABLE);
-			break;
-		default:
-			ret = SR_ERR_NA;
-		}
-	} else {
+	if (cg)
 		/* Channel group specified. */
-		ch = cg->channels->data;
-		pch = ch->priv;
-		switch (key) {
-		case SR_CONF_OUTPUT_ENABLED:
-			if (g_variant_get_boolean(data))
-				ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_ENABLE, pch->hwname);
-			else
-				ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_DISABLE, pch->hwname);
-			break;
-		case SR_CONF_OUTPUT_VOLTAGE_TARGET:
-			d = g_variant_get_double(data);
-			ret = scpi_cmd(sdi, SCPI_CMD_SET_VOLTAGE_TARGET, pch->hwname, d);
-			break;
-		case SR_CONF_OUTPUT_CURRENT_LIMIT:
-			d = g_variant_get_double(data);
-			ret = scpi_cmd(sdi, SCPI_CMD_SET_CURRENT_LIMIT, pch->hwname, 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,
-						pch->hwname);
-			else
-				ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_DISABLE,
-						pch->hwname);
-			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,
-					pch->hwname, 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,
-						pch->hwname);
-			else
-				ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE,
-						pch->hwname);
-			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,
-					pch->hwname, d);
-			break;
-		default:
-			ret = SR_ERR_NA;
-		}
+		select_channel(sdi, cg->channels->data);
+
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_OUTPUT_ENABLED:
+		if (g_variant_get_boolean(data))
+			ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_ENABLE);
+		else
+			ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_DISABLE);
+		break;
+	case SR_CONF_OUTPUT_VOLTAGE_TARGET:
+		d = g_variant_get_double(data);
+		ret = scpi_cmd(sdi, SCPI_CMD_SET_VOLTAGE_TARGET, d);
+		break;
+	case SR_CONF_OUTPUT_CURRENT_LIMIT:
+		d = g_variant_get_double(data);
+		ret = scpi_cmd(sdi, 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);
+		else
+			ret = scpi_cmd(sdi, 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);
+		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);
+		else
+			ret = scpi_cmd(sdi, 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);
+		break;
+	case SR_CONF_OVER_TEMPERATURE_PROTECTION:
+		if (g_variant_get_boolean(data))
+			ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_ENABLE);
+		else
+			ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_DISABLE);
+		break;
+	default:
+		ret = SR_ERR_NA;
 	}
 
 	return ret;
@@ -527,7 +494,7 @@
 	/* Prime the pipe with the first channel's fetch. */
 	ch = sdi->channels->data;
 	pch = ch->priv;
-	devc->cur_channel = ch;
+	select_channel(sdi, ch);
 	if (pch->mq == SR_MQ_VOLTAGE)
 		cmd = SCPI_CMD_GET_MEAS_VOLTAGE;
 	else if (pch->mq == SR_MQ_CURRENT)
diff --git a/src/hardware/scpi-pps/profiles.c b/src/hardware/scpi-pps/profiles.c
index d4a6520..06b63fd 100644
--- a/src/hardware/scpi-pps/profiles.c
+++ b/src/hardware/scpi-pps/profiles.c
@@ -82,33 +82,35 @@
 };
 
 struct scpi_command rigol_dp800_cmd[] = {
-	{ SCPI_CMD_KEY_UNLOCK, "SYST:KLOCK OFF" },
-	{ SCPI_CMD_GET_MEAS_VOLTAGE, ":MEAS:VOLT? CH%s" },
-	{ SCPI_CMD_GET_MEAS_CURRENT, ":MEAS:CURR? CH%s" },
-	{ SCPI_CMD_GET_MEAS_POWER, ":MEAS:POWE? CH%s" },
-	{ SCPI_CMD_GET_VOLTAGE_TARGET, ":SOUR%s:VOLT?" },
-	{ SCPI_CMD_SET_VOLTAGE_TARGET, ":SOUR%s:VOLT %.6f" },
-	{ SCPI_CMD_GET_CURRENT_LIMIT, ":SOUR%s:CURR?" },
-	{ SCPI_CMD_SET_CURRENT_LIMIT, ":SOUR%s:CURR %.6f" },
-	{ SCPI_CMD_GET_OUTPUT_ENABLED, ":OUTP? CH%s" },
-	{ SCPI_CMD_SET_OUTPUT_ENABLE, ":OUTP CH%s,ON" },
-	{ SCPI_CMD_SET_OUTPUT_DISABLE, ":OUTP CH%s,OFF" },
-	{ SCPI_CMD_GET_OUTPUT_REGULATION, ":OUTP:MODE? CH%s" },
+	{ SCPI_CMD_REMOTE, "SYST:REMOTE" },
+	{ SCPI_CMD_LOCAL, "SYST:LOCAL" },
+	{ SCPI_CMD_SELECT_CHANNEL, ":INST:NSEL %s" },
+	{ SCPI_CMD_GET_MEAS_VOLTAGE, ":MEAS:VOLT?" },
+	{ SCPI_CMD_GET_MEAS_CURRENT, ":MEAS:CURR?" },
+	{ SCPI_CMD_GET_MEAS_POWER, ":MEAS:POWE?" },
+	{ SCPI_CMD_GET_VOLTAGE_TARGET, ":SOUR:VOLT?" },
+	{ SCPI_CMD_SET_VOLTAGE_TARGET, ":SOUR:VOLT %.6f" },
+	{ SCPI_CMD_GET_CURRENT_LIMIT, ":SOUR:CURR?" },
+	{ SCPI_CMD_SET_CURRENT_LIMIT, ":SOUR:CURR %.6f" },
+	{ SCPI_CMD_GET_OUTPUT_ENABLED, ":OUTP?" },
+	{ SCPI_CMD_SET_OUTPUT_ENABLE, ":OUTP ON" },
+	{ SCPI_CMD_SET_OUTPUT_DISABLE, ":OUTP OFF" },
+	{ SCPI_CMD_GET_OUTPUT_REGULATION, ":OUTP:MODE?" },
 	{ SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION, ":SYST:OTP?" },
 	{ SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_ENABLE, ":SYST:OTP ON" },
 	{ SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_DISABLE, ":SYST:OTP OFF" },
-	{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ENABLED, ":OUTP:OVP? CH%s" },
-	{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_ENABLE, ":OUTP:OVP CH%s,ON" },
-	{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_DISABLE, ":OUTP:OVP CH%s,OFF" },
-	{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE, ":OUTP:OVP:QUES? CH%s" },
-	{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":OUTP:OVP:VAL? CH%s" },
-	{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":OUTP:OVP:VAL CH%s,%.6f" },
-	{ SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ENABLED, ":OUTP:OCP? CH%s" },
-	{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLE, ":OUTP:OCP CH%s,ON" },
-	{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE, ":OUTP:OCP CH%s,OFF" },
-	{ SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE, ":OUTP:OCP:QUES? CH%s" },
-	{ SCPI_CMD_GET_OVER_CURRENT_PROTECTION_THRESHOLD, ":OUTP:OCP:VAL? CH%s" },
-	{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD, ":OUTP:OCP:VAL CH%s,%.6f" },
+	{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ENABLED, ":OUTP:OVP?" },
+	{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_ENABLE, ":OUTP:OVP ON" },
+	{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_DISABLE, ":OUTP:OVP OFF" },
+	{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE, ":OUTP:OVP:QUES?" },
+	{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":OUTP:OVP:VAL?" },
+	{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, ":OUTP:OVP:VAL %.6f" },
+	{ SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ENABLED, ":OUTP:OCP?" },
+	{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLE, ":OUTP:OCP:STAT ON" },
+	{ SCPI_CMD_SET_OVER_CURRENT_PROTECTION_DISABLE, ":OUTP:OCP:STAT OFF" },
+	{ 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" },
 };
 
 /* HP 663xx series */
diff --git a/src/hardware/scpi-pps/protocol.c b/src/hardware/scpi-pps/protocol.c
index 4f2586d..667ce46 100644
--- a/src/hardware/scpi-pps/protocol.c
+++ b/src/hardware/scpi-pps/protocol.c
@@ -100,12 +100,33 @@
 	return ret;
 }
 
+SR_PRIV int select_channel(const struct sr_dev_inst *sdi, struct sr_channel *ch)
+{
+	struct dev_context *devc;
+	struct pps_channel *pch;
+	int ret;
+
+	if (g_slist_length(sdi->channels) == 1)
+		return SR_OK;
+
+	devc = sdi->priv;
+	if (ch == devc->cur_channel)
+		return SR_OK;
+
+	pch = ch->priv;
+	if ((ret = scpi_cmd(sdi, SCPI_CMD_SELECT_CHANNEL, pch->hwname)) == SR_OK)
+		devc->cur_channel = ch;
+
+	return ret;
+}
+
 SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data)
 {
 	struct dev_context *devc;
 	struct sr_datafeed_packet packet;
 	struct sr_datafeed_analog analog;
 	const struct sr_dev_inst *sdi;
+	struct sr_channel *next_channel;
 	struct sr_scpi_dev_inst *scpi;
 	struct pps_channel *pch;
 	GSList *l;
@@ -143,14 +164,22 @@
 		g_slist_free(analog.channels);
 	}
 
-	/* 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);
+	if (g_slist_length(sdi->channels) > 1) {
+		/* Find next enabled channel. */
+		next_channel = devc->cur_channel;
+		do {
+			l = g_slist_find(sdi->channels, next_channel);
+			if (l->next)
+				next_channel = l->next->data;
+			else
+				next_channel = sdi->channels->data;
+		} while (!next_channel->enabled);
+		select_channel(sdi, next_channel);
+		if (devc->cur_channel != next_channel) {
+			sr_err("Failed to select channel %s", next_channel->name);
+			return FALSE;
+		}
+	}
 
 	pch = devc->cur_channel->priv;
 	if (pch->mq == SR_MQ_VOLTAGE)
diff --git a/src/hardware/scpi-pps/protocol.h b/src/hardware/scpi-pps/protocol.h
index fcd451d..93c4580 100644
--- a/src/hardware/scpi-pps/protocol.h
+++ b/src/hardware/scpi-pps/protocol.h
@@ -28,7 +28,9 @@
 #define LOG_PREFIX "scpi-pps"
 
 enum pps_scpi_cmds {
-	SCPI_CMD_KEY_UNLOCK,
+	SCPI_CMD_REMOTE,
+	SCPI_CMD_LOCAL,
+	SCPI_CMD_SELECT_CHANNEL,
 	SCPI_CMD_GET_MEAS_VOLTAGE,
 	SCPI_CMD_GET_MEAS_CURRENT,
 	SCPI_CMD_GET_MEAS_POWER,
@@ -146,6 +148,7 @@
 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 int scpi_pps_receive_data(int fd, int revents, void *cb_data);
 
 #endif