scpi-pps: add support for Hameg / Rohde & Schwarz HMP4040

This commit introduces initial support for the HMP4040 power supply by
Rohde & Schwarz. It allows to configure the device and "statically" read
back current state. Automatic status updates with per-channel details
are not available yet (common support is missing).

[ gsi: drop status update remainder, address minor style nits ]
This commit is contained in:
Florian Schmidt 2020-04-07 16:33:29 +02:00 committed by Gerhard Sittig
parent 24a953382c
commit bd5f0a143e
3 changed files with 138 additions and 4 deletions

View File

@ -333,6 +333,7 @@ static int config_get(uint32_t key, GVariant **data,
int cmd, ret;
const char *s;
int reg;
gboolean is_hmp_sqii;
if (!sdi)
return SR_ERR_ARG;
@ -391,6 +392,11 @@ static int config_get(uint32_t key, GVariant **data,
cmd = SCPI_CMD_GET_CURRENT_LIMIT;
break;
case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
if (devc->device->dialect == SCPI_DIALECT_HMP) {
/* OVP is always enabled. */
*data = g_variant_new_boolean(TRUE);
return 0;
}
gvtype = G_VARIANT_TYPE_BOOLEAN;
cmd = SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ENABLED;
break;
@ -423,12 +429,18 @@ static int config_get(uint32_t key, GVariant **data,
cmd = SCPI_CMD_GET_OVER_CURRENT_PROTECTION_THRESHOLD;
break;
case SR_CONF_OVER_TEMPERATURE_PROTECTION:
if (devc->device->dialect == SCPI_DIALECT_HMP) {
/* OTP is always enabled. */
*data = g_variant_new_boolean(TRUE);
return 0;
}
gvtype = G_VARIANT_TYPE_BOOLEAN;
cmd = SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION;
break;
case SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE:
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB ||
devc->device->dialect == SCPI_DIALECT_HP_COMP)
devc->device->dialect == SCPI_DIALECT_HP_COMP ||
devc->device->dialect == SCPI_DIALECT_HMP)
gvtype = G_VARIANT_TYPE_STRING;
else
gvtype = G_VARIANT_TYPE_BOOLEAN;
@ -451,8 +463,22 @@ static int config_get(uint32_t key, GVariant **data,
channel_group_name = g_strdup(cg->name);
}
ret = sr_scpi_cmd_resp(sdi, devc->device->commands,
channel_group_cmd, channel_group_name, data, gvtype, cmd);
is_hmp_sqii = FALSE;
is_hmp_sqii |= cmd == SCPI_CMD_GET_OUTPUT_REGULATION;
is_hmp_sqii |= cmd == SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION_ACTIVE;
is_hmp_sqii &= devc->device->dialect == SCPI_DIALECT_HMP;
if (is_hmp_sqii) {
if (!cg) {
/* STAT:QUES:INST:ISUMx query requires channel spec. */
sr_err("Need a channel group for regulation or OTP-active query.");
return SR_ERR_NA;
}
ret = sr_scpi_cmd_resp(sdi, devc->device->commands,
0, NULL, data, gvtype, cmd, channel_group_name);
} else {
ret = sr_scpi_cmd_resp(sdi, devc->device->commands,
channel_group_cmd, channel_group_name, data, gvtype, cmd);
}
g_free(channel_group_name);
/*
@ -504,6 +530,18 @@ static int config_get(uint32_t key, GVariant **data,
else
*data = g_variant_new_string("UR");
}
if (devc->device->dialect == SCPI_DIALECT_HMP) {
/* Evaluate Condition Status Register from a HMP series device. */
s = g_variant_get_string(*data, NULL);
sr_atoi(s, &reg);
g_variant_unref(*data);
if (reg & (1 << 0))
*data = g_variant_new_string("CC");
else if (reg & (1 << 1))
*data = g_variant_new_string("CV");
else
*data = g_variant_new_string("UR");
}
s = g_variant_get_string(*data, NULL);
if (g_strcmp0(s, "CV") && g_strcmp0(s, "CC") && g_strcmp0(s, "CC-") &&
@ -556,7 +594,8 @@ static int config_get(uint32_t key, GVariant **data,
g_variant_unref(*data);
*data = g_variant_new_boolean(reg & (1 << 4));
}
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB) {
if (devc->device->dialect == SCPI_DIALECT_HP_66XXB ||
devc->device->dialect == SCPI_DIALECT_HMP) {
/* Evaluate Questionable Status Register bit 4 from a HP 66xxB. */
s = g_variant_get_string(*data, NULL);
sr_atoi(s, &reg);

View File

@ -1037,6 +1037,88 @@ static const struct scpi_command rs_hmc8043_cmd[] = {
ALL_ZERO
};
static const uint32_t rs_hmp4040_devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
};
static const uint32_t rs_hmp4040_devopts_cg[] = {
SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED | SR_CONF_GET,
SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE | SR_CONF_GET,
SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD | SR_CONF_GET | SR_CONF_SET,
SR_CONF_VOLTAGE | SR_CONF_GET,
SR_CONF_VOLTAGE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_CURRENT | SR_CONF_GET,
SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE | SR_CONF_GET,
SR_CONF_REGULATION | SR_CONF_GET,
};
static const struct channel_spec rs_hmp4040_ch[] = {
{ "1", { 0, 32.050, 0.001, 3, 4 }, { 0.001, 10.01, 0.0001, 3, 4 }, { 0, 0, 0, 0, 4 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
{ "2", { 0, 32.050, 0.001, 3, 4 }, { 0.001, 10.01, 0.0001, 3, 4 }, { 0, 0, 0, 0, 4 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
{ "3", { 0, 32.050, 0.001, 3, 4 }, { 0.001, 10.01, 0.0001, 3, 4 }, { 0, 0, 0, 0, 4 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
{ "4", { 0, 32.050, 0.001, 3, 4 }, { 0.001, 10.01, 0.0001, 3, 4 }, { 0, 0, 0, 0, 4 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
};
static const struct channel_group_spec rs_hmp4040_cg[] = {
{ "1", CH_IDX(0), PPS_OVP | PPS_OTP, SR_MQFLAG_DC },
{ "2", CH_IDX(1), PPS_OVP | PPS_OTP, SR_MQFLAG_DC },
{ "3", CH_IDX(2), PPS_OVP | PPS_OTP, SR_MQFLAG_DC },
{ "4", CH_IDX(3), PPS_OVP | PPS_OTP, SR_MQFLAG_DC },
};
/*
* Developer's note: Currently unused device commands. Some of them
* are not in use because SCPI_CMD codes are not defined yet.
* OUTP:GEN
* VOLT? MAX, CURR? MAX
* VOLT:PROT:CLE (could set SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE)
* VOLT:PROT:MODE
* FUSE:STAT, FUSE:TRIP?, FUSE:LINK, FUSE:UNL
* ARB:...
* SYST:LOC, SYST:REM, SYST:RWL, SYST:MIX
* SYST:BEEP:IMM
*/
static const struct scpi_command rs_hmp4040_cmd[] = {
{ SCPI_CMD_SELECT_CHANNEL, "INST:NSEL %s" },
{ SCPI_CMD_GET_MEAS_VOLTAGE, "MEAS:VOLT?" },
{ SCPI_CMD_GET_MEAS_CURRENT, "MEAS:CURR?" },
{ SCPI_CMD_GET_VOLTAGE_TARGET, "VOLT?" },
{ SCPI_CMD_SET_VOLTAGE_TARGET, "VOLT %.6f" },
{ SCPI_CMD_GET_CURRENT_LIMIT, "CURR?" },
{ SCPI_CMD_SET_CURRENT_LIMIT, "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, "STAT:QUES:INST:ISUM%s:COND?" },
{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE, "VOLT:PROT:TRIP?" },
{ SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_THRESHOLD, "VOLT:PROT:LEV?" },
{ SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD, "VOLT:PROT:LEV %.6f" },
{ SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION_ACTIVE, "STAT:QUES:INST:ISUM%s:COND?" },
ALL_ZERO
};
static int rs_hmp_init_acquisition(const struct sr_dev_inst *sdi)
{
struct sr_scpi_dev_inst *scpi;
int ret;
scpi = sdi->conn;
/*
* Sets the system to remote state. The front panel and remote
* control are possible simultaneously (mixed mode).
*/
ret = sr_scpi_send(scpi, "SYST:MIX");
if (ret != SR_OK)
return ret;
return SR_OK;
}
SR_PRIV const struct scpi_pps pps_profiles[] = {
/* Agilent N5763A */
{ "Agilent", "N5763A", SCPI_DIALECT_UNKNOWN, 0,
@ -1349,6 +1431,18 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
.init_acquisition = NULL,
.update_status = NULL,
},
/* Hameg / Rohde&Schwarz HMP4000 series */
{ "HAMEG", "HMP4040", SCPI_DIALECT_HMP, 0,
ARRAY_AND_SIZE(rs_hmp4040_devopts),
ARRAY_AND_SIZE(rs_hmp4040_devopts_cg),
ARRAY_AND_SIZE(rs_hmp4040_ch),
ARRAY_AND_SIZE(rs_hmp4040_cg),
rs_hmp4040_cmd,
.probe_channels = NULL,
.init_acquisition = rs_hmp_init_acquisition,
.update_status = NULL,
},
};
SR_PRIV unsigned int num_pps_profiles = ARRAY_SIZE(pps_profiles);

View File

@ -74,6 +74,7 @@ enum pps_scpi_dialect {
SCPI_DIALECT_HP_COMP,
SCPI_DIALECT_HP_66XXB,
SCPI_DIALECT_PHILIPS,
SCPI_DIALECT_HMP,
};
/*