From 8a1c0d2218b10be7d8c3a93aa8d2559d66ec2ed2 Mon Sep 17 00:00:00 2001 From: Ivan Churkin Date: Wed, 31 May 2023 00:21:29 +0100 Subject: [PATCH 1/2] Support for Korad KKG305P Support for KKG305P with new quirk. korad_kaxxxxp_send_cmd() changed in a way to support adding new line termination. STATUS parsed according to Korad "documentation". New flags in device structure to support status of remote sensing status and external control interface status. --- src/hardware/korad-kaxxxxp/api.c | 14 +++- src/hardware/korad-kaxxxxp/protocol.c | 96 +++++++++++++++++++++------ src/hardware/korad-kaxxxxp/protocol.h | 17 +++-- 3 files changed, 98 insertions(+), 29 deletions(-) diff --git a/src/hardware/korad-kaxxxxp/api.c b/src/hardware/korad-kaxxxxp/api.c index d36dc3581..f6db50051 100644 --- a/src/hardware/korad-kaxxxxp/api.c +++ b/src/hardware/korad-kaxxxxp/api.c @@ -60,6 +60,8 @@ static const struct korad_kaxxxxp_model models[] = { {"Korad", "KA3005P", "", 1, volts_30, amps_5, KORAD_QUIRK_ID_TRAILING}, {"Korad", "KD3005P", "", 1, volts_30, amps_5, 0}, + {"Korad", "KKG305P", "", 1, volts_30, amps_5, + KORAD_QUIRK_KKG_FAMILY}, {"Korad", "KD6005P", "", 1, volts_60, amps_5, 0}, {"RND", "KA3005P", "RND 320-KA3005P", 1, volts_30, amps_5, KORAD_QUIRK_ID_OPT_VERSION}, @@ -276,10 +278,20 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) len = sizeof(reply) - 1; sr_dbg("Want max %zu bytes.", len); - ret = korad_kaxxxxp_send_cmd(serial, "*IDN?"); + ret = korad_kaxxxxp_send_cmd(serial, "*IDN?", FALSE); if (ret < 0) return NULL; + ret = korad_kaxxxxp_read_chars(serial, len, reply); + if (ret == 0) { + /* + * Make an attemp to send line termination + */ + sr_dbg("Make an attempt to send line termination"); + ret = korad_kaxxxxp_send_cmd(serial, "\n", FALSE); + if (ret < 0) + return NULL; + } ret = korad_kaxxxxp_read_chars(serial, len, reply); if (ret < 0) return NULL; diff --git a/src/hardware/korad-kaxxxxp/protocol.c b/src/hardware/korad-kaxxxxp/protocol.c index c52bd9011..4bc4780ee 100644 --- a/src/hardware/korad-kaxxxxp/protocol.c +++ b/src/hardware/korad-kaxxxxp/protocol.c @@ -24,16 +24,29 @@ #define DEVICE_PROCESSING_TIME_MS 80 SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial, - const char *cmd) + const char *cmd, const gboolean nl_termination) { int ret; + uint32_t cmd_len; + char *_cmd; + + cmd_len = strlen(cmd); + // '\n' + '\0' + _cmd = g_malloc0(cmd_len+2); + strcpy(_cmd, cmd); + + if( nl_termination ) { + _cmd[cmd_len] = '\n'; + _cmd[++cmd_len] = '\0'; - sr_dbg("Sending '%s'.", cmd); - if ((ret = serial_write_blocking(serial, cmd, strlen(cmd), 0)) < 0) { - sr_err("Error sending command: %d.", ret); - return ret; } + sr_dbg("Sending '%s'.", _cmd); + if ((ret = serial_write_blocking(serial, _cmd, cmd_len, 0)) < 0) { + sr_err("Error sending command: %d.", ret); + } + g_free(_cmd); + return ret; } @@ -171,10 +184,13 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial, const char *cmd; float value; int ret; + gboolean nl_termination; g_mutex_lock(&devc->rw_mutex); give_device_time_to_process(devc); + nl_termination = devc->model->quirks & KORAD_QUIRK_KKG_FAMILY; + switch (target) { case KAXXXXP_CURRENT: case KAXXXXP_VOLTAGE: @@ -242,7 +258,7 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial, if (cmd) sr_snprintf_ascii(msg, 20, cmd, value); - ret = korad_kaxxxxp_send_cmd(serial, msg); + ret = korad_kaxxxxp_send_cmd(serial, msg, nl_termination); devc->req_sent_at = g_get_monotonic_time(); g_free(msg); @@ -260,9 +276,11 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial, char status_byte; gboolean needs_ovp_quirk; gboolean prev_status; + gboolean nl_termination; g_mutex_lock(&devc->rw_mutex); give_device_time_to_process(devc); + nl_termination = devc->model->quirks & KORAD_QUIRK_KKG_FAMILY; value = NULL; count = 5; @@ -270,22 +288,22 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial, switch (target) { case KAXXXXP_CURRENT: /* Read current from device. */ - ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?"); + ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?", nl_termination); value = &(devc->current); break; case KAXXXXP_CURRENT_LIMIT: /* Read set current from device. */ - ret = korad_kaxxxxp_send_cmd(serial, "ISET1?"); + ret = korad_kaxxxxp_send_cmd(serial, "ISET1?", nl_termination); value = &(devc->current_limit); break; case KAXXXXP_VOLTAGE: /* Read voltage from device. */ - ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?"); + ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?", nl_termination); value = &(devc->voltage); break; case KAXXXXP_VOLTAGE_TARGET: /* Read set voltage from device. */ - ret = korad_kaxxxxp_send_cmd(serial, "VSET1?"); + ret = korad_kaxxxxp_send_cmd(serial, "VSET1?", nl_termination); value = &(devc->voltage_target); break; case KAXXXXP_STATUS: @@ -293,7 +311,7 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial, case KAXXXXP_OCP: case KAXXXXP_OVP: /* Read status from device. */ - ret = korad_kaxxxxp_send_cmd(serial, "STATUS?"); + ret = korad_kaxxxxp_send_cmd(serial, "STATUS?", nl_termination); count = 1; break; default: @@ -323,16 +341,35 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial, prev_status = devc->cc_mode[0]; devc->cc_mode[0] = !(status_byte & (1 << 0)); devc->cc_mode_1_changed = devc->cc_mode[0] != prev_status; + + if( devc->model->quirks & KORAD_QUIRK_KKG_FAMILY) { + /* + * KKG family status bits are different + * BIT1 - remote compensation status + * BIT2 - external interface (trigger, switch) status + */ + /* Remote compensation */ + prev_status = devc->rmt_comp_enabled; + devc->rmt_comp_enabled = !(status_byte & (1 << 1)); + devc->rmt_comp_changed = devc->rmt_comp_enabled != prev_status; + + /* External interface */ + prev_status = devc->ext_int_enabled; + devc->ext_int_enabled = !(status_byte & (1 << 2)); + devc->ext_int_changed = devc->ext_int_enabled != prev_status; + } else { /* Constant current channel two. */ prev_status = devc->cc_mode[1]; devc->cc_mode[1] = !(status_byte & (1 << 1)); devc->cc_mode_2_changed = devc->cc_mode[1] != prev_status; + } /* * Tracking: * status_byte & ((1 << 2) | (1 << 3)) * 00 independent 01 series 11 parallel */ + devc->beep_enabled = status_byte & (1 << 4); /* OCP enabled. */ @@ -354,17 +391,32 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial, } sr_dbg("Status: 0x%02x", status_byte); - sr_spew("Status: CH1: constant %s CH2: constant %s. " - "Tracking would be %s and %s. Output is %s. " - "OCP is %s, OVP is %s. Device is %s.", - (status_byte & (1 << 0)) ? "voltage" : "current", - (status_byte & (1 << 1)) ? "voltage" : "current", - (status_byte & (1 << 2)) ? "parallel" : "series", - (status_byte & (1 << 3)) ? "tracking" : "independent", - (status_byte & (1 << 6)) ? "enabled" : "disabled", - (status_byte & (1 << 5)) ? "enabled" : "disabled", - (status_byte & (1 << 7)) ? "enabled" : "disabled", - (status_byte & (1 << 4)) ? "beeping" : "silent"); + if( devc->model->quirks & KORAD_QUIRK_KKG_FAMILY) { + sr_spew("Status: CH1: constant %s. " + "Remote compensation: %s. External interface: %s " + "Reserved bit %s. Output is %s. " + "OCP is %s, OVP is %s. Device is %s.", + (status_byte & (1 << 0)) ? "voltage" : "current", + (status_byte & (1 << 1)) ? "enabled" : "disabled", + (status_byte & (1 << 2)) ? "enabled" : "disabled", + (status_byte & (1 << 3)) ? "1" : "0", + (status_byte & (1 << 6)) ? "enabled" : "disabled", + (status_byte & (1 << 5)) ? "enabled" : "disabled", + (status_byte & (1 << 7)) ? "enabled" : "disabled", + (status_byte & (1 << 4)) ? "beeping" : "silent"); + } else { + sr_spew("Status: CH1: constant %s CH2: constant %s. " + "Tracking would be %s and %s. Output is %s. " + "OCP is %s, OVP is %s. Device is %s.", + (status_byte & (1 << 0)) ? "voltage" : "current", + (status_byte & (1 << 1)) ? "voltage" : "current", + (status_byte & (1 << 2)) ? "parallel" : "series", + (status_byte & (1 << 3)) ? "tracking" : "independent", + (status_byte & (1 << 6)) ? "enabled" : "disabled", + (status_byte & (1 << 5)) ? "enabled" : "disabled", + (status_byte & (1 << 7)) ? "enabled" : "disabled", + (status_byte & (1 << 4)) ? "beeping" : "silent"); + } } /* Read the sixth byte from ISET? BUG workaround. */ diff --git a/src/hardware/korad-kaxxxxp/protocol.h b/src/hardware/korad-kaxxxxp/protocol.h index 9dcc19cac..66346594f 100644 --- a/src/hardware/korad-kaxxxxp/protocol.h +++ b/src/hardware/korad-kaxxxxp/protocol.h @@ -37,7 +37,8 @@ enum korad_quirks_flag { KORAD_QUIRK_ID_NO_VENDOR = 1UL << 1, KORAD_QUIRK_ID_TRAILING = 1UL << 2, KORAD_QUIRK_ID_OPT_VERSION = 1UL << 3, - KORAD_QUIRK_ALL = (1UL << 4) - 1, + KORAD_QUIRK_KKG_FAMILY = 1UL << 4, + KORAD_QUIRK_ALL = (1UL << 5) - 1, }; /* Information on single model */ @@ -79,16 +80,20 @@ struct dev_context { float voltage_target; /**< Output voltage set. */ gboolean cc_mode[2]; /**< Device is in CC mode (otherwise CV). */ - gboolean output_enabled; /**< Is the output enabled? */ - gboolean beep_enabled; /**< Enable beeper. */ - gboolean ocp_enabled; /**< Output current protection enabled. */ - gboolean ovp_enabled; /**< Output voltage protection enabled. */ + gboolean output_enabled; /**< Is the output enabled? */ + gboolean beep_enabled; /**< Enable beeper. */ + gboolean ocp_enabled; /**< Output current protection enabled. */ + gboolean ovp_enabled; /**< Output voltage protection enabled. */ + gboolean rmt_comp_enabled; /**< Is remote compensation enabled. */ + gboolean ext_int_enabled; /**< Is external interface enabled. */ gboolean cc_mode_1_changed; /**< CC mode of channel 1 has changed. */ gboolean cc_mode_2_changed; /**< CC mode of channel 2 has changed. */ gboolean output_enabled_changed; /**< Output enabled state has changed. */ gboolean ocp_enabled_changed; /**< OCP enabled state has changed. */ gboolean ovp_enabled_changed; /**< OVP enabled state has changed. */ + gboolean rmt_comp_changed; /**< Is remote compensation enabled. */ + gboolean ext_int_changed; /**< Is external interface enabled. */ int acquisition_target; /**< What reply to expect. */ int program; /**< Program to store or recall. */ @@ -102,7 +107,7 @@ struct dev_context { }; SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial, - const char *cmd); + const char *cmd, const gboolean nl_termination); SR_PRIV int korad_kaxxxxp_read_chars(struct sr_serial_dev_inst *serial, size_t count, char *buf); SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial, From d4726c18019c5b84d1b7458e0a3bcfbebbf5f592 Mon Sep 17 00:00:00 2001 From: Ivan Churkin Date: Wed, 31 May 2023 00:41:20 +0100 Subject: [PATCH 2/2] Fix un-conditional double read --- src/hardware/korad-kaxxxxp/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/korad-kaxxxxp/api.c b/src/hardware/korad-kaxxxxp/api.c index f6db50051..5b9af8135 100644 --- a/src/hardware/korad-kaxxxxp/api.c +++ b/src/hardware/korad-kaxxxxp/api.c @@ -291,8 +291,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) ret = korad_kaxxxxp_send_cmd(serial, "\n", FALSE); if (ret < 0) return NULL; + ret = korad_kaxxxxp_read_chars(serial, len, reply); } - ret = korad_kaxxxxp_read_chars(serial, len, reply); if (ret < 0) return NULL; sr_dbg("Received: %d, %s", ret, reply);