gwinstek-gpd: Support auto-baud detection
If the user does not specify a serialcomm configuration, try all three options from the manual.
This commit is contained in:
parent
c329b788d2
commit
c93c014f47
|
@ -51,6 +51,12 @@ static const char *channel_modes[] = {
|
||||||
"Independent",
|
"Independent",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *gpd_serialcomms[] = {
|
||||||
|
"9600/8n1",
|
||||||
|
"57600/8n1",
|
||||||
|
"115200/8n1"
|
||||||
|
};
|
||||||
|
|
||||||
static const struct gpd_model models[] = {
|
static const struct gpd_model models[] = {
|
||||||
{ GPD_2303S, "GPD-2303S",
|
{ GPD_2303S, "GPD-2303S",
|
||||||
CHANMODE_INDEPENDENT,
|
CHANMODE_INDEPENDENT,
|
||||||
|
@ -76,7 +82,7 @@ static const struct gpd_model models[] = {
|
||||||
|
|
||||||
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
{
|
{
|
||||||
const char *conn, *serialcomm;
|
const char *conn, *serialcomm, **serialcomms;
|
||||||
const struct gpd_model *model;
|
const struct gpd_model *model;
|
||||||
const struct sr_config *src;
|
const struct sr_config *src;
|
||||||
struct sr_channel *ch;
|
struct sr_channel *ch;
|
||||||
|
@ -85,7 +91,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
struct sr_serial_dev_inst *serial;
|
struct sr_serial_dev_inst *serial;
|
||||||
struct sr_dev_inst *sdi;
|
struct sr_dev_inst *sdi;
|
||||||
char reply[100];
|
char reply[100];
|
||||||
unsigned int i;
|
unsigned int i, b, serialcomms_count;
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
char channel[10];
|
char channel[10];
|
||||||
GRegex *regex;
|
GRegex *regex;
|
||||||
|
@ -112,147 +118,154 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
|
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!serialcomm)
|
if (serialcomm) {
|
||||||
serialcomm = "115200/8n1";
|
serialcomms = &serialcomm;
|
||||||
sr_info("Probing serial port %s @ %s", conn, serialcomm);
|
serialcomms_count = 1;
|
||||||
serial = sr_serial_dev_inst_new(conn, serialcomm);
|
} else {
|
||||||
if (serial_open(serial, SERIAL_RDWR) != SR_OK)
|
serialcomms = gpd_serialcomms;
|
||||||
return NULL;
|
serialcomms_count = sizeof(gpd_serialcomms) / sizeof(gpd_serialcomms[0]);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
for( b = 0; b < serialcomms_count; b++) {
|
||||||
* Problem: we need to clear the GPD receive buffer before we
|
serialcomm = serialcomms[b];
|
||||||
* can expect it to process commands correctly.
|
sr_info("Probing serial port %s @ %s", conn, serialcomm);
|
||||||
*
|
serial = sr_serial_dev_inst_new(conn, serialcomm);
|
||||||
* Do not just send a newline, since that may cause it to
|
if (serial_open(serial, SERIAL_RDWR) != SR_OK)
|
||||||
* execute a currently buffered command.
|
continue;
|
||||||
*
|
|
||||||
* Solution: Send identification request a few times.
|
/*
|
||||||
* The first should corrupt any previous buffered command if present
|
* Problem: we need to clear the GPD receive buffer before we
|
||||||
* and respond with "Invalid Character." or respond directly with
|
* can expect it to process commands correctly.
|
||||||
* an identification string starting with "GW INSTEK"
|
*
|
||||||
*/
|
* Do not just send a newline, since that may cause it to
|
||||||
for (i = 0; i<IDN_RETRIES; ++i) {
|
* execute a currently buffered command.
|
||||||
/* Request the GPD to identify itself */
|
*
|
||||||
gpd_send_cmd(serial, "*IDN?\n");
|
* Solution: Send identification request a few times.
|
||||||
if (gpd_receive_reply(serial, reply, sizeof(reply)) == SR_OK) {
|
* The first should corrupt any previous buffered command if present
|
||||||
if (0 == strncmp(reply, "GW INSTEK", 9 )) {
|
* and respond with "Invalid Character." or respond directly with
|
||||||
|
* an identification string.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < IDN_RETRIES; i++) {
|
||||||
|
/* Request the GPD to identify itself */
|
||||||
|
gpd_send_cmd(serial, "*IDN?\n");
|
||||||
|
if (gpd_receive_reply(serial, reply, sizeof(reply)) == SR_OK) {
|
||||||
|
if (0 == strncmp(reply, "GW INSTEK", 9)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == IDN_RETRIES) {
|
||||||
|
sr_err("Device did not reply to identification request.");
|
||||||
|
serial_flush(serial);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returned identification string is for example:
|
||||||
|
* "GW INSTEK,GPD-2303S,SN:ER915277,V2.10"
|
||||||
|
*/
|
||||||
|
regex = g_regex_new("GW INSTEK,(.+),SN:(.+),(V.+)", 0, 0, NULL);
|
||||||
|
if (!g_regex_match(regex, reply, 0, &match_info)) {
|
||||||
|
sr_err("Unsupported model '%s'.", reply);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
model = NULL;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(models); i++) {
|
||||||
|
if (!strcmp(g_match_info_fetch(match_info, 1), models[i].name)) {
|
||||||
|
model = &models[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!model) {
|
||||||
if (i == IDN_RETRIES) {
|
sr_err("Unsupported model '%s'.", reply);
|
||||||
sr_err("Device did not reply to identification request.");
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
sr_info("Detected model '%s'.", model->name);
|
||||||
|
|
||||||
|
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
||||||
|
sdi->status = SR_ST_INACTIVE;
|
||||||
|
sdi->vendor = g_strdup("GW Instek");
|
||||||
|
sdi->model = g_strdup(model->name);
|
||||||
|
sdi->inst_type = SR_INST_SERIAL;
|
||||||
|
sdi->conn = serial;
|
||||||
|
|
||||||
|
for (i = 0; i < model->num_channels; i++) {
|
||||||
|
snprintf(channel, sizeof(channel), "CH%d", i + 1);
|
||||||
|
ch = sr_channel_new(sdi, i, SR_CHANNEL_ANALOG, TRUE, channel);
|
||||||
|
cg = g_malloc(sizeof(struct sr_channel_group));
|
||||||
|
cg->name = g_strdup(channel);
|
||||||
|
cg->channels = g_slist_append(NULL, ch);
|
||||||
|
cg->priv = NULL;
|
||||||
|
sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
|
||||||
|
}
|
||||||
|
|
||||||
|
devc = g_malloc0(sizeof(struct dev_context));
|
||||||
|
sr_sw_limits_init(&devc->limits);
|
||||||
|
devc->model = model;
|
||||||
|
devc->config = g_malloc0(sizeof(struct per_channel_config)
|
||||||
|
* model->num_channels);
|
||||||
|
sdi->priv = devc;
|
||||||
|
|
||||||
serial_flush(serial);
|
serial_flush(serial);
|
||||||
goto error;
|
gpd_send_cmd(serial, "STATUS?\n");
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returned identification string is for example:
|
|
||||||
* "GW INSTEK,GPD-2303S,SN:ER915277,V2.10"
|
|
||||||
*/
|
|
||||||
regex = g_regex_new("GW INSTEK,(.+),SN:(.+),(V.+)", 0, 0, NULL);
|
|
||||||
if (!g_regex_match(regex, reply, 0, &match_info)) {
|
|
||||||
sr_err("Unsupported model '%s'.", reply);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
model = NULL;
|
|
||||||
for (i = 0; i < ARRAY_SIZE(models); i++) {
|
|
||||||
if (!strcmp(g_match_info_fetch(match_info, 1), models[i].name)) {
|
|
||||||
model = &models[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!model) {
|
|
||||||
sr_err("Unsupported model '%s'.", reply);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
sr_info("Detected model '%s'.", model->name);
|
|
||||||
|
|
||||||
sdi = g_malloc0(sizeof(struct sr_dev_inst));
|
|
||||||
sdi->status = SR_ST_INACTIVE;
|
|
||||||
sdi->vendor = g_strdup("GW Instek");
|
|
||||||
sdi->model = g_strdup(model->name);
|
|
||||||
sdi->inst_type = SR_INST_SERIAL;
|
|
||||||
sdi->conn = serial;
|
|
||||||
|
|
||||||
for (i = 0; i < model->num_channels; i++) {
|
|
||||||
snprintf(channel, sizeof(channel), "CH%d", i + 1);
|
|
||||||
ch = sr_channel_new(sdi, i, SR_CHANNEL_ANALOG, TRUE, channel);
|
|
||||||
cg = g_malloc(sizeof(struct sr_channel_group));
|
|
||||||
cg->name = g_strdup(channel);
|
|
||||||
cg->channels = g_slist_append(NULL, ch);
|
|
||||||
cg->priv = NULL;
|
|
||||||
sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
|
|
||||||
}
|
|
||||||
|
|
||||||
devc = g_malloc0(sizeof(struct dev_context));
|
|
||||||
sr_sw_limits_init(&devc->limits);
|
|
||||||
devc->model = model;
|
|
||||||
devc->config = g_malloc0(sizeof(struct per_channel_config)
|
|
||||||
* model->num_channels);
|
|
||||||
sdi->priv = devc;
|
|
||||||
|
|
||||||
serial_flush(serial);
|
|
||||||
gpd_send_cmd(serial, "STATUS?\n");
|
|
||||||
gpd_receive_reply(serial, reply, sizeof(reply));
|
|
||||||
|
|
||||||
if (sscanf(reply, "%1u%1u%1u%1u%1u%1u%1u%1u", &cc_cv_ch1,
|
|
||||||
&cc_cv_ch2, &track1, &track2, &beep,
|
|
||||||
&devc->output_enabled, &baud1, &baud2) != 8) {
|
|
||||||
/* old firmware (< 2.00?) responds with different format */
|
|
||||||
if (sscanf(reply, "%1u %1u %1u %1u %1u X %1u X", &cc_cv_ch1,
|
|
||||||
&cc_cv_ch2, &track1, &track2, &beep,
|
|
||||||
&devc->output_enabled) != 6) {
|
|
||||||
sr_err("Invalid reply to STATUS: '%s'.", reply);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
/* ignore remaining two lines of status message */
|
|
||||||
gpd_receive_reply(serial, reply, sizeof(reply));
|
gpd_receive_reply(serial, reply, sizeof(reply));
|
||||||
gpd_receive_reply(serial, reply, sizeof(reply));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < model->num_channels; ++i) {
|
if (sscanf(reply, "%1u%1u%1u%1u%1u%1u%1u%1u", &cc_cv_ch1,
|
||||||
gpd_send_cmd(serial, "ISET%d?\n", i + 1);
|
&cc_cv_ch2, &track1, &track2, &beep,
|
||||||
gpd_receive_reply(serial, reply, sizeof(reply));
|
&devc->output_enabled, &baud1, &baud2) != 8) {
|
||||||
if (sscanf(reply, "%f", &devc->config[i].output_current_max) != 1) {
|
/* old firmware (< 2.00?) responds with different format */
|
||||||
sr_err("Invalid reply to ISETn?: '%s'.", reply);
|
if (sscanf(reply, "%1u %1u %1u %1u %1u X %1u X", &cc_cv_ch1,
|
||||||
goto error;
|
&cc_cv_ch2, &track1, &track2, &beep,
|
||||||
|
&devc->output_enabled) != 6) {
|
||||||
|
sr_err("Invalid reply to STATUS: '%s'.", reply);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
/* ignore remaining two lines of status message */
|
||||||
|
gpd_receive_reply(serial, reply, sizeof(reply));
|
||||||
|
gpd_receive_reply(serial, reply, sizeof(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
gpd_send_cmd(serial, "VSET%d?\n", i + 1);
|
for (i = 0; i < model->num_channels; i++) {
|
||||||
gpd_receive_reply(serial, reply, sizeof(reply));
|
gpd_send_cmd(serial, "ISET%d?\n", i + 1);
|
||||||
if (sscanf(reply, "%f", &devc->config[i].output_voltage_max) != 1) {
|
gpd_receive_reply(serial, reply, sizeof(reply));
|
||||||
sr_err("Invalid reply to VSETn?: '%s'.", reply);
|
if (sscanf(reply, "%f", &devc->config[i].output_current_max) != 1) {
|
||||||
goto error;
|
sr_err("Invalid reply to ISETn?: '%s'.", reply);
|
||||||
}
|
goto error;
|
||||||
gpd_send_cmd(serial, "IOUT%d?\n", i + 1);
|
}
|
||||||
gpd_receive_reply(serial, reply, sizeof(reply));
|
|
||||||
if (sscanf(reply, "%f", &devc->config[i].output_current_last) != 1) {
|
gpd_send_cmd(serial, "VSET%d?\n", i + 1);
|
||||||
sr_err("Invalid reply to IOUTn?: '%s'.", reply);
|
gpd_receive_reply(serial, reply, sizeof(reply));
|
||||||
goto error;
|
if (sscanf(reply, "%f", &devc->config[i].output_voltage_max) != 1) {
|
||||||
}
|
sr_err("Invalid reply to VSETn?: '%s'.", reply);
|
||||||
gpd_send_cmd(serial, "VOUT%d?\n", i + 1);
|
goto error;
|
||||||
gpd_receive_reply(serial, reply, sizeof(reply));
|
}
|
||||||
if (sscanf(reply, "%f", &devc->config[i].output_voltage_last) != 1) {
|
gpd_send_cmd(serial, "IOUT%d?\n", i + 1);
|
||||||
sr_err("Invalid reply to VOUTn?: '%s'.", reply);
|
gpd_receive_reply(serial, reply, sizeof(reply));
|
||||||
goto error;
|
if (sscanf(reply, "%f", &devc->config[i].output_current_last) != 1) {
|
||||||
|
sr_err("Invalid reply to IOUTn?: '%s'.", reply);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
gpd_send_cmd(serial, "VOUT%d?\n", i + 1);
|
||||||
|
gpd_receive_reply(serial, reply, sizeof(reply));
|
||||||
|
if (sscanf(reply, "%f", &devc->config[i].output_voltage_last) != 1) {
|
||||||
|
sr_err("Invalid reply to VOUTn?: '%s'.", reply);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (match_info)
|
||||||
|
g_match_info_free(match_info);
|
||||||
|
if (regex)
|
||||||
|
g_regex_unref(regex);
|
||||||
|
if (serial)
|
||||||
|
serial_close(serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
serial_close(serial);
|
|
||||||
|
|
||||||
return std_scan_complete(di, g_slist_append(NULL, sdi));
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (match_info)
|
|
||||||
g_match_info_free(match_info);
|
|
||||||
if (regex)
|
|
||||||
g_regex_unref(regex);
|
|
||||||
if (serial)
|
|
||||||
serial_close(serial);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue