]> sigrok.org Git - libsigrok.git/blob - src/dmm/bm25x.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / dmm / bm25x.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Janne Huttunen <jahuttun@gmail.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 /**
21  * @file
22  *
23  * Brymen BM25x serial protocol parser.
24  */
25
26 #include <config.h>
27 #include <math.h>
28 #include <libsigrok/libsigrok.h>
29 #include "libsigrok-internal.h"
30
31 #define LOG_PREFIX "brymen-bm25x"
32
33 #define MAX_DIGITS 4
34
35 SR_PRIV gboolean sr_brymen_bm25x_packet_valid(const uint8_t *buf)
36 {
37         int i;
38
39         if (buf[0] != 2)
40                 return FALSE;
41
42         for (i = 1; i < BRYMEN_BM25X_PACKET_SIZE; i++)
43                 if ((buf[i] >> 4) != i)
44                         return FALSE;
45
46         return TRUE;
47 }
48
49 static int decode_digit(int num, const uint8_t *buf)
50 {
51         int val;
52
53         val = (buf[3 + 2 * num] & 0xe) | ((buf[4 + 2 * num] << 4) & 0xf0);
54
55         switch (val) {
56         case 0xbe: return 0;
57         case 0xa0: return 1;
58         case 0xda: return 2;
59         case 0xf8: return 3;
60         case 0xe4: return 4;
61         case 0x7c: return 5;
62         case 0x7e: return 6;
63         case 0xa8: return 7;
64         case 0xfe: return 8;
65         case 0xfc: return 9;
66         case 0x00: return ' ';
67         case 0x40: return '-';
68         case 0x16: return 'L';
69         case 0x1e: return 'C';
70         case 0x4e: return 'F';
71         case 0x5e: return 'E';
72         case 0x62: return 'n';
73         case 0x42: return 'r';
74         default:
75                 sr_dbg("Unknown digit: 0x%02x.", val);
76                 return -1;
77         }
78 }
79
80 static int decode_point(const uint8_t *buf)
81 {
82         int i, p = 0;
83
84         for (i = 1; i < MAX_DIGITS; i++) {
85                 if ((buf[11 - 2 * i] & 1) == 0)
86                         continue;
87                 if (p != 0) {
88                         sr_spew("Multiple decimal points found!");
89                         return -1;
90                 }
91                 p = i;
92         }
93
94         return p;
95 }
96
97 static int decode_scale(int point, int digits)
98 {
99         int pos;
100
101         pos = point ? point + digits - MAX_DIGITS : 0;
102
103         if (pos < 0 || pos > 3) {
104                 sr_dbg("Invalid decimal point %d (%d digits).", point, digits);
105                 return 0;
106         }
107         return -pos;
108 }
109
110 static int decode_prefix(const uint8_t *buf)
111 {
112         if (buf[11] & 2) return  6;
113         if (buf[11] & 1) return  3;
114         if (buf[13] & 1) return -3;
115         if (buf[13] & 2) return -6;
116         if (buf[12] & 1) return -9;
117
118         return 0;
119 }
120
121 static float decode_value(const uint8_t *buf, int *exponent)
122 {
123         float val = 0.0f;
124         int i, digit;
125
126         for (i = 0; i < MAX_DIGITS; i++) {
127                 digit = decode_digit(i, buf);
128                 if (i == 3 && (digit == 'C' || digit == 'F'))
129                         break;
130                 if (digit < 0 || digit > 9)
131                         goto special;
132                 val = 10.0 * val + digit;
133         }
134
135         *exponent = decode_scale(decode_point(buf), i);
136         return val;
137
138 special:
139         if (decode_digit(1, buf) == 0 && decode_digit(2, buf) == 'L')
140                 return INFINITY;
141
142         return NAN;
143 }
144
145 SR_PRIV int sr_brymen_bm25x_parse(const uint8_t *buf, float *floatval,
146                                 struct sr_datafeed_analog *analog, void *info)
147 {
148         int exponent = 0;
149         float val;
150
151         (void)info;
152
153         analog->meaning->mq = SR_MQ_GAIN;
154         analog->meaning->unit = SR_UNIT_UNITLESS;
155         analog->meaning->mqflags = 0;
156
157         if (buf[1] & 8)
158                 analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
159         if (buf[1] & 4)
160                 analog->meaning->mqflags |= SR_MQFLAG_DC;
161         if (buf[1] & 2)
162                 analog->meaning->mqflags |= SR_MQFLAG_AC;
163         if (buf[1] & 1)
164                 analog->meaning->mqflags |= SR_MQFLAG_RELATIVE;
165         if (buf[11] & 8)
166                 analog->meaning->mqflags |= SR_MQFLAG_HOLD;
167         if (buf[13] & 8)
168                 analog->meaning->mqflags |= SR_MQFLAG_MAX;
169         if (buf[14] & 8)
170                 analog->meaning->mqflags |= SR_MQFLAG_MIN;
171
172         if (buf[14] & 4) {
173                 analog->meaning->mq = SR_MQ_VOLTAGE;
174                 analog->meaning->unit = SR_UNIT_VOLT;
175                 if ((analog->meaning->mqflags & (SR_MQFLAG_DC | SR_MQFLAG_AC)) == 0)
176                         analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
177         }
178         if (buf[14] & 2) {
179                 analog->meaning->mq = SR_MQ_CURRENT;
180                 analog->meaning->unit = SR_UNIT_AMPERE;
181         }
182         if (buf[12] & 4) {
183                 analog->meaning->mq = SR_MQ_RESISTANCE;
184                 analog->meaning->unit = SR_UNIT_OHM;
185         }
186         if (buf[13] & 4) {
187                 analog->meaning->mq = SR_MQ_CAPACITANCE;
188                 analog->meaning->unit = SR_UNIT_FARAD;
189         }
190         if (buf[12] & 2) {
191                 analog->meaning->mq = SR_MQ_FREQUENCY;
192                 analog->meaning->unit = SR_UNIT_HERTZ;
193         }
194
195         if (decode_digit(3, buf) == 'C') {
196                 analog->meaning->mq = SR_MQ_TEMPERATURE;
197                 analog->meaning->unit = SR_UNIT_CELSIUS;
198         }
199         if (decode_digit(3, buf) == 'F') {
200                 analog->meaning->mq = SR_MQ_TEMPERATURE;
201                 analog->meaning->unit = SR_UNIT_FAHRENHEIT;
202         }
203
204         val = decode_value(buf, &exponent);
205         exponent += decode_prefix(buf);
206         val *= powf(10, exponent);
207
208         if (buf[3] & 1)
209                 val = -val;
210
211         *floatval = val;
212         analog->encoding->digits = -exponent;
213         analog->spec->spec_digits = -exponent;
214
215         return SR_OK;
216 }