X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fbaylibre-acme%2Fprotocol.c;h=cba1f7c0edb7f2caee2f70649f88fbf79f1b164d;hb=6433156c3275df933e4bf6dcfb020c91fca0ae86;hp=86fe020b345115690f903345392b38288e5ebe68;hpb=4cd97e5ad7bb63cb90d209506464fafd9f9eef8a;p=libsigrok.git diff --git a/src/hardware/baylibre-acme/protocol.c b/src/hardware/baylibre-acme/protocol.c index 86fe020b..cba1f7c0 100644 --- a/src/hardware/baylibre-acme/protocol.c +++ b/src/hardware/baylibre-acme/protocol.c @@ -33,6 +33,8 @@ struct channel_group_priv { struct channel_priv { int ch_type; + int fd; + float val; struct channel_group_priv *probe; }; @@ -378,7 +380,7 @@ SR_PRIV int bl_acme_set_shunt(const struct sr_channel_group *cg, uint64_t shunt) */ fd = g_fopen(path->str, "w"); if (!fd) { - sr_err("Error opening %s: %s", path->str, strerror(errno)); + sr_err("Error opening %s: %s", path->str, g_strerror(errno)); ret = SR_ERR_IO; goto out; } @@ -414,6 +416,7 @@ SR_PRIV int bl_acme_set_power_off(const struct sr_channel_group *cg, gboolean off) { struct channel_group_priv *cgp; + int val; cgp = cg->priv; @@ -422,7 +425,12 @@ SR_PRIV int bl_acme_set_power_off(const struct sr_channel_group *cg, return SR_ERR_ARG; } - sr_gpio_setval_export(pws_gpios[cgp->index], off ? 0 : 1); + val = sr_gpio_setval_export(pws_gpios[cgp->index], off ? 0 : 1); + if (val < 0) { + sr_err("Error setting power-off state: gpio: %d", + pws_gpios[cgp->index]); + return SR_ERR_IO; + } return SR_OK; } @@ -488,10 +496,32 @@ static float adjust_data(int val, int type) static float read_sample(struct sr_channel *ch) { struct channel_priv *chp; - char path[64], *file, buf[16]; + char buf[16]; ssize_t len; int fd; + chp = ch->priv; + fd = chp->fd; + + lseek(fd, 0, SEEK_SET); + + len = read(fd, buf, sizeof(buf)); + if (len < 0) { + sr_err("Error reading from channel %s (hwmon: %d): %s", + ch->name, chp->probe->hwmon_num, g_strerror(errno)); + ch->enabled = FALSE; + return -1.0; + } + + return adjust_data(strtol(buf, NULL, 10), chp->ch_type); +} + +SR_PRIV int bl_acme_open_channel(struct sr_channel *ch) +{ + struct channel_priv *chp; + char path[64], *file; + int fd; + chp = ch->priv; switch (chp->ch_type) { @@ -502,40 +532,45 @@ static float read_sample(struct sr_channel *ch) case TEMP_OUT: file = "temp2_input"; break; default: sr_err("Invalid channel type: %d.", chp->ch_type); - return -1.0; + return SR_ERR; } snprintf(path, sizeof(path), "/sys/class/hwmon/hwmon%d/%s", chp->probe->hwmon_num, file); + fd = open(path, O_RDONLY); if (fd < 0) { - sr_err("Error opening %s: %s", path, strerror(errno)); + sr_err("Error opening %s: %s", path, g_strerror(errno)); ch->enabled = FALSE; - return -1.0; + return SR_ERR; } - len = read(fd, buf, sizeof(buf)); - close(fd); - if (len < 0) { - sr_err("Error reading from %s: %s", path, strerror(errno)); - ch->enabled = FALSE; - return -1.0; - } + chp->fd = fd; - return adjust_data(strtol(buf, NULL, 10), chp->ch_type); + return 0; +} + +SR_PRIV void bl_acme_close_channel(struct sr_channel *ch) +{ + struct channel_priv *chp; + + chp = ch->priv; + close(chp->fd); + chp->fd = -1; } SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data) { - uint32_t cur_time, elapsed_time, diff_time; - int64_t time_to_sleep; + uint32_t cur_time, elapsed_time; + uint64_t nrexpiration; struct sr_datafeed_packet packet, framep; struct sr_datafeed_analog analog; struct sr_dev_inst *sdi; struct sr_channel *ch; + struct channel_priv *chp; struct dev_context *devc; GSList *chl, chonly; - float valf; + unsigned i; (void)fd; (void)revents; @@ -551,44 +586,66 @@ SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data) packet.type = SR_DF_ANALOG; packet.payload = &analog; memset(&analog, 0, sizeof(struct sr_datafeed_analog)); - analog.data = &valf; - /* - * Reading from sysfs takes some time - try to keep up with samplerate. - */ - if (devc->samples_read) { - cur_time = g_get_monotonic_time(); - diff_time = cur_time - devc->last_sample_fin; - time_to_sleep = G_USEC_PER_SEC / devc->samplerate - diff_time; - if (time_to_sleep > 0) - g_usleep(time_to_sleep); + if (read(devc->timer_fd, &nrexpiration, sizeof(nrexpiration)) < 0) { + sr_warn("Failed to read timer information"); + return TRUE; } - framep.type = SR_DF_FRAME_BEGIN; - sr_session_send(cb_data, &framep); + /* + * We were not able to process the previous timer expiration, we are + * overloaded. + */ + if (nrexpiration > 1) + devc->samples_missed += nrexpiration - 1; /* - * Due to different units used in each channel we're sending - * samples one-by-one. + * XXX This is a nasty workaround... + * + * At high sampling rates and maximum channels we are not able to + * acquire samples fast enough, even though frontends still think + * that samples arrive on time. This causes shifts in frontend + * plots. + * + * To compensate for the delay we check if any clock events were + * missed and - if so - don't really read the next value, but send + * the same sample as fast as possible. We do it until we are back + * on schedule. + * + * At high sampling rate this doesn't seem to visibly reduce the + * accuracy. */ - for (chl = sdi->channels; chl; chl = chl->next) { - ch = chl->data; - if (!ch->enabled) - continue; - chonly.next = NULL; - chonly.data = ch; - analog.channels = &chonly; - analog.num_samples = 1; - analog.mq = channel_to_mq(chl->data); - analog.unit = channel_to_unit(ch); - - valf = read_sample(ch); - - sr_session_send(cb_data, &packet); - } + for (i = 0; i < nrexpiration; i++) { + framep.type = SR_DF_FRAME_BEGIN; + sr_session_send(cb_data, &framep); + + /* + * Due to different units used in each channel we're sending + * samples one-by-one. + */ + for (chl = sdi->channels; chl; chl = chl->next) { + ch = chl->data; + chp = ch->priv; + + if (!ch->enabled) + continue; + chonly.next = NULL; + chonly.data = ch; + analog.channels = &chonly; + analog.num_samples = 1; + analog.mq = channel_to_mq(chl->data); + analog.unit = channel_to_unit(ch); + + if (i < 1) + chp->val = read_sample(ch); + + analog.data = &chp->val; + sr_session_send(cb_data, &packet); + } - framep.type = SR_DF_FRAME_END; - sr_session_send(cb_data, &framep); + framep.type = SR_DF_FRAME_END; + sr_session_send(cb_data, &framep); + } devc->samples_read++; if (devc->limit_samples > 0 &&