X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fsigrok.c;h=1a0536ad4f3cd6797f198063af3eaf89e02948ca;hb=99eb08be924850cf76e3dece205d5cbf9c7d74c7;hp=9cb5e30aa96e5016f91cc71f9238337525245cbc;hpb=07a084327b6fa7e54a5101f1e9a23fee7e0721ce;p=collectd.git diff --git a/src/sigrok.c b/src/sigrok.c index 9cb5e30a..1a0536ad 100644 --- a/src/sigrok.c +++ b/src/sigrok.c @@ -31,12 +31,11 @@ /* Minimum interval between dispatches coming from this plugin. The RRD * plugin, at least, complains when written to with sub-second intervals.*/ -#define DEFAULT_MIN_DISPATCH_INTERVAL TIME_T_TO_CDTIME_T(1) +#define DEFAULT_MIN_DISPATCH_INTERVAL TIME_T_TO_CDTIME_T(0) static pthread_t sr_thread; static int sr_thread_running = FALSE; GSList *config_devices; -static struct sr_session *session = NULL; static int num_devices; static int loglevel = SR_LOG_WARN; static struct sr_context *sr_ctx; @@ -52,14 +51,14 @@ struct config_device { }; -static int cd_logger(void *cb_data, int msg_loglevel, const char *format, - va_list args) +static int sigrok_log_callback(void*cb_data __attribute__((unused)), + int msg_loglevel, const char *format, va_list args) { char s[512]; if (msg_loglevel <= loglevel) { vsnprintf(s, 512, format, args); - plugin_log(LOG_INFO, "sigrok: %s", s); + plugin_log(LOG_INFO, "sigrok plugin: %s", s); } return 0; @@ -67,41 +66,34 @@ static int cd_logger(void *cb_data, int msg_loglevel, const char *format, static int sigrok_config_device(oconfig_item_t *ci) { - oconfig_item_t *item; struct config_device *cfdev; - int ret, i; - - if (ci->values_num != 1 || ci->values[0].type != OCONFIG_TYPE_STRING) { - ERROR("Invalid device name."); - return 1; - } + int i; if (!(cfdev = malloc(sizeof(struct config_device)))) { - ERROR("malloc() failed."); - return 1; + ERROR("sigrok plugin: malloc() failed."); + return -1; + } + memset(cfdev, 0, sizeof(*cfdev)); + if (cf_util_get_string(ci, &cfdev->name)) { + free(cfdev); + WARNING("sigrok plugin: Invalid device name."); + return -1; } - memset(cfdev, 0, sizeof(struct config_device)); - cf_util_get_string(ci, &cfdev->name); cfdev->min_dispatch_interval = DEFAULT_MIN_DISPATCH_INTERVAL; for (i = 0; i < ci->children_num; i++) { - item = ci->children + i; - if (item->values_num != 1) { - ERROR("Missing value for '%s'.", item->key); - return 1; - } + oconfig_item_t *item = ci->children + i; if (!strcasecmp(item->key, "driver")) - ret = cf_util_get_string(item, &cfdev->driver); + cf_util_get_string(item, &cfdev->driver); else if (!strcasecmp(item->key, "conn")) - ret = cf_util_get_string(item, &cfdev->conn); + cf_util_get_string(item, &cfdev->conn); else if (!strcasecmp(item->key, "serialcomm")) - ret = cf_util_get_string(item, &cfdev->serialcomm); - else if (!strcasecmp(item->key, "interval")) - ret = cf_util_get_cdtime(item, &cfdev->min_dispatch_interval); - if (ret) { - ERROR("Invalid keyword '%s'.", item->key); - return 1; - } + cf_util_get_string(item, &cfdev->serialcomm); + else if (!strcasecmp(item->key, "minimuminterval")) + cf_util_get_cdtime(item, &cfdev->min_dispatch_interval); + else + WARNING("sigrok plugin: Invalid keyword \"%s\".", + item->key); } config_devices = g_slist_append(config_devices, cfdev); @@ -111,33 +103,58 @@ static int sigrok_config_device(oconfig_item_t *ci) static int sigrok_config(oconfig_item_t *ci) { - oconfig_item_t *item; - int tmp, i; + int i; for (i = 0; i < ci->children_num; i++) { - item = ci->children + i; - if (!strcasecmp(item->key, "loglevel")) { - if (cf_util_get_int(item, &tmp) || tmp < 0 || tmp > 5) { - ERROR("Invalid loglevel"); - return 1; + oconfig_item_t *item = ci->children + i; + if (strcasecmp("LogLevel", item->key) == 0) { + int status; + int tmp = -1; + + status = cf_util_get_int (item, &tmp); + if (status != 0) + continue; + else if ((tmp < 0) || (tmp > 5)) { + ERROR ("sigrok plugin: The \"LogLevel\" " + "configuration option expects " + "an integer between 0 and 5 " + "(inclusive); you provided %i.", + tmp); + continue; } loglevel = tmp; - } else if (!strcasecmp(item->key, "Device")) { - if (sigrok_config_device(item) != 0) - return 1; - } else { - ERROR("Invalid keyword '%s'.", item->key); - return 1; - } + } else if (!strcasecmp(item->key, "Device")) + sigrok_config_device(item); + else + WARNING("sigrok plugin: Invalid keyword \"%s\".", + item->key); } return 0; } -static void free_drvopts(struct sr_config *src) +static char *sigrok_value_type(const struct sr_datafeed_analog *analog) { - g_variant_unref(src->data); - g_free(src); + char *s; + + if (analog->mq == SR_MQ_VOLTAGE) + s = "voltage"; + else if (analog->mq == SR_MQ_CURRENT) + s = "current"; + else if (analog->mq == SR_MQ_FREQUENCY) + s = "frequency"; + else if (analog->mq == SR_MQ_POWER) + s = "power"; + else if (analog->mq == SR_MQ_TEMPERATURE) + s = "temperature"; + else if (analog->mq == SR_MQ_RELATIVE_HUMIDITY) + s = "humidity"; + else if (analog->mq == SR_MQ_SOUND_PRESSURE_LEVEL) + s = "spl"; + else + s = "gauge"; + + return s; } static void sigrok_feed_callback(const struct sr_dev_inst *sdi, @@ -146,15 +163,8 @@ static void sigrok_feed_callback(const struct sr_dev_inst *sdi, const struct sr_datafeed_analog *analog; struct config_device *cfdev; GSList *l; - value_t *values; + value_t value; value_list_t vl = VALUE_LIST_INIT; - int num_probes, s, p; - - if (packet->type == SR_DF_END) { - /* TODO: try to restart acquisition after a delay? */ - INFO("oops! ended"); - return; - } /* Find this device's configuration. */ cfdev = NULL; @@ -166,60 +176,125 @@ static void sigrok_feed_callback(const struct sr_dev_inst *sdi, } cfdev = NULL; } + if (!cfdev) { - ERROR("Unknown device instance in sigrok driver %s.", sdi->driver->name); + ERROR("sigrok plugin: Received data from driver \"%s\" but " + "can't find a configuration / device matching " + "it.", sdi->driver->name); return; } - if (packet->type == SR_DF_ANALOG) { - if (cdtime() - cfdev->last_dispatch < cfdev->min_dispatch_interval) - return; + if (packet->type == SR_DF_END) { + /* TODO: try to restart acquisition after a delay? */ + WARNING("sigrok plugin: acquisition for \"%s\" ended.", + cfdev->name); + return; + } - analog = packet->payload; - num_probes = g_slist_length(analog->probes); - if (!(values = malloc(sizeof(value_t) * num_probes))) { - ERROR("malloc() failed."); - return; - } - for (s = 0; s < analog->num_samples; s++) { - for (p = 0; p < num_probes; p++) { - values[s + p].gauge = analog->data[s + p]; - } - } - vl.values = values; - vl.values_len = num_probes; - sstrncpy(vl.host, hostname_g, sizeof(vl.host)); - sstrncpy(vl.plugin, "sigrok", sizeof(vl.plugin)); - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), - "%s", cfdev->name); - sstrncpy(vl.type, "gauge", sizeof(vl.type)); - plugin_dispatch_values(&vl); - - cfdev->last_dispatch = cdtime(); + if (packet->type != SR_DF_ANALOG) + return; + + if ((cfdev->min_dispatch_interval != 0) + && ((cdtime() - cfdev->last_dispatch) + < cfdev->min_dispatch_interval)) + return; + + /* Ignore all but the first sample on the first probe. */ + analog = packet->payload; + value.gauge = analog->data[0]; + vl.values = &value; + vl.values_len = 1; + sstrncpy(vl.host, hostname_g, sizeof(vl.host)); + sstrncpy(vl.plugin, "sigrok", sizeof(vl.plugin)); + ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), + "%s", cfdev->name); + sstrncpy(vl.type, sigrok_value_type(analog), sizeof(vl.type)); + + plugin_dispatch_values(&vl); + cfdev->last_dispatch = cdtime(); +} + +static void sigrok_free_drvopts(struct sr_config *src) +{ + g_variant_unref(src->data); + g_free(src); +} + +static int sigrok_init_driver(struct config_device *cfdev, + struct sr_dev_driver *drv) +{ + struct sr_config *src; + GSList *devlist, *drvopts; + char hwident[512]; + + if (sr_driver_init(sr_ctx, drv) != SR_OK) + /* Error was logged by libsigrok. */ + return -1; + + drvopts = NULL; + if (cfdev->conn) { + if (!(src = malloc(sizeof(struct sr_config)))) + return -1; + src->key = SR_CONF_CONN; + src->data = g_variant_new_string(cfdev->conn); + drvopts = g_slist_append(drvopts, src); + } + if (cfdev->serialcomm) { + if (!(src = malloc(sizeof(struct sr_config)))) + return -1; + src->key = SR_CONF_SERIALCOMM; + src->data = g_variant_new_string(cfdev->serialcomm); + drvopts = g_slist_append(drvopts, src); + } + devlist = sr_driver_scan(drv, drvopts); + g_slist_free_full(drvopts, (GDestroyNotify)sigrok_free_drvopts); + if (!devlist) { + /* Not an error, but the user should know about it. */ + WARNING("sigrok plugin: No device found for \"%s\".", + cfdev->name); + return 0; } + if (g_slist_length(devlist) > 1) { + INFO("sigrok plugin: %d sigrok devices for device entry " + "\"%s\": must be 1.", + g_slist_length(devlist), cfdev->name); + return -1; + } + cfdev->sdi = devlist->data; + g_slist_free(devlist); + ssnprintf(hwident, sizeof(hwident), "%s %s %s", + cfdev->sdi->vendor ? cfdev->sdi->vendor : "", + cfdev->sdi->model ? cfdev->sdi->model : "", + cfdev->sdi->version ? cfdev->sdi->version : ""); + INFO("sigrok plugin: Device \"%s\" is a %s", cfdev->name, hwident); + + if (sr_dev_open(cfdev->sdi) != SR_OK) + return -1; + + if (sr_session_dev_add(cfdev->sdi) != SR_OK) + return -1; + + return 1; } -static void *thread_init(void *arg) +static void *sigrok_read_thread(void *arg __attribute__((unused))) { struct sr_dev_driver *drv, **drvlist; - struct sr_config *src; - GSList *devlist, *drvopts, *l; + GSList *l; struct config_device *cfdev; int ret, i; - char hwident[512]; - - (void)arg; - sr_log_callback_set(cd_logger, NULL); + sr_log_callback_set(sigrok_log_callback, NULL); sr_log_loglevel_set(loglevel); if ((ret = sr_init(&sr_ctx)) != SR_OK) { - ERROR("Failed to initialize libsigrok: %s.", sr_strerror(ret)); + ERROR("sigrok plugin: Failed to initialize libsigrok: %s.", + sr_strerror(ret)); return NULL; } - if (!(session = sr_session_new())) + if (!sr_session_new()) return NULL; num_devices = 0; @@ -234,59 +309,22 @@ static void *thread_init(void *arg) } } if (!drv) { - ERROR("sigrok: Unknown driver '%s'.", cfdev->driver); - return NULL; - } - - if (sr_driver_init(sr_ctx, drv) != SR_OK) - return NULL; - - drvopts = NULL; - if (cfdev->conn) { - if (!(src = malloc(sizeof(struct sr_config)))) - return NULL; - src->key = SR_CONF_CONN; - src->data = g_variant_new_string(cfdev->conn); - drvopts = g_slist_append(drvopts, src); - } - if (cfdev->serialcomm) { - if (!(src = malloc(sizeof(struct sr_config)))) - return NULL; - src->key = SR_CONF_SERIALCOMM; - src->data = g_variant_new_string(cfdev->serialcomm); - drvopts = g_slist_append(drvopts, src); - } - devlist = sr_driver_scan(drv, drvopts); - g_slist_free_full(drvopts, (GDestroyNotify)free_drvopts); - if (!devlist) - /* No devices found for this driver. */ - continue; - - if (g_slist_length(devlist) > 1) { - INFO("sigrok: %d sigrok devices for device entry '%s': must be 1.", - g_slist_length(devlist), cfdev->name); + ERROR("sigrok plugin: Unknown driver \"%s\".", + cfdev->driver); return NULL; } - cfdev->sdi = devlist->data; - g_slist_free(devlist); - ssnprintf(hwident, sizeof(hwident), "%s %s %s", - cfdev->sdi->vendor ? cfdev->sdi->vendor : "", - cfdev->sdi->model ? cfdev->sdi->model : "", - cfdev->sdi->version ? cfdev->sdi->version : ""); - INFO("sigrok: Device '%s' is a %s.", cfdev->name, hwident); - - if (sr_dev_open(cfdev->sdi) != SR_OK) - return NULL; - if (sr_session_dev_add(cfdev->sdi) != SR_OK) + if ((ret = sigrok_init_driver(cfdev, drv)) < 0) + /* Error was already logged. */ return NULL; - num_devices++; + num_devices += ret; } if (num_devices > 0) { /* Do this only when we're sure there's hardware to talk to. */ - if (sr_session_datafeed_callback_add(sigrok_feed_callback, NULL) != SR_OK) + if (sr_session_datafeed_callback_add(sigrok_feed_callback, NULL) + != SR_OK) return NULL; /* Start acquisition on all devices. */ @@ -315,12 +353,17 @@ static int sigrok_init(void) int status; if (sr_thread_running) { - ERROR("sigrok: Thread already running."); + ERROR("sigrok plugin: Thread already running."); return -1; } - if ((status = plugin_thread_create(&sr_thread, NULL, thread_init, NULL)) != 0) { - ERROR("sigrok: Failed to create thread: %s.", strerror(status)); + status = plugin_thread_create(&sr_thread, NULL, sigrok_read_thread, + NULL); + if (status != 0) + { + char errbuf[1024]; + ERROR("sigrok plugin: Failed to create thread: %s.", + sstrerror (errno, errbuf, sizeof (errbuf))); return -1; } sr_thread_running = TRUE; @@ -353,9 +396,7 @@ static int sigrok_shutdown(void) void module_register(void) { - plugin_register_complex_config("sigrok", sigrok_config); plugin_register_init("sigrok", sigrok_init); plugin_register_shutdown("sigrok", sigrok_shutdown); - }