]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/baylibre-acme/protocol.c
baylibre-acme: Optimize reading of values from sysfs.
[libsigrok.git] / src / hardware / baylibre-acme / protocol.c
index e7f1ede1faf04d80133c2e3b49140c732b056484..dfd634bb380ee60a121b9b6f5205a5068b7f1fb4 100644 (file)
@@ -33,6 +33,7 @@ struct channel_group_priv {
 
 struct channel_priv {
        int ch_type;
+       int fd;
        struct channel_group_priv *probe;
 };
 
@@ -201,13 +202,12 @@ static void append_channel(struct sr_dev_inst *sdi, struct sr_channel_group *cg,
        cp->ch_type = type;
        cp->probe = cg->priv;
 
-       ch = sr_channel_new(devc->num_channels++,
+       ch = sr_channel_new(sdi, devc->num_channels++,
                            SR_CHANNEL_ANALOG, TRUE, name);
        g_free(name);
 
        ch->priv = cp;
        cg->channels = g_slist_append(cg->channels, ch);
-       sdi->channels = g_slist_append(sdi->channels, ch);
 }
 
 SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type,
@@ -246,6 +246,20 @@ SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type,
        return TRUE;
 }
 
+SR_PRIV int bl_acme_get_probe_type(const struct sr_channel_group *cg)
+{
+       struct channel_group_priv *cgp = cg->priv;
+
+       return cgp->probe_type;
+}
+
+SR_PRIV int bl_acme_probe_has_pws(const struct sr_channel_group *cg)
+{
+       struct channel_group_priv *cgp = cg->priv;
+
+       return sr_gpio_getval_export(pws_info_gpios[cgp->index]);
+}
+
 /*
  * Sets path to the hwmon attribute if this channel group
  * supports shunt resistance setting. The caller has to supply
@@ -282,6 +296,43 @@ static int get_shunt_path(const struct sr_channel_group *cg, GString *path)
        return ret;
 }
 
+/*
+ * Try setting the update_interval sysfs attribute for each probe according
+ * to samplerate.
+ */
+SR_PRIV void bl_acme_maybe_set_update_interval(const struct sr_dev_inst *sdi,
+                                              uint64_t samplerate)
+{
+       struct sr_channel_group *cg;
+       struct channel_group_priv *cgp;
+       GString *hwmon;
+       GSList *l;
+       FILE *fd;
+
+       for (l = sdi->channel_groups; l != NULL; l = l->next) {
+               cg = l->data;
+               cgp = cg->priv;
+
+               hwmon = g_string_sized_new(64);
+               g_string_append_printf(hwmon,
+                               "/sys/class/hwmon/hwmon%d/update_interval",
+                               cgp->hwmon_num);
+
+               if (g_file_test(hwmon->str, G_FILE_TEST_EXISTS)) {
+                       fd = g_fopen(hwmon->str, "w");
+                       if (!fd) {
+                               g_string_free(hwmon, TRUE);
+                               continue;
+                       }
+
+                       g_fprintf(fd, "%" PRIu64 "\n", 1000 / samplerate);
+                       fclose(fd);
+               }
+
+               g_string_free(hwmon, TRUE);
+       }
+}
+
 SR_PRIV int bl_acme_get_shunt(const struct sr_channel_group *cg,
                              uint64_t *shunt)
 {
@@ -329,16 +380,11 @@ 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));
-               g_string_free(path, TRUE);
-               return SR_ERR_IO;
+               ret = SR_ERR_IO;
+               goto out;
        }
 
-       g_string_free(path, TRUE);
        g_fprintf(fd, "%" PRIu64 "\n", MOHM_TO_UOHM(shunt));
-       /*
-        * XXX There's no g_fclose() in GLib. This seems to work,
-        * but is it safe?
-        */
        fclose(fd);
 
 out:
@@ -354,8 +400,7 @@ SR_PRIV int bl_acme_read_power_state(const struct sr_channel_group *cg,
 
        cgp = cg->priv;
 
-       val = sr_gpio_getval_export(pws_info_gpios[cgp->index]);
-       if (val != 1) {
+       if (!bl_acme_probe_has_pws(cg)) {
                sr_err("Probe has no power-switch");
                return SR_ERR_ARG;
        }
@@ -374,13 +419,17 @@ SR_PRIV int bl_acme_set_power_off(const struct sr_channel_group *cg,
 
        cgp = cg->priv;
 
-       val = sr_gpio_getval_export(pws_info_gpios[cgp->index]);
-       if (val != 1) {
+       if (!bl_acme_probe_has_pws(cg)) {
                sr_err("Probe has no power-switch");
                return SR_ERR_ARG;
        }
 
        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;
 }
@@ -446,10 +495,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: %s): %s",
+                       ch->name, chp->probe->hwmon_num, 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) {
@@ -460,27 +531,31 @@ 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));
                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)
@@ -508,7 +583,7 @@ 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(analog));
+       memset(&analog, 0, sizeof(struct sr_datafeed_analog));
        analog.data = &valf;
 
        /*