]> sigrok.org Git - libsigrok.git/blame - src/dmm/ms2115b.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / dmm / ms2115b.c
CommitLineData
dcd212f7
VV
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
99static 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
150SR_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 */
163enum {
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
173static 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
182static 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
193static 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
203static 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
211SR_PRIV const char *ms2115b_channel_formats[MS2115B_DISPLAY_COUNT] = {
212 "main", "sub",
213};
214
215static 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 */
362SR_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}