]> sigrok.org Git - libsigrok.git/blob - src/analog.c
Add analog helper sr_analog_float_to_string().
[libsigrok.git] / src / analog.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include "libsigrok.h"
25 #include "libsigrok-internal.h"
26
27 #define LOG_PREFIX "analog"
28
29 SR_PRIV int sr_analog_init(struct sr_datafeed_analog2 *analog,
30                 struct sr_analog_encoding *encoding,
31                 struct sr_analog_meaning *meaning,
32                 struct sr_analog_spec *spec,
33                 int digits)
34 {
35         memset(analog, 0, sizeof(*analog));
36         memset(encoding, 0, sizeof(*encoding));
37         memset(meaning, 0, sizeof(*meaning));
38         memset(spec, 0, sizeof(*spec));
39
40         analog->encoding = encoding;
41         analog->meaning = meaning;
42         analog->spec = spec;
43
44         encoding->unitsize = sizeof(float);
45         encoding->is_float = TRUE;
46 #ifdef WORDS_BIGENDIAN
47         encoding->is_bigendian = TRUE;
48 #else
49         encoding->is_bigendian = FALSE;
50 #endif
51         encoding->digits = digits;
52         encoding->is_digits_decimal = TRUE;
53         encoding->scale.p = 1;
54         encoding->scale.q = 1;
55         encoding->offset.p = 0;
56         encoding->offset.q = 1;
57
58         spec->spec_digits = digits;
59
60         return SR_OK;
61 }
62
63 SR_API int sr_analog_to_float(const struct sr_datafeed_analog2 *analog,
64                 float *outbuf)
65 {
66         float offset;
67         unsigned int b, i;
68         gboolean bigendian;
69
70 #ifdef WORDS_BIGENDIAN
71         bigendian = TRUE;
72 #else
73         bigendian = FALSE;
74 #endif
75         if (!analog->encoding->is_float) {
76                 /* TODO */
77                 sr_err("Only floating-point encoding supported so far.");
78                 return SR_ERR;
79         }
80
81         if (analog->encoding->unitsize == sizeof(float)
82                         && analog->encoding->is_bigendian == bigendian
83                         && (analog->encoding->scale.p == analog->encoding->scale.q)
84                         && analog->encoding->offset.p / (float)analog->encoding->offset.q == 0) {
85                 /* The data is already in the right format. */
86                 memcpy(outbuf, analog->data, analog->num_samples * sizeof(float));
87         } else {
88                 for (i = 0; i < analog->num_samples; i += analog->encoding->unitsize) {
89                         for (b = 0; b < analog->encoding->unitsize; b++) {
90                                 if (analog->encoding->is_bigendian == bigendian)
91                                         outbuf[i + b] = ((float *)analog->data)[i * analog->encoding->unitsize + b];
92                                 else
93                                         outbuf[i + (analog->encoding->unitsize - b)] = ((float *)analog->data)[i * analog->encoding->unitsize + b];
94                         }
95                         if (analog->encoding->scale.p != analog->encoding->scale.q)
96                                 outbuf[i] = (outbuf[i] * analog->encoding->scale.p) / analog->encoding->scale.q;
97                         offset = ((float)analog->encoding->offset.p / (float)analog->encoding->offset.q);
98                         outbuf[i] += offset;
99                 }
100         }
101
102         return SR_OK;
103 }
104
105 /*
106  * Convert a floating point value to a string, limited to the given
107  * number of decimal digits.
108  *
109  * @param value The value to convert.
110  * @param digits Number of digits after the decimal point to print.
111  * @param outbuf Buffer in which the resulting string will be placed.
112  * @param bufsize Size of the buffer in bytes.
113  *
114  * @retval SR_OK
115  *
116  * @since 0.4.0
117  */
118 SR_API int sr_analog_float_to_string(float value, int digits, char *outbuf,
119                 int bufsize)
120 {
121         int cnt, i;
122
123         /* This produces at least one too many digits */
124         snprintf(outbuf, bufsize, "%.*f", digits, value);
125         for (i = 0, cnt = 0; outbuf[i] && i < bufsize; i++) {
126                 if (isdigit(outbuf[i++]))
127                         cnt++;
128                 if (cnt == digits) {
129                         outbuf[i] = 0;
130                         break;
131                 }
132         }
133
134         return SR_OK;
135 }
136