Implement support for SR_CONF_PROBE_FACTOR setting in BayLibre ACME driver. Given the channel-group parameter this allows to set the shunt resistance for each probe.
Signed-off-by: Bartosz Golaszewski <bgolaszew...@baylibre.com> --- src/hardware/baylibre-acme/api.c | 18 ++++-- src/hardware/baylibre-acme/protocol.c | 108 ++++++++++++++++++++++++++++++++++ src/hardware/baylibre-acme/protocol.h | 5 ++ 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/src/hardware/baylibre-acme/api.c b/src/hardware/baylibre-acme/api.c index 89d8b09..201f934 100644 --- a/src/hardware/baylibre-acme/api.c +++ b/src/hardware/baylibre-acme/api.c @@ -27,6 +27,7 @@ static const uint32_t devopts[] = { SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET, SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_PROBE_FACTOR | SR_CONF_GET | SR_CONF_SET, }; #define MAX_SAMPLE_RATE 500 /* In Hz */ @@ -168,8 +169,7 @@ static int config_get(uint32_t key, GVariant **data, { struct dev_context *devc; int ret; - - (void)cg; + uint64_t shunt; devc = sdi->priv; @@ -184,6 +184,13 @@ static int config_get(uint32_t key, GVariant **data, case SR_CONF_SAMPLERATE: *data = g_variant_new_uint64(devc->samplerate); break; + case SR_CONF_PROBE_FACTOR: + if (!cg) + return SR_ERR_CHANNEL_GROUP; + ret = bl_acme_get_shunt(cg, &shunt); + if (ret == SR_OK) + *data = g_variant_new_uint64(shunt); + break; default: return SR_ERR_NA; } @@ -199,8 +206,6 @@ static int config_set(uint32_t key, GVariant *data, uint64_t samplerate; int ret; - (void)cg; - if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; @@ -229,6 +234,11 @@ static int config_set(uint32_t key, GVariant *data, devc->samplerate = samplerate; sr_dbg("Setting samplerate to %" PRIu64, devc->samplerate); break; + case SR_CONF_PROBE_FACTOR: + if (!cg) + return SR_ERR_CHANNEL_GROUP; + ret = bl_acme_set_shunt(cg, g_variant_get_uint64(data)); + break; default: ret = SR_ERR_NA; } diff --git a/src/hardware/baylibre-acme/protocol.c b/src/hardware/baylibre-acme/protocol.c index 272a4ff..22af9f9 100644 --- a/src/hardware/baylibre-acme/protocol.c +++ b/src/hardware/baylibre-acme/protocol.c @@ -21,10 +21,12 @@ #include <stdlib.h> /* strtol() */ #include <errno.h> #include <fcntl.h> /* open(), etc... */ +#include <glib/gstdio.h> #include "protocol.h" struct channel_group_priv { int hwmon_num; + int probe_type; }; struct channel_priv { @@ -40,6 +42,9 @@ static const uint8_t temp_i2c_addrs[] = { 0x0, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x4f, 0x4b, }; +#define MOHM_TO_UOHM(x) ((x) * 1000) +#define UOHM_TO_MOHM(x) ((x) / 1000) + SR_PRIV uint8_t bl_acme_get_enrg_addr(int index) { return enrg_i2c_addrs[index]; @@ -212,6 +217,7 @@ SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type, cg = g_malloc0(sizeof(struct sr_channel_group)); cgp = g_malloc0(sizeof(struct channel_group_priv)); cgp->hwmon_num = hwmon; + cgp->probe_type = type; cg->name = g_strdup_printf("Probe_%d", prb_num); cg->priv = cgp; @@ -231,6 +237,108 @@ SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type, return TRUE; } +/* + * Sets path to the hwmon attribute if this channel group + * supports shunt resistance setting. The caller has to supply + * a valid GString. + */ +static int get_shunt_path(const struct sr_channel_group *cg, GString *path) +{ + struct channel_group_priv *cgp; + int ret = SR_OK, status; + + cgp = cg->priv; + + if (cgp->probe_type != PROBE_ENRG) { + sr_err("Probe doesn't support shunt resistance setting"); + return SR_ERR_ARG; + } + + g_string_append_printf(path, + "/sys/class/hwmon/hwmon%d/shunt_resistor", + cgp->hwmon_num); + + /* + * The shunt_resistor sysfs attribute is available + * in the Linux kernel since version 3.20. We have + * to notify the user if this attribute is not + * present. + */ + status = g_file_test(path->str, G_FILE_TEST_EXISTS); + if (!status) { + sr_err("shunt_resistance attribute not present please update " + "your kernel to version >=3.20"); + return SR_ERR_NA; + } + + return ret; +} + +SR_PRIV int bl_acme_get_shunt(const struct sr_channel_group *cg, + uint64_t *shunt) +{ + GString *path = g_string_sized_new(64); + gchar *contents; + int status, ret = SR_OK; + GError *err = NULL; + + status = get_shunt_path(cg, path); + if (status != SR_OK) { + ret = status; + goto out; + } + + status = g_file_get_contents(path->str, &contents, NULL, &err); + if (!status) { + sr_err("Error reading shunt resistance: %s", err->message); + ret = SR_ERR_IO; + goto out; + } + + *shunt = UOHM_TO_MOHM(strtol(contents, NULL, 10)); + +out: + g_string_free(path, TRUE); + return ret; +} + +SR_PRIV int bl_acme_set_shunt(const struct sr_channel_group *cg, + uint64_t shunt) +{ + GString *path = g_string_sized_new(64);; + int status, ret = SR_OK; + FILE *fd; + + status = get_shunt_path(cg, path); + if (status != SR_OK) { + ret = status; + goto out; + } + + /* + * Can't use g_file_set_contents() here, as it calls open() with + * O_EXEC flag in a sysfs directory thus failing with EACCES. + */ + 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; + } + + g_string_free(path, TRUE); + g_fprintf(fd, "%llu\n", MOHM_TO_UOHM(shunt)); + /* + * XXX There's no g_fclose() in GLib. This seems to work, + * but is it safe? + */ + fclose(fd); + +out: + g_string_free(path, TRUE); + return ret; +} + static int channel_to_mq(struct sr_channel *ch) { struct channel_priv *chp; diff --git a/src/hardware/baylibre-acme/protocol.h b/src/hardware/baylibre-acme/protocol.h index 5252118..b70182c 100644 --- a/src/hardware/baylibre-acme/protocol.h +++ b/src/hardware/baylibre-acme/protocol.h @@ -81,6 +81,11 @@ SR_PRIV gboolean bl_acme_detect_probe(unsigned int addr, SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type, unsigned int addr, int prb_num); +SR_PRIV int bl_acme_get_shunt(const struct sr_channel_group *cg, + uint64_t *shunt); +SR_PRIV int bl_acme_set_shunt(const struct sr_channel_group *cg, + uint64_t shunt); + SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data); #endif -- 2.1.4 ------------------------------------------------------------------------------ Dive into the World of Parallel Programming. The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ _______________________________________________ sigrok-devel mailing list sigrok-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/sigrok-devel