From: Bartosz Golaszewski Date: Thu, 12 Feb 2015 13:53:53 +0000 (+0100) Subject: baylibre-acme: Add support for probe factor setting. X-Git-Tag: libsigrok-0.4.0~632 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=61f2b7f74cd2d05cacb2bfb3cad2c2d67c856f47;p=libsigrok.git baylibre-acme: Add support for probe factor setting. 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 --- diff --git a/src/hardware/baylibre-acme/api.c b/src/hardware/baylibre-acme/api.c index 89d8b09e..201f9341 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 272a4ff6..22af9f97 100644 --- a/src/hardware/baylibre-acme/protocol.c +++ b/src/hardware/baylibre-acme/protocol.c @@ -21,10 +21,12 @@ #include /* strtol() */ #include #include /* open(), etc... */ +#include #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 52521188..b70182c7 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