From: Andreas Sandberg Date: Fri, 6 Mar 2020 14:41:19 +0000 (+0000) Subject: binary_helpers: Add helper for devices with binary data X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=18698b40d19fa4b15000a2d29c1dee85df0f578f;p=libsigrok.git binary_helpers: Add helper for devices with binary data Many devices receive a struct with binary values when polled. Many of these values will correspond channels in sigrok. This change introduces helper functions for automatically reading and scaling such values and sending them down a sigrok analog channel. Signed-off-by: Andreas Sandberg --- diff --git a/Makefile.am b/Makefile.am index b7e3ad01..0695ee08 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,6 +50,7 @@ lib_LTLIBRARIES = libsigrok.la # Backend files libsigrok_la_SOURCES = \ src/backend.c \ + src/binary_helpers.c \ src/conversion.c \ src/device.c \ src/session.c \ diff --git a/src/binary_helpers.c b/src/binary_helpers.c new file mode 100644 index 00000000..8c1b7b7c --- /dev/null +++ b/src/binary_helpers.c @@ -0,0 +1,109 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2020 Andreas Sandberg + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include "libsigrok-internal.h" + +SR_PRIV int bv_get_value(float *out, const struct binary_value_spec *spec, const void *data, size_t length) +{ + float value; + + if (!out || !spec || !data) + return SR_ERR_ARG; + +#define VALUE_TYPE(T, R, L) \ + case T: \ + if (spec->offset + (L) > length) \ + return SR_ERR_DATA; \ + value = R(data + spec->offset); \ + break + + switch (spec->type) { + VALUE_TYPE(BVT_UINT8, R8, 1); + + VALUE_TYPE(BVT_BE_UINT16, RB16, 2); + VALUE_TYPE(BVT_BE_UINT32, RB32, 4); + VALUE_TYPE(BVT_BE_UINT64, RB64, 8); + VALUE_TYPE(BVT_BE_FLOAT, RBFL, 4); + + VALUE_TYPE(BVT_LE_UINT16, RL16, 2); + VALUE_TYPE(BVT_LE_UINT32, RL32, 4); + VALUE_TYPE(BVT_LE_UINT64, RL64, 8); + VALUE_TYPE(BVT_LE_FLOAT, RLFL, 4); + + default: + return SR_ERR_ARG; + } + +#undef VALUE_TYPE + + *out = value * spec->scale; + return SR_OK; +} + +SR_PRIV int bv_send_analog_channel(const struct sr_dev_inst *sdi, struct sr_channel *ch, + const struct binary_analog_channel *bac, const void *data, size_t length) +{ + int err; + struct sr_analog_encoding encoding; + struct sr_analog_meaning meaning; + struct sr_analog_spec spec; + struct sr_datafeed_analog analog; + struct sr_datafeed_packet packet = { + .type = SR_DF_ANALOG, + .payload = &analog, + }; + float value; + + err = bv_get_value(&value, &bac->spec, data, length); + if (err != SR_OK) + goto err_out; + + err = sr_analog_init(&analog, &encoding, &meaning, &spec, bac->digits); + if (err != SR_OK) + goto err_out; + + meaning.mq = bac->mq; + meaning.unit = bac->unit; + meaning.mqflags = 0; + meaning.channels = g_slist_append(NULL, ch); + if (!meaning.channels) { + err = SR_ERR_MALLOC; + goto err_out; + } + + spec.spec_digits = bac->digits; + + analog.data = &value; + analog.num_samples = 1; + + err = sr_session_send(sdi, &packet); + if (err != SR_OK) + goto err_free; + + return SR_OK; + +err_free: + g_slist_free(meaning.channels); + +err_out: + return err; +} diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index 5b20e54b..990d038f 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -1715,6 +1715,73 @@ SR_PRIV gboolean usb_match_manuf_prod(libusb_device *dev, const char *manufacturer, const char *product); #endif +/*--- binary_helpers.c ------------------------------------------------------*/ + +/** Binary value type */ +enum binary_value_type { + BVT_UINT8 = 0, + BVT_BE_UINT8 = BVT_UINT8, + BVT_LE_UINT8 = BVT_UINT8, + + BVT_BE_UINT16, + BVT_BE_UINT32, + BVT_BE_UINT64, + BVT_BE_FLOAT, + + BVT_LE_UINT16, + BVT_LE_UINT32, + BVT_LE_UINT64, + BVT_LE_FLOAT, +}; + +/** Binary value specification */ +struct binary_value_spec { + /** Offset into binary blob */ + size_t offset; + /** Data type to decode */ + enum binary_value_type type; + /** Scale factor to get native units */ + float scale; +}; + +/** Binary channel definition */ +struct binary_analog_channel { + /** Channel name */ + const char *name; + /** Binary value in data stream */ + struct binary_value_spec spec; + /** Significant digits */ + int digits; + /** Measured quantity */ + enum sr_mq mq; + /** Measured unit */ + enum sr_unit unit; +}; + +/** + * Read extract a value from a binary blob. + * + * @param out Pointer to output buffer. + * @param spec Binary value specification + * @param data Pointer to binary blob + * @param length Size of binary blob + * @return SR_OK on success, SR_ERR_* error code on failure. + */ +SR_PRIV int bv_get_value(float *out, const struct binary_value_spec *spec, const void *data, size_t length); + +/** + * Send an analog channel packet based on a binary analog channel + * specification. + * + * @param sdi Device instance + * @param ch Sigrok channel + * @param spec Channel specification + * @param data Pointer to binary blob + * @param length Size of binary blob + * @return SR_OK on success, SR_ERR_* error code on failure. + */ +SR_PRIV int bv_send_analog_channel(const struct sr_dev_inst *sdi, struct sr_channel *ch, + const struct binary_analog_channel *spec, const void *data, size_t length); /*--- modbus/modbus.c -------------------------------------------------------*/