X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fhameg-hmo%2Fprotocol.c;h=28d8412d950d739c9da5591ace10739f46d13fb9;hb=fe227d17aeda0c460367883f57c3b683fe4798a6;hp=49f956c6aae685fec9568294f116663a5d05c61e;hpb=b1f8310376265f622c6f7d81c0cc0580598ea973;p=libsigrok.git diff --git a/src/hardware/hameg-hmo/protocol.c b/src/hardware/hameg-hmo/protocol.c index 49f956c6..28d8412d 100644 --- a/src/hardware/hameg-hmo/protocol.c +++ b/src/hardware/hameg-hmo/protocol.c @@ -17,6 +17,10 @@ * along with this program. If not, see . */ +#include +#include +#include +#include "scpi.h" #include "protocol.h" static const char *hameg_scpi_dialect[] = { @@ -166,6 +170,8 @@ static const uint64_t hmo_vdivs[][2] = { { 2, 1 }, { 5, 1 }, { 10, 1 }, + { 20, 1 }, + { 50, 1 }, }; static const char *scope_analog_channel_names[] = { @@ -196,7 +202,9 @@ static const char *scope_digital_channel_names[] = { static const struct scope_config scope_models[] = { { - .name = {"HMO722", "HMO1022", "HMO1522", "HMO2022", NULL}, + /* HMO2522/3032/3042/3052 support 16 digital channels but they're not supported yet. */ + .name = {"HMO722", "HMO1022", "HMO1522", "HMO2022", "HMO2522", + "HMO3032", "HMO3042", "HMO3052", NULL}, .analog_channels = 2, .digital_channels = 8, .digital_pods = 1, @@ -226,7 +234,9 @@ static const struct scope_config scope_models[] = { .scpi_dialect = &hameg_scpi_dialect, }, { - .name = {"HMO724", "HMO1024", "HMO1524", "HMO2024", NULL}, + /* HMO2524/3034/3044/3054 support 16 digital channels but they're not supported yet. */ + .name = {"HMO724", "HMO1024", "HMO1524", "HMO2024", "HMO2524", + "HMO3034", "HMO3044", "HMO3054", NULL}, .analog_channels = 4, .digital_channels = 8, .digital_pods = 1, @@ -263,7 +273,7 @@ static void scope_state_dump(const struct scope_config *config, unsigned int i; char *tmp; - for (i = 0; i < config->analog_channels; ++i) { + for (i = 0; i < config->analog_channels; i++) { tmp = sr_voltage_string((*config->vdivs)[state->analog_channels[i].vdiv][0], (*config->vdivs)[state->analog_channels[i].vdiv][1]); sr_info("State of analog channel %d -> %s : %s (coupling) %s (vdiv) %2.2e (offset)", @@ -272,12 +282,12 @@ static void scope_state_dump(const struct scope_config *config, tmp, state->analog_channels[i].vertical_offset); } - for (i = 0; i < config->digital_channels; ++i) { + for (i = 0; i < config->digital_channels; i++) { sr_info("State of digital channel %d -> %s", i, state->digital_channels[i] ? "On" : "Off"); } - for (i = 0; i < config->digital_pods; ++i) { + for (i = 0; i < config->digital_pods; i++) { sr_info("State of digital POD %d -> %s", i, state->digital_pods[i] ? "On" : "Off"); } @@ -308,7 +318,7 @@ static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi, return SR_ERR; } - for (i = 0; (*array)[i]; ++i) { + for (i = 0; (*array)[i]; i++) { if (!g_strcmp0(tmp, (*array)[i])) { *result = i; g_free(tmp); @@ -325,15 +335,77 @@ static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi, return SR_OK; } +/** + * This function takes a value of the form "2.000E-03", converts it to a + * significand / factor pair and returns the index of an array where + * a matching pair was found. + * + * It's a bit convoluted because of floating-point issues. The value "10.00E-09" + * is parsed by g_ascii_strtod() as 0.000000009999999939, for example. + * Therefore it's easier to break the number up into two strings and handle + * them separately. + * + * @param value The string to be parsed. + * @param array The array of s/f pairs. + * @param array_len The number of pairs in the array. + * @param result The index at which a matching pair was found. + * + * @return SR_ERR on any parsing error, SR_OK otherwise. + */ +static int array_float_get(gchar *value, const uint64_t array[][2], + int array_len, unsigned int *result) +{ + int i; + uint64_t f; + float s; + unsigned int s_int; + gchar ss[10], es[10]; + + memset(ss, 0, sizeof(ss)); + memset(es, 0, sizeof(es)); + + strncpy(ss, value, 5); + strncpy(es, &(value[6]), 3); + + if (sr_atof_ascii(ss, &s) != SR_OK) + return SR_ERR; + if (sr_atoi(es, &i) != SR_OK) + return SR_ERR; + + /* Transform e.g. 10^-03 to 1000 as the array stores the inverse. */ + f = pow(10, abs(i)); + + /* + * Adjust the significand/factor pair to make sure + * that f is a multiple of 1000. + */ + while ((int)fmod(log10(f), 3) > 0) { + s *= 10; + f *= 10; + } + + /* Truncate s to circumvent rounding errors. */ + s_int = (unsigned int)s; + + for (i = 0; i < array_len; i++) { + if ((s_int == array[i][0]) && (f == array[i][1])) { + *result = i; + return SR_OK; + } + } + + return SR_ERR; +} + static int analog_channel_state_get(struct sr_scpi_dev_inst *scpi, const struct scope_config *config, struct scope_state *state) { unsigned int i, j; - float tmp_float; char command[MAX_COMMAND_SIZE]; + char *tmp_str; - for (i = 0; i < config->analog_channels; ++i) { + for (i = 0; i < config->analog_channels; i++) { g_snprintf(command, sizeof(command), (*config->scpi_dialect)[SCPI_CMD_GET_ANALOG_CHAN_STATE], i + 1); @@ -346,20 +418,19 @@ static int analog_channel_state_get(struct sr_scpi_dev_inst *scpi, (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_DIV], i + 1); - if (sr_scpi_get_float(scpi, command, &tmp_float) != SR_OK) + if (sr_scpi_get_string(scpi, command, &tmp_str) != SR_OK) return SR_ERR; - for (j = 0; j < config->num_vdivs; j++) { - if (tmp_float == ((float) (*config->vdivs)[j][0] / - (*config->vdivs)[j][1])) { - state->analog_channels[i].vdiv = j; - break; - } - } - if (j == config->num_vdivs) { + + if (array_float_get(tmp_str, hmo_vdivs, ARRAY_SIZE(hmo_vdivs), + &j) != SR_OK) { + g_free(tmp_str); sr_err("Could not determine array index for vertical div scale."); return SR_ERR; } + g_free(tmp_str); + state->analog_channels[i].vdiv = j; + g_snprintf(command, sizeof(command), (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_OFFSET], i + 1); @@ -387,7 +458,7 @@ static int digital_channel_state_get(struct sr_scpi_dev_inst *scpi, unsigned int i; char command[MAX_COMMAND_SIZE]; - for (i = 0; i < config->digital_channels; ++i) { + for (i = 0; i < config->digital_channels; i++) { g_snprintf(command, sizeof(command), (*config->scpi_dialect)[SCPI_CMD_GET_DIG_CHAN_STATE], i); @@ -397,7 +468,7 @@ static int digital_channel_state_get(struct sr_scpi_dev_inst *scpi, return SR_ERR; } - for (i = 0; i < config->digital_pods; ++i) { + for (i = 0; i < config->digital_pods; i++) { g_snprintf(command, sizeof(command), (*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_STATE], i + 1); @@ -428,7 +499,7 @@ SR_PRIV int hmo_update_sample_rate(const struct sr_dev_inst *sdi) state = devc->model_state; channel_found = FALSE; - for (i = 0; i < config->analog_channels; ++i) { + for (i = 0; i < config->analog_channels; i++) { if (state->analog_channels[i].state) { g_snprintf(chan_name, sizeof(chan_name), "CHAN%d", i + 1); g_snprintf(tmp_str, sizeof(tmp_str), @@ -612,7 +683,7 @@ SR_PRIV int hmo_init_device(struct sr_dev_inst *sdi) } /* Add digital channel groups. */ - for (i = 0; i < scope_models[model_index].digital_pods; ++i) { + for (i = 0; i < scope_models[model_index].digital_pods; i++) { g_snprintf(tmp, 25, "POD%d", i); devc->digital_groups[i] = g_malloc0(sizeof(struct sr_channel_group)); @@ -647,7 +718,7 @@ SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data) struct dev_context *devc; struct sr_datafeed_packet packet; GArray *data; - struct sr_datafeed_analog analog; + struct sr_datafeed_analog_old analog; struct sr_datafeed_logic logic; (void)fd; @@ -660,69 +731,70 @@ SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data) if (!(devc = sdi->priv)) return TRUE; - if (revents == G_IO_IN) { - ch = devc->current_channel->data; + if (revents != G_IO_IN) + return TRUE; - switch (ch->type) { - case SR_CHANNEL_ANALOG: - if (sr_scpi_get_floatv(sdi->conn, NULL, &data) != SR_OK) { - if (data) - g_array_free(data, TRUE); + ch = devc->current_channel->data; - return TRUE; - } + switch (ch->type) { + case SR_CHANNEL_ANALOG: + if (sr_scpi_get_floatv(sdi->conn, NULL, &data) != SR_OK) { + if (data) + g_array_free(data, TRUE); - packet.type = SR_DF_FRAME_BEGIN; - sr_session_send(sdi, &packet); - - analog.channels = g_slist_append(NULL, ch); - analog.num_samples = data->len; - analog.data = (float *) data->data; - analog.mq = SR_MQ_VOLTAGE; - analog.unit = SR_UNIT_VOLT; - analog.mqflags = 0; - packet.type = SR_DF_ANALOG; - packet.payload = &analog; - sr_session_send(cb_data, &packet); - g_slist_free(analog.channels); - g_array_free(data, TRUE); - data = NULL; - break; - case SR_CHANNEL_LOGIC: - if (sr_scpi_get_uint8v(sdi->conn, NULL, &data) != SR_OK) { - g_free(data); - return TRUE; - } - - packet.type = SR_DF_FRAME_BEGIN; - sr_session_send(sdi, &packet); - - logic.length = data->len; - logic.unitsize = 1; - logic.data = data->data; - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - sr_session_send(cb_data, &packet); - g_array_free(data, TRUE); - data = NULL; - break; - default: - sr_err("Invalid channel type."); - break; + return TRUE; } - packet.type = SR_DF_FRAME_END; + packet.type = SR_DF_FRAME_BEGIN; sr_session_send(sdi, &packet); - if (devc->current_channel->next) { - devc->current_channel = devc->current_channel->next; - hmo_request_data(sdi); - } else if (++devc->num_frames == devc->frame_limit) { - sdi->driver->dev_acquisition_stop(sdi, cb_data); - } else { - devc->current_channel = devc->enabled_channels; - hmo_request_data(sdi); + analog.channels = g_slist_append(NULL, ch); + analog.num_samples = data->len; + analog.data = (float *) data->data; + analog.mq = SR_MQ_VOLTAGE; + analog.unit = SR_UNIT_VOLT; + analog.mqflags = 0; + packet.type = SR_DF_ANALOG_OLD; + packet.payload = &analog; + sr_session_send(cb_data, &packet); + g_slist_free(analog.channels); + g_array_free(data, TRUE); + data = NULL; + break; + case SR_CHANNEL_LOGIC: + if (sr_scpi_get_uint8v(sdi->conn, NULL, &data) != SR_OK) { + g_free(data); + return TRUE; } + + packet.type = SR_DF_FRAME_BEGIN; + sr_session_send(sdi, &packet); + + logic.length = data->len; + logic.unitsize = 1; + logic.data = data->data; + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + sr_session_send(cb_data, &packet); + g_array_free(data, TRUE); + data = NULL; + break; + default: + sr_err("Invalid channel type."); + break; + } + + packet.type = SR_DF_FRAME_END; + sr_session_send(sdi, &packet); + + if (devc->current_channel->next) { + devc->current_channel = devc->current_channel->next; + hmo_request_data(sdi); + } else if (++devc->num_frames == devc->frame_limit) { + sdi->driver->dev_acquisition_stop(sdi, cb_data); + } else { + devc->current_channel = devc->enabled_channels; + hmo_request_data(sdi); } return TRUE;