Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions contrib/60-libsigrok.rules
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,11 @@ ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1001", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1006", ENV{ID_SIGROK}="1"

# Siglent USBTMC devices.
# 0483:7540: E.g. SPD3303X-E psu
# f4ec:ee3a: E.g. SDS1052DL+ scope
# f4ec:ee38: E.g. SDS1104X-E scope
# f4ed:ee3a: E.g. SDS1202X-E scope or SDG1010 waveform generator
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="7540", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="f4ec", ATTRS{idProduct}=="ee3a", ENV{ID_SIGROK}="1"
ATTRS{idVendor}=="f4ed", ATTRS{idProduct}=="ee3a", ENV{ID_SIGROK}="1"

Expand Down
117 changes: 106 additions & 11 deletions src/hardware/scpi-pps/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi,
sr_scpi_hw_info_free(hw_info);
hw_info = NULL;

if (devc->device->dialect == SCPI_DIALECT_SIGLENT) {
scpi->quirks |= SCPI_QUIRK_CMD_OMIT_LF;
scpi->quirks |= SCPI_QUIRK_OPC_UNSUPPORTED;
scpi->quirks |= SCPI_QUIRK_SLOW_CHANNEL_SELECT;
}

/* Don't send SCPI_CMD_LOCAL for HP 66xxB using SCPI over GPIB. */
if (!(devc->device->dialect == SCPI_DIALECT_HP_66XXB &&
scpi->transport == SCPI_TRANSPORT_LIBGPIB))
Expand Down Expand Up @@ -333,6 +339,7 @@ static int config_get(uint32_t key, GVariant **data,
int cmd, ret;
const char *s;
int reg;
long regl;

if (!sdi)
return SR_ERR_ARG;
Expand Down Expand Up @@ -363,7 +370,10 @@ static int config_get(uint32_t key, GVariant **data,
cmd = -1;
switch (key) {
case SR_CONF_ENABLED:
gvtype = G_VARIANT_TYPE_BOOLEAN;
if (devc->device->dialect == SCPI_DIALECT_SIGLENT)
gvtype = G_VARIANT_TYPE_STRING;
else
gvtype = G_VARIANT_TYPE_BOOLEAN;
cmd = SCPI_CMD_GET_OUTPUT_ENABLED;
break;
case SR_CONF_VOLTAGE:
Expand Down Expand Up @@ -438,6 +448,10 @@ static int config_get(uint32_t key, GVariant **data,
gvtype = G_VARIANT_TYPE_STRING;
cmd = SCPI_CMD_GET_OUTPUT_REGULATION;
break;
case SR_CONF_CHANNEL_CONFIG:
gvtype = G_VARIANT_TYPE_STRING;
cmd = SCPI_CMD_GET_CHANNEL_CONFIG;
break;
default:
return sr_sw_limits_config_get(&devc->limits, key, data);
}
Expand All @@ -452,13 +466,28 @@ static int config_get(uint32_t key, GVariant **data,
}

ret = sr_scpi_cmd_resp(sdi, devc->device->commands,
channel_group_cmd, channel_group_name, data, gvtype, cmd);
g_free(channel_group_name);
channel_group_cmd, channel_group_name, data, gvtype, cmd,
channel_group_name);

/*
* Handle special cases
*/

if (cmd == SCPI_CMD_GET_OUTPUT_ENABLED) {
if (devc->device->dialect == SCPI_DIALECT_SIGLENT) {
s = g_variant_get_string(*data, NULL);
sr_atol_base(s, &regl, NULL, 16);
g_variant_unref(*data);
if (channel_group_name) {
sr_atoi(channel_group_name, &reg);
} else {
reg=1;
}
regl = (regl >> (reg+3));
*data = g_variant_new_boolean(regl & 0x01);
}
}

if (cmd == SCPI_CMD_GET_OUTPUT_REGULATION) {
if (devc->device->dialect == SCPI_DIALECT_PHILIPS) {
/*
Expand Down Expand Up @@ -504,6 +533,22 @@ static int config_get(uint32_t key, GVariant **data,
else
*data = g_variant_new_string("UR");
}
if (devc->device->dialect == SCPI_DIALECT_SIGLENT) {
/* evaluate status register */
s = g_variant_get_string(*data, NULL);
sr_atol_base(s, &regl, NULL, 16);
g_variant_unref(*data);
if (channel_group_name) {
sr_atoi(channel_group_name, &reg);
} else {
reg=1;
}
regl = (regl >> (reg-1));
if (regl & 0x01)
*data = g_variant_new_string("CC");
else
*data = g_variant_new_string("CV");
}

s = g_variant_get_string(*data, NULL);
if (g_strcmp0(s, "CV") && g_strcmp0(s, "CC") && g_strcmp0(s, "CC-") &&
Expand Down Expand Up @@ -565,6 +610,25 @@ static int config_get(uint32_t key, GVariant **data,
}
}

if (cmd == SCPI_CMD_GET_CHANNEL_CONFIG) {
if (devc->device->dialect == SCPI_DIALECT_SIGLENT) {
/* evaluate status register */
s = g_variant_get_string(*data, NULL);
sr_atol_base(s, &regl, NULL, 16);
g_variant_unref(*data);

regl = (regl >> 2) & 0x03;
if (regl == 0x02)
*data = g_variant_new_string("Parallel");
else if (regl == 0x03)
*data = g_variant_new_string("Series");
else
*data = g_variant_new_string("Independent");
}
}

g_free(channel_group_name);

return ret;
}

Expand All @@ -575,6 +639,7 @@ static int config_set(uint32_t key, GVariant *data,
double d;
int channel_group_cmd;
char *channel_group_name;
const char *s;
int ret;

if (!sdi)
Expand All @@ -594,17 +659,26 @@ static int config_set(uint32_t key, GVariant *data,
if (g_variant_get_boolean(data))
ret = sr_scpi_cmd(sdi, devc->device->commands,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_OUTPUT_ENABLE);
SCPI_CMD_SET_OUTPUT_ENABLE,
channel_group_name);
else
ret = sr_scpi_cmd(sdi, devc->device->commands,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_OUTPUT_DISABLE);
SCPI_CMD_SET_OUTPUT_DISABLE,
channel_group_name);
break;
case SR_CONF_VOLTAGE_TARGET:
d = g_variant_get_double(data);
ret = sr_scpi_cmd(sdi, devc->device->commands,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_VOLTAGE_TARGET, d);
if (devc->device->dialect == SCPI_DIALECT_SIGLENT) {
ret = sr_scpi_cmd(sdi, devc->device->commands,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_VOLTAGE_TARGET,
channel_group_name, d);
} else {
ret = sr_scpi_cmd(sdi, devc->device->commands,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_VOLTAGE_TARGET, d);
}
break;
case SR_CONF_OUTPUT_FREQUENCY_TARGET:
d = g_variant_get_double(data);
Expand All @@ -614,9 +688,16 @@ static int config_set(uint32_t key, GVariant *data,
break;
case SR_CONF_CURRENT_LIMIT:
d = g_variant_get_double(data);
ret = sr_scpi_cmd(sdi, devc->device->commands,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_CURRENT_LIMIT, d);
if (devc->device->dialect == SCPI_DIALECT_SIGLENT) {
ret = sr_scpi_cmd(sdi, devc->device->commands,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_CURRENT_LIMIT,
channel_group_name, d);
} else {
ret = sr_scpi_cmd(sdi, devc->device->commands,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_CURRENT_LIMIT, d);
}
break;
case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
if (g_variant_get_boolean(data))
Expand Down Expand Up @@ -660,6 +741,20 @@ static int config_set(uint32_t key, GVariant *data,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION_DISABLE);
break;
case SR_CONF_CHANNEL_CONFIG:
s = g_variant_get_string(data, NULL);
if (devc->device->dialect == SCPI_DIALECT_SIGLENT) {
if (!strncmp(s, "Parallel", 8))
s = "2";
else if (!strncmp(s, "Series", 6))
s = "1";
else
s = "0";
}
ret = sr_scpi_cmd(sdi, devc->device->commands,
channel_group_cmd, channel_group_name,
SCPI_CMD_SET_CHANNEL_CONFIG, s);
break;
default:
ret = sr_sw_limits_config_set(&devc->limits, key, data);
}
Expand Down
150 changes: 150 additions & 0 deletions src/hardware/scpi-pps/profiles.c
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,121 @@ static const struct scpi_command rs_hmc8043_cmd[] = {
ALL_ZERO
};

/* Siglent SPD3303 series */
static const uint32_t siglent_spd3303_devopts[] = {
SR_CONF_CONTINUOUS,
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
SR_CONF_CHANNEL_CONFIG | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
};

static const uint32_t siglent_spd3303_devopts_cg[] = {
SR_CONF_REGULATION | SR_CONF_GET,
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,
};

static const struct channel_spec siglent_spd3303x_ch[] = {
{ "1", { 0, 32, 0.001, 3, 3 }, { 0, 3.2, 0.001, 3, 3 }, { 0, 102.4 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
{ "2", { 0, 32, 0.001, 3, 3 }, { 0, 3.2, 0.001, 3, 3 }, { 0, 102.4 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
};

static const struct channel_spec siglent_spd3303xe_ch[] = {
{ "1", { 0, 32, 0.01, 2, 3 }, { 0, 3.2, 0.01, 2, 3 }, { 0, 102.4 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
{ "2", { 0, 32, 0.01, 2, 3 }, { 0, 3.2, 0.01, 2, 3 }, { 0, 102.4 }, FREQ_DC_ONLY, NO_OVP_LIMITS, NO_OCP_LIMITS },
};

static const struct channel_group_spec siglent_spd3303_cg[] = {
{ "1", CH_IDX(0), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
{ "2", CH_IDX(1), PPS_OVP | PPS_OCP, SR_MQFLAG_DC },
};

static const struct scpi_command siglent_spd3303_cmd[] = {
{ 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, "CH%s:VOLT?" },
{ SCPI_CMD_SET_VOLTAGE_TARGET, "CH%s:VOLT %.6f" },
{ SCPI_CMD_GET_CURRENT_LIMIT, "CH%s:CURR?" },
{ SCPI_CMD_SET_CURRENT_LIMIT, "CH%s:CURR %.6f" },
{ SCPI_CMD_GET_OUTPUT_REGULATION, "SYST:STAT?" },
{ SCPI_CMD_GET_OUTPUT_ENABLED, "SYST:STAT?" },
{ SCPI_CMD_SET_OUTPUT_ENABLE, "OUTP CH%s,ON" },
{ SCPI_CMD_SET_OUTPUT_DISABLE, "OUTP CH%s,OFF" },
{ SCPI_CMD_GET_CHANNEL_CONFIG, "SYST:STAT?" },
{ SCPI_CMD_SET_CHANNEL_CONFIG, "OUTP:TRACK %s" },
ALL_ZERO
};

static int siglent_spd3303_update_status(const struct sr_dev_inst *sdi)
{
struct dev_context *devc;
struct sr_scpi_dev_inst *scpi;
int ret;
char *response;
long int status_register;
uint32_t old, cur, reg, en, ch, mode;
char *mode_str, *reg_str;

scpi = sdi->conn;
devc = sdi->priv;

if (!sdi || !scpi || !devc)
return SR_ERR_ARG;

/* read status register */
ret = sr_scpi_get_string(scpi, "SYST:STAT?", &response);
if (ret != SR_OK)
return ret;
if (!response)
return SR_ERR;
sr_atol_base(response, &status_register, NULL, 16);
g_free(response);

cur = status_register;
old = devc->priv_status >> 1;

if (devc->priv_status) {
/* check for regulation/enable changes */
for (ch = 0; ch < 2; ch++) {
reg = (cur >> ch) & 0x01;
en = (cur >> (ch + 4)) & 0x01;

if (reg != ((old >> ch) & 0x01)) {
reg_str = (reg & 0x01 ? "CC" : "CV");
sr_info("regulation change: ch=%d, reg=%s", ch + 1, reg_str);
/* FIXME: send SR_CONF_REGULATION meta frame
(when API gets support for channel_group) */
}
if (en != ((old >> (ch + 4)) & 0x01)) {
sr_info("mode change: ch=%d, enabled=%d", ch + 1, en);
/* FIXME: send SR_CONF_ENABLED meta frame
(when API gets support for channel_group) */
}
}
/* check for channel mode change */
mode = (cur >> 2) & 0x03;
if (mode != ((old >> 2) & 0x03)) {
if (mode == 0x02)
mode_str = "Parallel";
else if (mode == 0x03)
mode_str = "Series";
else
mode_str = "Independent";
sr_session_send_meta(sdi, SR_CONF_CHANNEL_CONFIG,
g_variant_new_string(mode_str));
}
}

/* save current status */
devc->priv_status = (cur << 1) | 1;

return SR_OK;
}

SR_PRIV const struct scpi_pps pps_profiles[] = {
/* Agilent N5763A */
{ "Agilent", "N5763A", SCPI_DIALECT_UNKNOWN, 0,
Expand Down Expand Up @@ -1349,6 +1464,41 @@ SR_PRIV const struct scpi_pps pps_profiles[] = {
.init_acquisition = NULL,
.update_status = NULL,
},

/* Siglent SPD3303 series */
{ "Siglent Technologies", "SPD3303C", SCPI_DIALECT_SIGLENT,
PPS_INDEPENDENT | PPS_SERIES | PPS_PARALLEL,
ARRAY_AND_SIZE(siglent_spd3303_devopts),
ARRAY_AND_SIZE(siglent_spd3303_devopts_cg),
ARRAY_AND_SIZE(siglent_spd3303xe_ch),
ARRAY_AND_SIZE(siglent_spd3303_cg),
siglent_spd3303_cmd,
.probe_channels = NULL,
.init_acquisition = NULL,
.update_status = siglent_spd3303_update_status,
},
{ "Siglent Technologies", "SPD3303X", SCPI_DIALECT_SIGLENT,
PPS_INDEPENDENT | PPS_SERIES | PPS_PARALLEL,
ARRAY_AND_SIZE(siglent_spd3303_devopts),
ARRAY_AND_SIZE(siglent_spd3303_devopts_cg),
ARRAY_AND_SIZE(siglent_spd3303x_ch),
ARRAY_AND_SIZE(siglent_spd3303_cg),
siglent_spd3303_cmd,
.probe_channels = NULL,
.init_acquisition = NULL,
.update_status = siglent_spd3303_update_status,
},
{ "Siglent Technologies", "SPD3303X-E", SCPI_DIALECT_SIGLENT,
PPS_INDEPENDENT | PPS_SERIES | PPS_PARALLEL,
ARRAY_AND_SIZE(siglent_spd3303_devopts),
ARRAY_AND_SIZE(siglent_spd3303_devopts_cg),
ARRAY_AND_SIZE(siglent_spd3303xe_ch),
ARRAY_AND_SIZE(siglent_spd3303_cg),
siglent_spd3303_cmd,
.probe_channels = NULL,
.init_acquisition = NULL,
.update_status = siglent_spd3303_update_status,
},
};

SR_PRIV unsigned int num_pps_profiles = ARRAY_SIZE(pps_profiles);
3 changes: 2 additions & 1 deletion src/hardware/scpi-pps/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ SR_PRIV int scpi_pps_receive_data(int fd, int revents, void *cb_data)
}

ret = sr_scpi_cmd_resp(sdi, devc->device->commands,
channel_group_cmd, channel_group_name, &gvdata, gvtype, cmd);
channel_group_cmd, channel_group_name, &gvdata, gvtype, cmd,
channel_group_name);

if (ret != SR_OK)
return ret;
Expand Down
Loading