]> sigrok.org Git - libsigrok.git/blob - src/lcr/es51919.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / lcr / es51919.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Janne Huttunen <jahuttun@gmail.com>
5  * Copyright (C) 2019 Gerhard Sittig <gerhard.sittig@gmx.net>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <glib.h>
23 #include <libsigrok/libsigrok.h>
24 #include "libsigrok-internal.h"
25 #include <math.h>
26 #include <stdint.h>
27 #include <string.h>
28
29 #define LOG_PREFIX "es51919"
30
31 #ifdef HAVE_SERIAL_COMM
32
33 /*
34  * Cyrustek ES51919 LCR chipset host protocol.
35  *
36  * Public official documentation does not contain the protocol
37  * description, so this is all based on reverse engineering.
38  *
39  * Packet structure (17 bytes):
40  *
41  * 0x00: header1 ?? (0x00)
42  * 0x01: header2 ?? (0x0d)
43  *
44  * 0x02: flags
45  *         bit 0 = hold enabled
46  *         bit 1 = reference shown (in delta mode)
47  *         bit 2 = delta mode
48  *         bit 3 = calibration mode
49  *         bit 4 = sorting mode
50  *         bit 5 = LCR mode
51  *         bit 6 = auto mode
52  *         bit 7 = parallel measurement (vs. serial)
53  *
54  * 0x03: config
55  *         bit 0-4 = ??? (0x10)
56  *         bit 5-7 = test frequency
57  *                     0 = 100 Hz
58  *                     1 = 120 Hz
59  *                     2 = 1 kHz
60  *                     3 = 10 kHz
61  *                     4 = 100 kHz
62  *                     5 = 0 Hz (DC)
63  *
64  * 0x04: tolerance (sorting mode)
65  *         0 = not set
66  *         3 = +-0.25%
67  *         4 = +-0.5%
68  *         5 = +-1%
69  *         6 = +-2%
70  *         7 = +-5%
71  *         8 = +-10%
72  *         9 = +-20%
73  *        10 = -20+80%
74  *
75  * 0x05-0x09: primary measurement
76  *   0x05: measured quantity
77  *           1 = inductance
78  *           2 = capacitance
79  *           3 = resistance
80  *           4 = DC resistance
81  *   0x06: measurement MSB  (0x4e20 = 20000 = outside limits)
82  *   0x07: measurement LSB
83  *   0x08: measurement info
84  *           bit 0-2 = decimal point multiplier (10^-val)
85  *           bit 3-7 = unit
86  *                       0 = no unit
87  *                       1 = Ohm
88  *                       2 = kOhm
89  *                       3 = MOhm
90  *                       5 = uH
91  *                       6 = mH
92  *                       7 = H
93  *                       8 = kH
94  *                       9 = pF
95  *                       10 = nF
96  *                       11 = uF
97  *                       12 = mF
98  *                       13 = %
99  *                       14 = degree
100  *   0x09: measurement status
101  *           bit 0-3 = status
102  *                       0 = normal (measurement shown)
103  *                       1 = blank (nothing shown)
104  *                       2 = lines ("----")
105  *                       3 = outside limits ("OL")
106  *                       7 = pass ("PASS")
107  *                       8 = fail ("FAIL")
108  *                       9 = open ("OPEn")
109  *                      10 = shorted ("Srt")
110  *           bit 4-6 = ??? (maybe part of same field with 0-3)
111  *           bit 7   = ??? (some independent flag)
112  *
113  * 0x0a-0x0e: secondary measurement
114  *   0x0a: measured quantity
115  *           0 = none
116  *           1 = dissipation factor
117  *           2 = quality factor
118  *           3 = parallel AC resistance / ESR
119  *           4 = phase angle
120  *   0x0b-0x0e: like primary measurement
121  *
122  * 0x0f: footer1 (0x0d) ?
123  * 0x10: footer2 (0x0a) ?
124  */
125
126 static const double frequencies[] = {
127         SR_HZ(0), SR_HZ(100), SR_HZ(120),
128         SR_KHZ(1), SR_KHZ(10), SR_KHZ(100),
129 };
130
131 static const size_t freq_code_map[] = {
132         1, 2, 3, 4, 5, 0,
133 };
134
135 static uint64_t get_frequency(size_t code)
136 {
137         uint64_t freq;
138
139         if (code >= ARRAY_SIZE(freq_code_map)) {
140                 sr_err("Unknown output frequency code %zu.", code);
141                 return frequencies[0];
142         }
143
144         code = freq_code_map[code];
145         freq = frequencies[code];
146
147         return freq;
148 }
149
150 enum { MODEL_NONE, MODEL_PAR, MODEL_SER, MODEL_AUTO, };
151
152 static const char *const circuit_models[] = {
153         "NONE", "PARALLEL", "SERIES", "AUTO",
154 };
155
156 static const char *get_equiv_model(size_t code)
157 {
158         if (code >= ARRAY_SIZE(circuit_models)) {
159                 sr_err("Unknown equivalent circuit model code %zu.", code);
160                 return "NONE";
161         }
162
163         return circuit_models[code];
164 }
165
166 static const uint8_t *pkt_to_buf(const uint8_t *pkt, int is_secondary)
167 {
168         return is_secondary ? pkt + 10 : pkt + 5;
169 }
170
171 static int parse_mq(const uint8_t *pkt, int is_secondary, int is_parallel)
172 {
173         const uint8_t *buf;
174
175         buf = pkt_to_buf(pkt, is_secondary);
176
177         switch (is_secondary << 8 | buf[0]) {
178         case 0x001:
179                 return is_parallel ?
180                         SR_MQ_PARALLEL_INDUCTANCE : SR_MQ_SERIES_INDUCTANCE;
181         case 0x002:
182                 return is_parallel ?
183                         SR_MQ_PARALLEL_CAPACITANCE : SR_MQ_SERIES_CAPACITANCE;
184         case 0x003:
185         case 0x103:
186                 return is_parallel ?
187                         SR_MQ_PARALLEL_RESISTANCE : SR_MQ_SERIES_RESISTANCE;
188         case 0x004:
189                 return SR_MQ_RESISTANCE;
190         case 0x100:
191                 return SR_MQ_DIFFERENCE;
192         case 0x101:
193                 return SR_MQ_DISSIPATION_FACTOR;
194         case 0x102:
195                 return SR_MQ_QUALITY_FACTOR;
196         case 0x104:
197                 return SR_MQ_PHASE_ANGLE;
198         }
199
200         sr_err("Unknown quantity 0x%03x.", is_secondary << 8 | buf[0]);
201
202         return 0;
203 }
204
205 static float parse_value(const uint8_t *buf, int *digits)
206 {
207         static const int exponents[] = {0, -1, -2, -3, -4, -5, -6, -7};
208
209         int exponent;
210         int16_t val;
211         float fval;
212
213         exponent = exponents[buf[3] & 7];
214         *digits = -exponent;
215         val = (buf[1] << 8) | buf[2];
216         fval = (float)val;
217         fval *= powf(10, exponent);
218
219         return fval;
220 }
221
222 static void parse_measurement(const uint8_t *pkt, float *floatval,
223         struct sr_datafeed_analog *analog, int is_secondary)
224 {
225         static const struct {
226                 int unit;
227                 int exponent;
228         } units[] = {
229                 { SR_UNIT_UNITLESS,   0 }, /* no unit */
230                 { SR_UNIT_OHM,        0 }, /* Ohm */
231                 { SR_UNIT_OHM,        3 }, /* kOhm */
232                 { SR_UNIT_OHM,        6 }, /* MOhm */
233                 { -1,                 0 }, /* ??? */
234                 { SR_UNIT_HENRY,     -6 }, /* uH */
235                 { SR_UNIT_HENRY,     -3 }, /* mH */
236                 { SR_UNIT_HENRY,      0 }, /* H */
237                 { SR_UNIT_HENRY,      3 }, /* kH */
238                 { SR_UNIT_FARAD,    -12 }, /* pF */
239                 { SR_UNIT_FARAD,     -9 }, /* nF */
240                 { SR_UNIT_FARAD,     -6 }, /* uF */
241                 { SR_UNIT_FARAD,     -3 }, /* mF */
242                 { SR_UNIT_PERCENTAGE, 0 }, /* % */
243                 { SR_UNIT_DEGREE,     0 }, /* degree */
244         };
245
246         const uint8_t *buf;
247         int digits, exponent;
248         int state;
249
250         buf = pkt_to_buf(pkt, is_secondary);
251
252         analog->meaning->mq = 0;
253         analog->meaning->mqflags = 0;
254
255         state = buf[4] & 0xf;
256
257         if (state != 0 && state != 3)
258                 return;
259
260         if (pkt[2] & 0x18) {
261                 /* Calibration and Sorting modes not supported. */
262                 return;
263         }
264
265         if (!is_secondary) {
266                 if (pkt[2] & 0x01)
267                         analog->meaning->mqflags |= SR_MQFLAG_HOLD;
268                 if (pkt[2] & 0x02)
269                         analog->meaning->mqflags |= SR_MQFLAG_REFERENCE;
270         } else {
271                 if (pkt[2] & 0x04)
272                         analog->meaning->mqflags |= SR_MQFLAG_RELATIVE;
273         }
274
275         if ((analog->meaning->mq = parse_mq(pkt, is_secondary, pkt[2] & 0x80)) == 0)
276                 return;
277
278         if ((buf[3] >> 3) >= ARRAY_SIZE(units)) {
279                 sr_err("Unknown unit %u.", buf[3] >> 3);
280                 analog->meaning->mq = 0;
281                 return;
282         }
283
284         analog->meaning->unit = units[buf[3] >> 3].unit;
285
286         exponent = units[buf[3] >> 3].exponent;
287         *floatval = parse_value(buf, &digits);
288         *floatval *= (state == 0) ? powf(10, exponent) : INFINITY;
289         analog->encoding->digits = digits - exponent;
290         analog->spec->spec_digits = digits - exponent;
291 }
292
293 static uint64_t parse_freq(const uint8_t *pkt)
294 {
295         return get_frequency(pkt[3] >> 5);
296 }
297
298 static const char *parse_model(const uint8_t *pkt)
299 {
300         size_t code;
301
302         if (pkt[2] & 0x40)
303                 code = MODEL_AUTO;
304         else if (parse_mq(pkt, 0, 0) == SR_MQ_RESISTANCE)
305                 code = MODEL_NONE;
306         else
307                 code = (pkt[2] & 0x80) ? MODEL_PAR : MODEL_SER;
308
309         return get_equiv_model(code);
310 }
311
312 SR_PRIV gboolean es51919_packet_valid(const uint8_t *pkt)
313 {
314
315         /* Check for fixed 0x00 0x0d prefix. */
316         if (pkt[0] != 0x00 || pkt[1] != 0x0d)
317                 return FALSE;
318
319         /* Check for fixed 0x0d 0x0a suffix. */
320         if (pkt[15] != 0x0d || pkt[16] != 0x0a)
321                 return FALSE;
322
323         /* Packet appears to be valid. */
324         return TRUE;
325 }
326
327 SR_PRIV int es51919_packet_parse(const uint8_t *pkt, float *val,
328         struct sr_datafeed_analog *analog, void *info)
329 {
330         struct lcr_parse_info *parse_info;
331
332         parse_info = info;
333         if (!parse_info->ch_idx) {
334                 parse_info->output_freq = parse_freq(pkt);
335                 parse_info->circuit_model = parse_model(pkt);
336         }
337         if (val && analog)
338                 parse_measurement(pkt, val, analog, parse_info->ch_idx == 1);
339
340         return SR_OK;
341 }
342
343 /*
344  * These are the get/set/list routines for the _chip_ specific parameters,
345  * the _device_ driver resides in src/hardware/serial-lcr/ instead.
346  */
347
348 SR_PRIV int es51919_config_list(uint32_t key, GVariant **data,
349         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
350 {
351
352         (void)sdi;
353         (void)cg;
354
355         switch (key) {
356         case SR_CONF_OUTPUT_FREQUENCY:
357                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_DOUBLE,
358                         ARRAY_AND_SIZE(frequencies), sizeof(frequencies[0]));
359                 return SR_OK;
360         case SR_CONF_EQUIV_CIRCUIT_MODEL:
361                 *data = g_variant_new_strv(ARRAY_AND_SIZE(circuit_models));
362                 return SR_OK;
363         default:
364                 return SR_ERR_NA;
365         }
366         /* UNREACH */
367 }
368
369 #endif