]> sigrok.org Git - libsigrok.git/blob - src/lcr/es51919.c
serial-lcr: move device driver code from src/lcr/ to src/hardware/
[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         0, 100, 120, 1000, 10000, 100000,
128 };
129
130 static const size_t freq_code_map[] = {
131         1, 2, 3, 4, 5, 0,
132 };
133
134 static uint64_t get_frequency(size_t code)
135 {
136         uint64_t freq;
137
138         if (code >= ARRAY_SIZE(freq_code_map)) {
139                 sr_err("Unknown output frequency code %zu.", code);
140                 return frequencies[0];
141         }
142
143         code = freq_code_map[code];
144         freq = frequencies[code];
145
146         return freq;
147 }
148
149 enum { MODEL_NONE, MODEL_PAR, MODEL_SER, MODEL_AUTO, };
150
151 static const char *const circuit_models[] = {
152         "NONE", "PARALLEL", "SERIES", "AUTO",
153 };
154
155 static const char *get_equiv_model(size_t code)
156 {
157         if (code >= ARRAY_SIZE(circuit_models)) {
158                 sr_err("Unknown equivalent circuit model code %zu.", code);
159                 return "NONE";
160         }
161
162         return circuit_models[code];
163 }
164
165 static const uint8_t *pkt_to_buf(const uint8_t *pkt, int is_secondary)
166 {
167         return is_secondary ? pkt + 10 : pkt + 5;
168 }
169
170 static int parse_mq(const uint8_t *pkt, int is_secondary, int is_parallel)
171 {
172         const uint8_t *buf;
173
174         buf = pkt_to_buf(pkt, is_secondary);
175
176         switch (is_secondary << 8 | buf[0]) {
177         case 0x001:
178                 return is_parallel ?
179                         SR_MQ_PARALLEL_INDUCTANCE : SR_MQ_SERIES_INDUCTANCE;
180         case 0x002:
181                 return is_parallel ?
182                         SR_MQ_PARALLEL_CAPACITANCE : SR_MQ_SERIES_CAPACITANCE;
183         case 0x003:
184         case 0x103:
185                 return is_parallel ?
186                         SR_MQ_PARALLEL_RESISTANCE : SR_MQ_SERIES_RESISTANCE;
187         case 0x004:
188                 return SR_MQ_RESISTANCE;
189         case 0x100:
190                 return SR_MQ_DIFFERENCE;
191         case 0x101:
192                 return SR_MQ_DISSIPATION_FACTOR;
193         case 0x102:
194                 return SR_MQ_QUALITY_FACTOR;
195         case 0x104:
196                 return SR_MQ_PHASE_ANGLE;
197         }
198
199         sr_err("Unknown quantity 0x%03x.", is_secondary << 8 | buf[0]);
200
201         return 0;
202 }
203
204 static float parse_value(const uint8_t *buf, int *digits)
205 {
206         static const int exponents[] = {0, -1, -2, -3, -4, -5, -6, -7};
207
208         int exponent;
209         int16_t val;
210         float fval;
211
212         exponent = exponents[buf[3] & 7];
213         *digits = -exponent;
214         val = (buf[1] << 8) | buf[2];
215         fval = (float)val;
216         fval *= powf(10, exponent);
217
218         return fval;
219 }
220
221 static void parse_measurement(const uint8_t *pkt, float *floatval,
222         struct sr_datafeed_analog *analog, int is_secondary)
223 {
224         static const struct {
225                 int unit;
226                 int exponent;
227         } units[] = {
228                 { SR_UNIT_UNITLESS,   0 }, /* no unit */
229                 { SR_UNIT_OHM,        0 }, /* Ohm */
230                 { SR_UNIT_OHM,        3 }, /* kOhm */
231                 { SR_UNIT_OHM,        6 }, /* MOhm */
232                 { -1,                 0 }, /* ??? */
233                 { SR_UNIT_HENRY,     -6 }, /* uH */
234                 { SR_UNIT_HENRY,     -3 }, /* mH */
235                 { SR_UNIT_HENRY,      0 }, /* H */
236                 { SR_UNIT_HENRY,      3 }, /* kH */
237                 { SR_UNIT_FARAD,    -12 }, /* pF */
238                 { SR_UNIT_FARAD,     -9 }, /* nF */
239                 { SR_UNIT_FARAD,     -6 }, /* uF */
240                 { SR_UNIT_FARAD,     -3 }, /* mF */
241                 { SR_UNIT_PERCENTAGE, 0 }, /* % */
242                 { SR_UNIT_DEGREE,     0 }, /* degree */
243         };
244
245         const uint8_t *buf;
246         int digits, exponent;
247         int state;
248
249         buf = pkt_to_buf(pkt, is_secondary);
250
251         analog->meaning->mq = 0;
252         analog->meaning->mqflags = 0;
253
254         state = buf[4] & 0xf;
255
256         if (state != 0 && state != 3)
257                 return;
258
259         if (pkt[2] & 0x18) {
260                 /* Calibration and Sorting modes not supported. */
261                 return;
262         }
263
264         if (!is_secondary) {
265                 if (pkt[2] & 0x01)
266                         analog->meaning->mqflags |= SR_MQFLAG_HOLD;
267                 if (pkt[2] & 0x02)
268                         analog->meaning->mqflags |= SR_MQFLAG_REFERENCE;
269         } else {
270                 if (pkt[2] & 0x04)
271                         analog->meaning->mqflags |= SR_MQFLAG_RELATIVE;
272         }
273
274         if ((analog->meaning->mq = parse_mq(pkt, is_secondary, pkt[2] & 0x80)) == 0)
275                 return;
276
277         if ((buf[3] >> 3) >= ARRAY_SIZE(units)) {
278                 sr_err("Unknown unit %u.", buf[3] >> 3);
279                 analog->meaning->mq = 0;
280                 return;
281         }
282
283         analog->meaning->unit = units[buf[3] >> 3].unit;
284
285         exponent = units[buf[3] >> 3].exponent;
286         *floatval = parse_value(buf, &digits);
287         *floatval *= (state == 0) ? powf(10, exponent) : INFINITY;
288         analog->encoding->digits = digits - exponent;
289         analog->spec->spec_digits = digits - exponent;
290 }
291
292 static uint64_t parse_freq(const uint8_t *pkt)
293 {
294         return get_frequency(pkt[3] >> 5);
295 }
296
297 static const char *parse_model(const uint8_t *pkt)
298 {
299         size_t code;
300
301         if (pkt[2] & 0x40)
302                 code = MODEL_AUTO;
303         else if (parse_mq(pkt, 0, 0) == SR_MQ_RESISTANCE)
304                 code = MODEL_NONE;
305         else
306                 code = (pkt[2] & 0x80) ? MODEL_PAR : MODEL_SER;
307
308         return get_equiv_model(code);
309 }
310
311 SR_PRIV gboolean es51919_packet_valid(const uint8_t *pkt)
312 {
313
314         /* Check for fixed 0x00 0x0d prefix. */
315         if (pkt[0] != 0x00 || pkt[1] != 0x0d)
316                 return FALSE;
317
318         /* Check for fixed 0x0d 0x0a suffix. */
319         if (pkt[15] != 0x0d || pkt[16] != 0x0a)
320                 return FALSE;
321
322         /* Packet appears to be valid. */
323         return TRUE;
324 }
325
326 SR_PRIV int es51919_packet_parse(const uint8_t *pkt, float *val,
327         struct sr_datafeed_analog *analog, void *info)
328 {
329         struct lcr_parse_info *parse_info;
330
331         parse_info = info;
332         if (!parse_info->ch_idx) {
333                 parse_info->output_freq = parse_freq(pkt);
334                 parse_info->circuit_model = parse_model(pkt);
335         }
336         if (val && analog)
337                 parse_measurement(pkt, val, analog, parse_info->ch_idx == 1);
338
339         return SR_OK;
340 }
341
342 /*
343  * These are the get/set/list routines for the _chip_ specific parameters,
344  * the _device_ driver resides in src/hardware/serial-lcr/ instead.
345  */
346
347 SR_PRIV int es51919_config_list(uint32_t key, GVariant **data,
348         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
349 {
350
351         (void)sdi;
352         (void)cg;
353
354         switch (key) {
355         case SR_CONF_OUTPUT_FREQUENCY:
356                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_DOUBLE,
357                         ARRAY_AND_SIZE(frequencies), sizeof(double));
358                 return SR_OK;
359         case SR_CONF_EQUIV_CIRCUIT_MODEL:
360                 *data = g_variant_new_strv(ARRAY_AND_SIZE(circuit_models));
361                 return SR_OK;
362         default:
363                 return SR_ERR_NA;
364         }
365         /* UNREACH */
366 }
367
368 #endif