+ if (input_unitsize == sizeof(uint8_t) && input_signed) {
+ int8_t (*reader)(const uint8_t **p);
+ reader = read_i8_inc;
+ while (count--) {
+ value = reader(&data8);
+ value *= scale;
+ value += offset;
+ *outbuf++ = value;
+ }
+ return SR_OK;
+ }
+ if (input_unitsize == sizeof(uint8_t)) {
+ uint8_t (*reader)(const uint8_t **p);
+ reader = read_u8_inc;
+ while (count--) {
+ value = reader(&data8);
+ value *= scale;
+ value += offset;
+ *outbuf++ = value;
+ }
+ return SR_OK;
+ }
+ if (input_unitsize == sizeof(uint16_t) && input_signed) {
+ int16_t (*reader)(const uint8_t **p);
+ if (input_bigendian)
+ reader = read_i16be_inc;
+ else
+ reader = read_i16le_inc;
+ while (count--) {
+ value = reader(&data8);
+ value *= scale;
+ value += offset;
+ *outbuf++ = value;
+ }
+ return SR_OK;
+ }
+ if (input_unitsize == sizeof(uint16_t)) {
+ uint16_t (*reader)(const uint8_t **p);
+ if (input_bigendian)
+ reader = read_u16be_inc;
+ else
+ reader = read_u16le_inc;
+ while (count--) {
+ value = reader(&data8);
+ value *= scale;
+ value += offset;
+ *outbuf++ = value;
+ }
+ return SR_OK;
+ }
+ if (input_unitsize == sizeof(uint32_t) && input_signed) {
+ int32_t (*reader)(const uint8_t **p);
+ if (input_bigendian)
+ reader = read_i32be_inc;
+ else
+ reader = read_i32le_inc;
+ while (count--) {
+ value = reader(&data8);
+ value *= scale;
+ value += offset;
+ *outbuf++ = value;
+ }
+ return SR_OK;
+ }
+ if (input_unitsize == sizeof(uint32_t)) {
+ uint32_t (*reader)(const uint8_t **p);
+ if (input_bigendian)
+ reader = read_u32be_inc;
+ else
+ reader = read_u32le_inc;
+ while (count--) {
+ value = reader(&data8);
+ value *= scale;
+ value += offset;
+ *outbuf++ = value;
+ }
+ return SR_OK;
+ }
+ snprintf(type_text, sizeof(type_text), "%c%zu%s",
+ input_float ? 'f' : input_signed ? 'i' : 'u',
+ input_unitsize * 8, input_bigendian ? "be" : "le");
+ sr_err("Unsupported type for analog-to-float conversion: %s.",
+ type_text);
+ return SR_ERR;
+}
+
+/**
+ * Scale a float value to the appropriate SI prefix.
+ *
+ * @param[in,out] value The float value to convert to appropriate SI prefix.
+ * @param[in,out] digits The number of significant decimal digits in value.
+ *
+ * @return The SI prefix to which value was scaled, as a printable string.
+ *
+ * @since 0.5.0
+ */
+SR_API const char *sr_analog_si_prefix(float *value, int *digits)
+{
+/** @cond PRIVATE */
+#define NEG_PREFIX_COUNT 5 /* number of prefixes below unity */
+#define POS_PREFIX_COUNT (int)(ARRAY_SIZE(prefixes) - NEG_PREFIX_COUNT - 1)
+/** @endcond */
+ static const char *prefixes[] = { "f", "p", "n", "ยต", "m", "", "k", "M", "G", "T" };
+
+ if (!value || !digits || isnan(*value))
+ return prefixes[NEG_PREFIX_COUNT];
+
+ float logval = log10f(fabsf(*value));
+ int prefix = (logval / 3) - (logval < 1);
+
+ if (prefix < -NEG_PREFIX_COUNT)
+ prefix = -NEG_PREFIX_COUNT;
+ if (3 * prefix < -*digits)
+ prefix = (-*digits + 2 * (*digits < 0)) / 3;
+ if (prefix > POS_PREFIX_COUNT)
+ prefix = POS_PREFIX_COUNT;
+
+ *value *= powf(10, -3 * prefix);
+ *digits += 3 * prefix;
+
+ return prefixes[prefix + NEG_PREFIX_COUNT];
+}
+
+/**
+ * Check if a unit "accepts" an SI prefix.
+ *
+ * E.g. SR_UNIT_VOLT is SI prefix friendly while SR_UNIT_DECIBEL_MW or
+ * SR_UNIT_PERCENTAGE are not.
+ *
+ * @param[in] unit The unit to check for SI prefix "friendliness".
+ *
+ * @return TRUE if the unit "accept" an SI prefix.
+ *
+ * @since 0.5.0
+ */
+SR_API gboolean sr_analog_si_prefix_friendly(enum sr_unit unit)
+{
+ static const enum sr_unit prefix_friendly_units[] = {
+ SR_UNIT_VOLT,
+ SR_UNIT_AMPERE,
+ SR_UNIT_OHM,
+ SR_UNIT_FARAD,
+ SR_UNIT_KELVIN,
+ SR_UNIT_HERTZ,
+ SR_UNIT_SECOND,
+ SR_UNIT_SIEMENS,
+ SR_UNIT_VOLT_AMPERE,
+ SR_UNIT_WATT,
+ SR_UNIT_WATT_HOUR,
+ SR_UNIT_METER_SECOND,
+ SR_UNIT_HENRY,
+ SR_UNIT_GRAM
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(prefix_friendly_units); i++)
+ if (unit == prefix_friendly_units[i])
+ return TRUE;
+
+ return FALSE;