2 * This file is part of the libsigrok project.
4 * Copyright (C) 2019 Vitaliy Vorobyov
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.
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.
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/>.
21 * MASTECH MS2115B protocol parser.
24 * D0 D1 D2 D3 D4 D5 D6 D7 D8 D9
26 * D0 = 0x55 - sync byte
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)
48 * (secondary value, hz, min/max, rel)
49 * D6 secondary value LSB
50 * D7 secondary value MSB
55 * B0 - 0 - auto, 1 - manual
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)
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)
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)
85 * - Communication parameters: Unidirectional, 1200/8n1
86 * - CP2102 USB to UART bridge controller
94 #include <libsigrok/libsigrok.h>
95 #include "libsigrok-internal.h"
97 #define LOG_PREFIX "ms2115b"
99 static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
100 const struct ms2115b_info *info)
102 /* Measurement modes */
104 analog->meaning->mq = SR_MQ_VOLTAGE;
105 analog->meaning->unit = SR_UNIT_VOLT;
107 if (info->is_ampere) {
108 analog->meaning->mq = SR_MQ_CURRENT;
109 analog->meaning->unit = SR_UNIT_AMPERE;
112 analog->meaning->mq = SR_MQ_RESISTANCE;
113 analog->meaning->unit = SR_UNIT_OHM;
116 analog->meaning->mq = SR_MQ_FREQUENCY;
117 analog->meaning->unit = SR_UNIT_HERTZ;
119 if (info->is_farad) {
120 analog->meaning->mq = SR_MQ_CAPACITANCE;
121 analog->meaning->unit = SR_UNIT_FARAD;
124 analog->meaning->mq = SR_MQ_CONTINUITY;
125 analog->meaning->unit = SR_UNIT_BOOLEAN;
126 *floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
128 if (info->is_diode) {
129 analog->meaning->mq = SR_MQ_VOLTAGE;
130 analog->meaning->unit = SR_UNIT_VOLT;
133 if (info->is_duty_cycle)
134 analog->meaning->mq = SR_MQ_DUTY_CYCLE;
136 if (info->is_percent)
137 analog->meaning->unit = SR_UNIT_PERCENTAGE;
139 /* Measurement related flags */
141 analog->meaning->mqflags |= SR_MQFLAG_AC;
143 analog->meaning->mqflags |= SR_MQFLAG_DC;
145 analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
147 analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
150 SR_PRIV gboolean sr_ms2115b_packet_valid(const uint8_t *buf)
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],
162 /* Mode values equal to received data */
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) */
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) */
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) */
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) */
211 SR_PRIV const char *ms2115b_channel_formats[MS2115B_DISPLAY_COUNT] = {
215 static int ms2115b_parse(const uint8_t *buf, float *floatval,
216 struct sr_datafeed_analog *analog, void *info)
219 float up_limit = 6000.0;
220 gboolean sign = FALSE;
222 uint32_t mode = (buf[1] & 7);
223 gboolean func = (buf[1] & 8) ? TRUE : FALSE;
224 uint32_t range = (buf[2] & 7);
226 struct ms2115b_info *info_local = info;
228 enum eev121gw_display display = info_local->ch_idx;
229 memset(info_local, 0, sizeof(*info_local));
230 info_local->ch_idx = display;
233 case MS2115B_DISPLAY_MAIN:
238 info_local->is_ampere = TRUE;
240 info_local->is_dc = TRUE;
242 info_local->is_ac = TRUE;
247 info_local->is_ampere = TRUE;
249 info_local->is_dc = TRUE;
251 info_local->is_ac = TRUE;
254 if (range >= ARRAY_SIZE(v_exp))
256 exponent = v_exp[range];
258 info_local->is_volt = TRUE;
260 info_local->is_dc = TRUE;
262 info_local->is_ac = TRUE;
264 case MODE_DIODE_BEEP:
268 info_local->is_diode = TRUE;
270 info_local->is_beep = TRUE;
274 if (range >= ARRAY_SIZE(res_exp))
276 exponent = res_exp[range];
277 info_local->is_ohm = TRUE;
280 if (range >= ARRAY_SIZE(cap_exp))
282 exponent = cap_exp[range];
283 info_local->is_farad = TRUE;
286 range = (buf[3] & 7);
287 if (range >= ARRAY_SIZE(hz_exp))
289 exponent = hz_exp[range];
290 info_local->is_hz = TRUE;
297 *floatval = RL16S(buf + 4); /* signed 16bit value */
299 *floatval = RL16(buf + 4); /* unsigned 16bit value */
302 info_local->is_auto = (buf[8] & 1) ? FALSE : TRUE;
304 case MS2115B_DISPLAY_SUB:
313 info_local->is_hz = TRUE;
317 info_local->is_duty_cycle = TRUE;
318 info_local->is_percent = TRUE;
325 *floatval = RL16(buf + 6); /* unsigned 16bit value */
331 if (fabsf(*floatval) > up_limit) {
332 sr_spew("Over limit.");
333 *floatval = INFINITY;
337 *floatval *= powf(10, exponent);
339 handle_flags(analog, floatval, info_local);
341 analog->encoding->digits = -exponent;
342 analog->spec->spec_digits = -exponent;
348 * Parse a protocol packet.
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.
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.
359 * @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
360 * 'analog' variable contents are undefined and should not be used.
362 SR_PRIV int sr_ms2115b_parse(const uint8_t *buf, float *floatval,
363 struct sr_datafeed_analog *analog, void *info)
367 struct ms2115b_info *info_local = info;
369 ch_idx = info_local->ch_idx;
370 ret = ms2115b_parse(buf, floatval, analog, info);
371 info_local->ch_idx = ch_idx + 1;