]> sigrok.org Git - libsigrok.git/blob - src/dmm/ms2115b.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / dmm / ms2115b.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2019 Vitaliy Vorobyov
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 2 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  * MASTECH MS2115B protocol parser.
22  *
23  * Sends 9 bytes.
24  * D0 D1 D2 D3 D4 D5 D6 D7 D8 D9
25  *
26  * D0 = 0x55 - sync byte
27  *
28  * D1 - mode:
29  * bits:
30  * B7..B4 ??
31  * B3 - func
32  * B2..B0:
33  * 0 - A 600/1000 (func=0 AC, func=1 DC), signed
34  * 1 - A 60 (func=0 AC, func=1 DC), signed
35  * 2 - V (func=0 AC, func=1 DC), signed
36  * 3 - diode/beep (func=0 buz, func=1 diode)
37  * 4 - resistance
38  * 5 - capacitance
39  * 6 - hz
40  *
41  * D2 - range
42  *
43  * D3 - frq range
44  *
45  * D4 main value LSB
46  * D5 main value MSB
47  *
48  * (secondary value, hz, min/max, rel)
49  * D6 secondary value LSB
50  * D7 secondary value MSB
51  *
52  * D8 - flags
53  * bits:
54  * B7..B1:??
55  * B0 - 0 - auto, 1 - manual
56  *
57  * resistance:
58  * 55 04 00 00 9B 18 00 00 01 (0.L, manual) 600.0 Ohm (x 0.1)
59  * 55 04 01 00 9B 18 00 00 01 (0.L, manual) 6.000 kOhm (x 0.001)
60  * 55 04 02 00 9B 18 00 00 01 (0.L, manual) 60.00 kOhm (x 0.01)
61  * 55 04 03 00 9B 18 00 00 01 (0.L, manual) 600.0 kOhm (x 0.1)
62  * 55 04 04 00 9B 18 00 00 01 (0.L, manual) 6.000 MOhm (x 0.001)
63  * 55 04 05 00 9B 18 00 00 00 (0.L, auto)   60.00 MOhm (x 0.01)
64  *
65  * capacitance:
66  * 55 05 00 00 04 00 00 00 00 (4nF, auto)
67  * 55 05 00 00 05 00 00 00 01 (5nF, manual)      6.000 nF (x 0.001)
68  * 55 05 01 00 03 19 00 00 01 (0.L nF, manual)   60.00 nF (x 0.01)
69  * 55 05 02 00 D4 03 00 00 01 (980.0 nF, manual) 600.0 nF (x 0.1)
70  * 55 05 03 00 63 00 00 00 01 (0.099 uF, manual) 6.000 uF (x 0.001)
71  * 55 05 04 00 40 18 00 00 01 (0.L uF, manual)
72  * 55 05 04 00 F0 00 00 00 01 (2.40 uF, manual)  60.00 uF (x 0.01)
73  * 55 05 05 00 17 00 00 00 01 (2.3 uF, manual)   600.0 uF (x 0.1)
74  * 55 05 06 00 02 00 00 00 01 (0.002 mF, manual) 6.000 mF (x 0.001)
75  * 55 05 07 00 2F 00 00 00 01 (0.47 mF, manual)  60.00 mF (x 0.01)
76  *
77  * voltage:
78  * 55 02 00 00 00 00 00 00 01 (0.0mV, manual)  600.0 mV (x 0.1)
79  * 55 02 01 00 00 00 00 00 00 (0.000V, auto)
80  * 55 02 01 00 00 00 00 00 01 (0.000V, manual) 6.000 V  (x 0.001)
81  * 55 02 02 00 00 00 00 00 01 (0.00V, manual)  60.00 V  (x 0.01)
82  * 55 02 03 00 00 00 00 00 01 (0.0V, manual)   600.0 V  (x 0.1)
83  * 55 02 04 00 00 00 00 00 01 (0V, manual)     1000  V  (x 1)
84  *
85  * - Communication parameters: Unidirectional, 1200/8n1
86  * - CP2102 USB to UART bridge controller
87  */
88
89 #include <config.h>
90 #include <string.h>
91 #include <ctype.h>
92 #include <math.h>
93 #include <glib.h>
94 #include <libsigrok/libsigrok.h>
95 #include "libsigrok-internal.h"
96
97 #define LOG_PREFIX "ms2115b"
98
99 static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
100         const struct ms2115b_info *info)
101 {
102         /* Measurement modes */
103         if (info->is_volt) {
104                 analog->meaning->mq = SR_MQ_VOLTAGE;
105                 analog->meaning->unit = SR_UNIT_VOLT;
106         }
107         if (info->is_ampere) {
108                 analog->meaning->mq = SR_MQ_CURRENT;
109                 analog->meaning->unit = SR_UNIT_AMPERE;
110         }
111         if (info->is_ohm) {
112                 analog->meaning->mq = SR_MQ_RESISTANCE;
113                 analog->meaning->unit = SR_UNIT_OHM;
114         }
115         if (info->is_hz) {
116                 analog->meaning->mq = SR_MQ_FREQUENCY;
117                 analog->meaning->unit = SR_UNIT_HERTZ;
118         }
119         if (info->is_farad) {
120                 analog->meaning->mq = SR_MQ_CAPACITANCE;
121                 analog->meaning->unit = SR_UNIT_FARAD;
122         }
123         if (info->is_beep) {
124                 analog->meaning->mq = SR_MQ_CONTINUITY;
125                 analog->meaning->unit = SR_UNIT_BOOLEAN;
126                 *floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
127         }
128         if (info->is_diode) {
129                 analog->meaning->mq = SR_MQ_VOLTAGE;
130                 analog->meaning->unit = SR_UNIT_VOLT;
131         }
132
133         if (info->is_duty_cycle)
134                 analog->meaning->mq = SR_MQ_DUTY_CYCLE;
135
136         if (info->is_percent)
137                 analog->meaning->unit = SR_UNIT_PERCENTAGE;
138
139         /* Measurement related flags */
140         if (info->is_ac)
141                 analog->meaning->mqflags |= SR_MQFLAG_AC;
142         if (info->is_dc)
143                 analog->meaning->mqflags |= SR_MQFLAG_DC;
144         if (info->is_auto)
145                 analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
146         if (info->is_diode)
147                 analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
148 }
149
150 SR_PRIV gboolean sr_ms2115b_packet_valid(const uint8_t *buf)
151 {
152         sr_dbg("DMM packet: %02x %02x %02x %02x %02x %02x %02x %02x %02x",
153                 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
154                 buf[7], buf[8]);
155
156         if (buf[0] == 0x55)
157                 return TRUE;
158
159         return FALSE;
160 }
161
162 /* Mode values equal to received data */
163 enum {
164         MODE_A600_1000 = 0,
165         MODE_A60 = 1,
166         MODE_V = 2,
167         MODE_DIODE_BEEP = 3,
168         MODE_OHM = 4,
169         MODE_CAP = 5,
170         MODE_HZ = 6,
171 };
172
173 static const int res_exp[] = {
174         -1,     /* 600.0 Ohm  (x 0.1)   */
175         -3 + 3, /* 6.000 kOhm (x 0.001) */
176         -2 + 3, /* 60.00 kOhm (x 0.01)  */
177         -1 + 3, /* 600.0 kOhm (x 0.1)   */
178         -3 + 6, /* 6.000 MOhm (x 0.001) */
179         -2 + 6, /* 60.00 MOhm (x 0.01)  */
180 };
181
182 static const int cap_exp[] = {
183         -3 - 9, /* 6.000 nF (x 0.001) */
184         -2 - 9, /* 60.00 nF (x 0.01)  */
185         -1 - 9, /* 600.0 nF (x 0.1)   */
186         -3 - 6, /* 6.000 uF (x 0.001) */
187         -2 - 6, /* 60.00 uF (x 0.01)  */
188         -1 - 6, /* 600.0 uF (x 0.1)   */
189         -3 - 3, /* 6.000 mF (x 0.001) */
190         -2 - 3, /* 60.00 mF (x 0.01)  */
191 };
192
193 static const int hz_exp[] = {
194         -2,     /* 60.00 Hz  (x 0.01)  */
195         -1,     /* 600.0 Hz  (x 0.1)   */
196         -3 + 3, /* 6.000 kHz (x 0.001) */
197         -2 + 3, /* 60.00 kHz (x 0.01)  */
198         -1 + 3, /* 600.0 kHz (x 0.1)   */
199         -3 + 6, /* 6.000 MHz (x 0.001) */
200         -2 + 6, /* 60.00 MHz (x 0.01)  */
201 };
202
203 static const int v_exp[] = {
204         -1 - 3, /* 600.0 mV (x 0.1)   */
205         -3,     /* 6.000 V  (x 0.001) */
206         -2,     /* 60.00 V  (x 0.01)  */
207         -1,     /* 600.0 V  (x 0.1)   */
208         0,      /* 1000  V  (x 1)     */
209 };
210
211 SR_PRIV const char *ms2115b_channel_formats[MS2115B_DISPLAY_COUNT] = {
212         "main", "sub",
213 };
214
215 static int ms2115b_parse(const uint8_t *buf, float *floatval,
216         struct sr_datafeed_analog *analog, void *info)
217 {
218         int exponent = 0;
219         float up_limit = 6000.0;
220         gboolean sign = FALSE;
221
222         uint32_t mode = (buf[1] & 7);
223         gboolean func = (buf[1] & 8) ? TRUE : FALSE;
224         uint32_t range = (buf[2] & 7);
225
226         struct ms2115b_info *info_local = info;
227
228         enum eev121gw_display display = info_local->ch_idx;
229         memset(info_local, 0, sizeof(*info_local));
230         info_local->ch_idx = display;
231
232         switch (display) {
233         case MS2115B_DISPLAY_MAIN:
234                 switch (mode) {
235                 case MODE_A600_1000:
236                         exponent = -1;
237                         sign = TRUE;
238                         info_local->is_ampere = TRUE;
239                         if (func)
240                                 info_local->is_dc = TRUE;
241                         else
242                                 info_local->is_ac = TRUE;
243                         break;
244                 case MODE_A60:
245                         exponent = -2;
246                         sign = TRUE;
247                         info_local->is_ampere = TRUE;
248                         if (func)
249                                 info_local->is_dc = TRUE;
250                         else
251                                 info_local->is_ac = TRUE;
252                         break;
253                 case MODE_V:
254                         if (range >= ARRAY_SIZE(v_exp))
255                                 return SR_ERR;
256                         exponent = v_exp[range];
257                         sign = TRUE;
258                         info_local->is_volt = TRUE;
259                         if (func)
260                                 info_local->is_dc = TRUE;
261                         else
262                                 info_local->is_ac = TRUE;
263                         break;
264                 case MODE_DIODE_BEEP:
265                         if (func) {
266                                 exponent = -3;
267                                 up_limit = 2500.0;
268                                 info_local->is_diode = TRUE;
269                         } else {
270                                 info_local->is_beep = TRUE;
271                         }
272                         break;
273                 case MODE_OHM:
274                         if (range >= ARRAY_SIZE(res_exp))
275                                 return SR_ERR;
276                         exponent = res_exp[range];
277                         info_local->is_ohm = TRUE;
278                         break;
279                 case MODE_CAP:
280                         if (range >= ARRAY_SIZE(cap_exp))
281                                 return SR_ERR;
282                         exponent = cap_exp[range];
283                         info_local->is_farad = TRUE;
284                         break;
285                 case MODE_HZ:
286                         range = (buf[3] & 7);
287                         if (range >= ARRAY_SIZE(hz_exp))
288                                 return SR_ERR;
289                         exponent = hz_exp[range];
290                         info_local->is_hz = TRUE;
291                         break;
292                 default:
293                         return SR_ERR;
294                 }
295
296                 if (sign) {
297                         *floatval = RL16S(buf + 4); /* signed 16bit value */
298                 } else {
299                         *floatval = RL16(buf + 4); /* unsigned 16bit value */
300                 }
301
302                 info_local->is_auto = (buf[8] & 1) ? FALSE : TRUE;
303                 break;
304         case MS2115B_DISPLAY_SUB:
305                 switch (mode) {
306                 case MODE_A600_1000:
307                 case MODE_A60:
308                 case MODE_V:
309                         if (func) /* DC */
310                                 return SR_ERR_NA;
311
312                         /* AC */
313                         info_local->is_hz = TRUE;
314                         exponent = -2;
315                         break;
316                 case MODE_HZ:
317                         info_local->is_duty_cycle = TRUE;
318                         info_local->is_percent = TRUE;
319                         exponent = -1;
320                         break;
321                 default:
322                         return SR_ERR_NA;
323                 }
324
325                 *floatval = RL16(buf + 6); /* unsigned 16bit value */
326                 break;
327         default:
328                 return SR_ERR;
329         }
330
331         if (fabsf(*floatval) > up_limit) {
332                 sr_spew("Over limit.");
333                 *floatval = INFINITY;
334                 return SR_OK;
335         }
336
337         *floatval *= powf(10, exponent);
338
339         handle_flags(analog, floatval, info_local);
340
341         analog->encoding->digits = -exponent;
342         analog->spec->spec_digits = -exponent;
343
344         return SR_OK;
345 }
346
347 /**
348  * Parse a protocol packet.
349  *
350  * @param buf Buffer containing the 9-byte protocol packet. Must not be NULL.
351  * @param floatval Pointer to a float variable. That variable will contain the
352  *                 result value upon parsing success. Must not be NULL.
353  * @param analog Pointer to a struct sr_datafeed_analog. The struct will be
354  *               filled with data according to the protocol packet.
355  *               Must not be NULL.
356  * @param info Pointer to a struct ms2115b_info. The struct will be filled
357  *             with data according to the protocol packet. Must not be NULL.
358  *
359  * @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
360  *         'analog' variable contents are undefined and should not be used.
361  */
362 SR_PRIV int sr_ms2115b_parse(const uint8_t *buf, float *floatval,
363                 struct sr_datafeed_analog *analog, void *info)
364 {
365         int ret;
366         int ch_idx;
367         struct ms2115b_info *info_local = info;
368
369         ch_idx = info_local->ch_idx;
370         ret = ms2115b_parse(buf, floatval, analog, info);
371         info_local->ch_idx = ch_idx + 1;
372
373         return ret;
374 }