1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2019 Derek Hageman <hageman@inthat.cloud>
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 3 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 #include <config.h>
21 #include "protocol.h"
22 
23 static struct sr_dev_driver mooshimeter_dmm_driver_info;
24 
25 static const uint32_t scanopts[] = {
26 	SR_CONF_CONN,
27 };
28 
29 static const uint32_t drvopts[] = {
30 	SR_CONF_MULTIMETER,
31 };
32 
33 static const uint32_t devopts[] = {
34 	SR_CONF_CONTINUOUS,
35 	SR_CONF_LIMIT_SAMPLES | SR_CONF_SET | SR_CONF_LIST,
36 	SR_CONF_LIMIT_MSEC | SR_CONF_SET | SR_CONF_LIST,
37 	SR_CONF_AVG_SAMPLES | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
38 	SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
39 	SR_CONF_CHANNEL_CONFIG | SR_CONF_SET,
40 };
41 
init_dev(struct sr_dev_inst * sdi)42 static void init_dev(struct sr_dev_inst *sdi)
43 {
44 	struct dev_context *devc;
45 	struct sr_channel *chan;
46 
47 	devc = g_new0(struct dev_context, 1);
48 	sdi->priv = devc;
49 	sdi->status = SR_ST_INITIALIZING;
50 	sdi->vendor = g_strdup("Mooshim Engineering");
51 	sdi->model = g_strdup("Mooshimeter");
52 
53 	sr_sw_limits_init(&devc->limits);
54 
55 	chan = sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "CH1");
56 	devc->channel_meaning[0].mq = SR_MQ_CURRENT;
57 	devc->channel_meaning[0].unit = SR_UNIT_AMPERE;
58 	devc->channel_meaning[0].mqflags = SR_MQFLAG_DC;
59 	devc->channel_meaning[0].channels = g_slist_prepend(NULL, chan);
60 
61 	chan = sr_channel_new(sdi, 1, SR_CHANNEL_ANALOG, TRUE, "CH2");
62 	devc->channel_meaning[1].mq = SR_MQ_VOLTAGE;
63 	devc->channel_meaning[1].unit = SR_UNIT_VOLT;
64 	devc->channel_meaning[1].mqflags = SR_MQFLAG_DC;
65 	devc->channel_meaning[1].channels = g_slist_prepend(NULL, chan);
66 
67 	chan = sr_channel_new(sdi, 2, SR_CHANNEL_ANALOG, FALSE, "P");
68 	devc->channel_meaning[2].mq = SR_MQ_POWER;
69 	devc->channel_meaning[2].unit = SR_UNIT_WATT;
70 	devc->channel_meaning[2].mqflags = SR_MQFLAG_RMS;
71 	devc->channel_meaning[2].channels = g_slist_prepend(NULL, chan);
72 }
73 
scan(struct sr_dev_driver * di,GSList * options)74 static GSList *scan(struct sr_dev_driver *di, GSList *options)
75 {
76 	struct sr_bt_desc *desc;
77 	const char *conn;
78 	struct sr_config *src;
79 	GSList *l;
80 	int ret;
81 
82 	conn = NULL;
83 	for (l = options; l; l = l->next) {
84 		src = l->data;
85 		switch (src->key) {
86 		case SR_CONF_CONN:
87 			conn = g_variant_get_string(src->data, NULL);
88 			break;
89 		}
90 	}
91 
92 	if (!conn)
93 		return NULL;
94 
95 	desc = sr_bt_desc_new();
96 	if (!desc)
97 		return NULL;
98 
99 	ret = sr_bt_config_addr_remote(desc, conn);
100 	if (ret < 0)
101 		goto err;
102 
103 	/*
104 	 * These handles where queried with btgatt-client, since the
105 	 * documentation specifies them in terms of UUIDs.
106 	 *
107 	 * service - start: 0x0010, end: 0xffff, type: primary, uuid: 1bc5ffa0-0200-62ab-e411-f254e005dbd4
108          * charac - start: 0x0011, value: 0x0012, props: 0x08, ext_props: 0x0000, uuid: 1bc5ffa1-0200-62ab-e411-f254e005dbd4
109          *         descr - handle: 0x0013, uuid: 00002901-0000-1000-8000-00805f9b34fb
110          * charac - start: 0x0014, value: 0x0015, props: 0x10, ext_props: 0x0000, uuid: 1bc5ffa2-0200-62ab-e411-f254e005dbd4
111          *         descr - handle: 0x0016, uuid: 00002902-0000-1000-8000-00805f9b34fb
112          *         descr - handle: 0x0017, uuid: 00002901-0000-1000-8000-00805f9b34fb
113 	 */
114 	ret = sr_bt_config_notify(desc, 0x0015, 0x0012, 0x0016, 0x0001);
115 	if (ret < 0)
116 		goto err;
117 
118 	ret = sr_bt_connect_ble(desc);
119 	if (ret < 0)
120 		goto err;
121 	sr_bt_disconnect(desc);
122 
123 	struct sr_dev_inst *sdi = g_malloc0(sizeof(struct sr_dev_inst));
124 	struct dev_context *devc = g_malloc0(sizeof(struct dev_context));
125 
126 	sdi->priv = devc;
127 	sdi->inst_type = SR_INST_USER;
128 	sdi->connection_id = g_strdup(conn);
129 	sdi->conn = desc;
130 
131 	init_dev(sdi);
132 
133 	return std_scan_complete(di, g_slist_prepend(NULL, sdi));
134 
135 err:
136 	sr_bt_desc_free(desc);
137 	return NULL;
138 }
139 
dev_clear(const struct sr_dev_driver * di)140 static int dev_clear(const struct sr_dev_driver *di)
141 {
142 	struct drv_context *drvc = di->context;
143 	struct sr_dev_inst *sdi;
144 	GSList *l;
145 
146 	if (drvc) {
147 		for (l = drvc->instances; l; l = l->next) {
148 			sdi = l->data;
149 			struct sr_bt_desc *desc = sdi->conn;
150 			if (desc)
151 				sr_bt_desc_free(desc);
152 			sdi->conn = NULL;
153 		}
154 	}
155 
156 	return std_dev_clear(di);
157 }
158 
set_channel1_mean(const struct sr_dev_inst * sdi)159 static int set_channel1_mean(const struct sr_dev_inst *sdi)
160 {
161 	struct dev_context *devc = sdi->priv;
162 	devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_RMS;
163 	devc->channel_meaning[0].mqflags |= SR_MQFLAG_DC;
164 
165 	return mooshimeter_dmm_set_chooser(sdi, "CH1:ANALYSIS",
166 		"CH1:ANALYSIS:MEAN");
167 }
168 
set_channel1_rms(const struct sr_dev_inst * sdi)169 static int set_channel1_rms(const struct sr_dev_inst *sdi)
170 {
171 	struct dev_context *devc = sdi->priv;
172 	devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_DC;
173 	devc->channel_meaning[0].mqflags |= SR_MQFLAG_RMS;
174 
175 	return mooshimeter_dmm_set_chooser(sdi, "CH1:ANALYSIS",
176 		"CH1:ANALYSIS:RMS");
177 }
178 
set_channel1_buffer(const struct sr_dev_inst * sdi)179 static int set_channel1_buffer(const struct sr_dev_inst *sdi)
180 {
181 	struct dev_context *devc = sdi->priv;
182 	devc->channel_meaning[0].mqflags &= ~(SR_MQFLAG_DC | SR_MQFLAG_RMS);
183 
184 	return mooshimeter_dmm_set_chooser(sdi, "CH1:ANALYSIS",
185 		"CH1:ANALYSIS:BUFFER");
186 }
187 
set_channel2_mean(const struct sr_dev_inst * sdi)188 static int set_channel2_mean(const struct sr_dev_inst *sdi)
189 {
190 	struct dev_context *devc = sdi->priv;
191 	devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_RMS;
192 	devc->channel_meaning[1].mqflags |= SR_MQFLAG_DC;
193 
194 	return mooshimeter_dmm_set_chooser(sdi, "CH2:ANALYSIS",
195 		"CH2:ANALYSIS:MEAN");
196 }
197 
set_channel2_rms(const struct sr_dev_inst * sdi)198 static int set_channel2_rms(const struct sr_dev_inst *sdi)
199 {
200 	struct dev_context *devc = sdi->priv;
201 	devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_DC;
202 	devc->channel_meaning[1].mqflags |= SR_MQFLAG_RMS;
203 
204 	return mooshimeter_dmm_set_chooser(sdi, "CH2:ANALYSIS",
205 		"CH2:ANALYSIS:RMS");
206 }
207 
set_channel2_buffer(const struct sr_dev_inst * sdi)208 static int set_channel2_buffer(const struct sr_dev_inst *sdi)
209 {
210 	struct dev_context *devc = sdi->priv;
211 
212 	devc->channel_meaning[1].mqflags &= ~(SR_MQFLAG_DC | SR_MQFLAG_RMS);
213 
214 	return mooshimeter_dmm_set_chooser(sdi, "CH2:ANALYSIS",
215 		"CH2:ANALYSIS:BUFFER");
216 }
217 
autorange_channel1_current(const struct sr_dev_inst * sdi,float value)218 static void autorange_channel1_current(const struct sr_dev_inst *sdi,
219 	float value)
220 {
221 	mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
222 		"CH1:MAPPING:CURRENT", value);
223 }
224 
configure_channel1_current(const struct sr_dev_inst * sdi,float range)225 static int configure_channel1_current(const struct sr_dev_inst *sdi,
226 	float range)
227 {
228 	struct dev_context *devc = sdi->priv;
229 	int ret;
230 
231 	ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
232 		"CH1:MAPPING:CURRENT");
233 	if (ret != SR_OK)
234 		return ret;
235 
236 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
237 		"CH1:MAPPING:CURRENT", range);
238 	if (ret != SR_OK)
239 		return ret;
240 
241 	if (range <= 0) {
242 		devc->channel_autorange[0] = autorange_channel1_current;
243 		devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
244 	} else {
245 		devc->channel_autorange[0] = NULL;
246 		devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
247 	}
248 
249 	devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_DIODE;
250 	devc->channel_meaning[0].mq = SR_MQ_CURRENT;
251 	devc->channel_meaning[0].unit = SR_UNIT_AMPERE;
252 
253 	return SR_OK;
254 }
255 
autorange_channel1_temperature(const struct sr_dev_inst * sdi,float value)256 static void autorange_channel1_temperature(const struct sr_dev_inst *sdi,
257 	float value)
258 {
259 	mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
260 		"CH1:MAPPING:TEMP", value);
261 }
262 
configure_channel1_temperature(const struct sr_dev_inst * sdi,float range)263 static int configure_channel1_temperature(const struct sr_dev_inst *sdi,
264 	float range)
265 {
266 	struct dev_context *devc = sdi->priv;
267 	int ret;
268 
269 	ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
270 		"CH1:MAPPING:TEMP");
271 	if (ret != SR_OK)
272 		return ret;
273 
274 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
275 		"CH1:MAPPING:TEMP", range);
276 	if (ret != SR_OK)
277 		return ret;
278 
279 	if (range <= 0) {
280 		devc->channel_autorange[0] = autorange_channel1_temperature;
281 		devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
282 	} else {
283 		devc->channel_autorange[0] = NULL;
284 		devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
285 	}
286 
287 	devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_DIODE;
288 	devc->channel_meaning[0].mq = SR_MQ_TEMPERATURE;
289 	devc->channel_meaning[0].unit = SR_UNIT_KELVIN;
290 
291 	return SR_OK;
292 }
293 
autorange_channel1_auxv(const struct sr_dev_inst * sdi,float value)294 static void autorange_channel1_auxv(const struct sr_dev_inst *sdi,
295 	float value)
296 {
297 	mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
298 		"SHARED:AUX_V", value);
299 }
300 
configure_channel1_auxv(const struct sr_dev_inst * sdi,float range)301 static int configure_channel1_auxv(const struct sr_dev_inst *sdi,
302 	float range)
303 {
304 	struct dev_context *devc = sdi->priv;
305 	int ret;
306 
307 	ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:AUX_V");
308 	if (ret != SR_OK)
309 		return ret;
310 
311 	ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
312 		"CH1:MAPPING:SHARED");
313 	if (ret != SR_OK)
314 		return ret;
315 
316 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
317 		"SHARED:AUX_V", range);
318 	if (ret != SR_OK)
319 		return ret;
320 
321 	if (range <= 0) {
322 		devc->channel_autorange[0] = autorange_channel1_auxv;
323 		devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
324 	} else {
325 		devc->channel_autorange[0] = NULL;
326 		devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
327 	}
328 
329 	devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_DIODE;
330 	devc->channel_meaning[0].mq = SR_MQ_VOLTAGE;
331 	devc->channel_meaning[0].unit = SR_UNIT_VOLT;
332 
333 	return SR_OK;
334 }
335 
autorange_channel1_resistance(const struct sr_dev_inst * sdi,float value)336 static void autorange_channel1_resistance(const struct sr_dev_inst *sdi,
337 	float value)
338 {
339 	mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
340 		"SHARED:RESISTANCE", value);
341 }
342 
configure_channel1_resistance(const struct sr_dev_inst * sdi,float range)343 static int configure_channel1_resistance(const struct sr_dev_inst *sdi,
344 	float range)
345 {
346 	struct dev_context *devc = sdi->priv;
347 	int ret;
348 
349 	ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:RESISTANCE");
350 	if (ret != SR_OK)
351 		return ret;
352 
353 	ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
354 		"CH1:MAPPING:SHARED");
355 	if (ret != SR_OK)
356 		return ret;
357 
358 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
359 		"SHARED:RESISTANCE", range);
360 	if (ret != SR_OK)
361 		return ret;
362 
363 	if (range <= 0) {
364 		devc->channel_autorange[0] = autorange_channel1_resistance;
365 		devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
366 	} else {
367 		devc->channel_autorange[0] = NULL;
368 		devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
369 	}
370 
371 	devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_DIODE;
372 	devc->channel_meaning[0].mq = SR_MQ_RESISTANCE;
373 	devc->channel_meaning[0].unit = SR_UNIT_OHM;
374 
375 	return SR_OK;
376 }
377 
autorange_channel1_diode(const struct sr_dev_inst * sdi,float value)378 static void autorange_channel1_diode(const struct sr_dev_inst *sdi,
379 	float value)
380 {
381 	mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
382 		"SHARED:DIODE", value);
383 }
384 
configure_channel1_diode(const struct sr_dev_inst * sdi,float range)385 static int configure_channel1_diode(const struct sr_dev_inst *sdi,
386 	float range)
387 {
388 	struct dev_context *devc = sdi->priv;
389 	int ret;
390 
391 	ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:DIODE");
392 	if (ret != SR_OK)
393 		return ret;
394 
395 	ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
396 		"CH1:MAPPING:SHARED");
397 	if (ret != SR_OK)
398 		return ret;
399 
400 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
401 		"SHARED:DIODE", range);
402 	if (ret != SR_OK)
403 		return ret;
404 
405 	if (range <= 0) {
406 		devc->channel_autorange[0] = autorange_channel1_diode;
407 		devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
408 	} else {
409 		devc->channel_autorange[0] = NULL;
410 		devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
411 	}
412 
413 	devc->channel_meaning[0].mqflags |= SR_MQFLAG_DIODE;
414 	devc->channel_meaning[0].mq = SR_MQ_VOLTAGE;
415 	devc->channel_meaning[0].unit = SR_UNIT_VOLT;
416 
417 	return SR_OK;
418 }
419 
autorange_channel2_voltage(const struct sr_dev_inst * sdi,float value)420 static void autorange_channel2_voltage(const struct sr_dev_inst *sdi,
421 	float value)
422 {
423 	mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
424 		"CH2:MAPPING:VOLTAGE", value);
425 }
426 
configure_channel2_voltage(const struct sr_dev_inst * sdi,float range)427 static int configure_channel2_voltage(const struct sr_dev_inst *sdi,
428 	float range)
429 {
430 	struct dev_context *devc = sdi->priv;
431 	int ret;
432 
433 	ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
434 		"CH2:MAPPING:VOLTAGE");
435 	if (ret != SR_OK)
436 		return ret;
437 
438 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
439 		"CH2:MAPPING:VOLTAGE", range);
440 	if (ret != SR_OK)
441 		return ret;
442 
443 	if (range <= 0) {
444 		devc->channel_autorange[1] = autorange_channel2_voltage;
445 		devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
446 	} else {
447 		devc->channel_autorange[1] = NULL;
448 		devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
449 	}
450 
451 	devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_DIODE;
452 	devc->channel_meaning[1].mq = SR_MQ_VOLTAGE;
453 	devc->channel_meaning[1].unit = SR_UNIT_VOLT;
454 
455 	return SR_OK;
456 }
457 
autorange_channel2_temperature(const struct sr_dev_inst * sdi,float value)458 static void autorange_channel2_temperature(const struct sr_dev_inst *sdi,
459 	float value)
460 {
461 	mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
462 		"CH2:MAPPING:TEMP", value);
463 }
464 
configure_channel2_temperature(const struct sr_dev_inst * sdi,float range)465 static int configure_channel2_temperature(const struct sr_dev_inst *sdi,
466 	float range)
467 {
468 	struct dev_context *devc = sdi->priv;
469 	int ret;
470 
471 	ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
472 		"CH2:MAPPING:TEMP");
473 	if (ret != SR_OK)
474 		return ret;
475 
476 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
477 		"CH2:MAPPING:TEMP", range);
478 	if (ret != SR_OK)
479 		return ret;
480 
481 	if (range <= 0) {
482 		devc->channel_autorange[1] = autorange_channel2_temperature;
483 		devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
484 	} else {
485 		devc->channel_autorange[1] = NULL;
486 		devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
487 	}
488 
489 	devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_DIODE;
490 	devc->channel_meaning[1].mq = SR_MQ_TEMPERATURE;
491 	devc->channel_meaning[1].unit = SR_UNIT_CELSIUS;
492 
493 	return SR_OK;
494 }
495 
autorange_channel2_auxv(const struct sr_dev_inst * sdi,float value)496 static void autorange_channel2_auxv(const struct sr_dev_inst *sdi,
497 	float value)
498 {
499 	mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
500 		"SHARED:AUX_V", value);
501 }
502 
configure_channel2_auxv(const struct sr_dev_inst * sdi,float range)503 static int configure_channel2_auxv(const struct sr_dev_inst *sdi,
504 	float range)
505 {
506 	struct dev_context *devc = sdi->priv;
507 	int ret;
508 
509 	ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:AUX_V");
510 	if (ret != SR_OK)
511 		return ret;
512 
513 	ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
514 		"CH2:MAPPING:SHARED");
515 	if (ret != SR_OK)
516 		return ret;
517 
518 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
519 		"SHARED:AUX_V", range);
520 	if (ret != SR_OK)
521 		return ret;
522 
523 	if (range <= 0) {
524 		devc->channel_autorange[1] = autorange_channel2_auxv;
525 		devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
526 	} else {
527 		devc->channel_autorange[1] = NULL;
528 		devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
529 	}
530 
531 	devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_DIODE;
532 	devc->channel_meaning[1].mq = SR_MQ_VOLTAGE;
533 	devc->channel_meaning[1].unit = SR_UNIT_VOLT;
534 
535 	return SR_OK;
536 }
537 
autorange_channel2_resistance(const struct sr_dev_inst * sdi,float value)538 static void autorange_channel2_resistance(const struct sr_dev_inst *sdi,
539 	float value)
540 {
541 	mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
542 		"SHARED:RESISTANCE", value);
543 }
544 
configure_channel2_resistance(const struct sr_dev_inst * sdi,float range)545 static int configure_channel2_resistance(const struct sr_dev_inst *sdi,
546 	float range)
547 {
548 	struct dev_context *devc = sdi->priv;
549 	int ret;
550 
551 	ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:RESISTANCE");
552 	if (ret != SR_OK)
553 		return ret;
554 
555 	ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
556 		"CH2:MAPPING:SHARED");
557 	if (ret != SR_OK)
558 		return ret;
559 
560 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
561 		"SHARED:RESISTANCE", range);
562 	if (ret != SR_OK)
563 		return ret;
564 
565 	if (range <= 0) {
566 		devc->channel_autorange[1] = autorange_channel2_resistance;
567 		devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
568 	} else {
569 		devc->channel_autorange[1] = NULL;
570 		devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
571 	}
572 
573 	devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_DIODE;
574 	devc->channel_meaning[1].mq = SR_MQ_RESISTANCE;
575 	devc->channel_meaning[1].unit = SR_UNIT_OHM;
576 
577 	return SR_OK;
578 }
579 
autorange_channel2_diode(const struct sr_dev_inst * sdi,float value)580 static void autorange_channel2_diode(const struct sr_dev_inst *sdi,
581 	float value)
582 {
583 	mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
584 		"SHARED:DIODE", value);
585 }
586 
configure_channel2_diode(const struct sr_dev_inst * sdi,float range)587 static int configure_channel2_diode(const struct sr_dev_inst *sdi,
588 	float range)
589 {
590 	struct dev_context *devc = sdi->priv;
591 	int ret;
592 
593 	ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:DIODE");
594 	if (ret != SR_OK)
595 		return ret;
596 
597 	ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
598 		"CH2:MAPPING:SHARED");
599 	if (ret != SR_OK)
600 		return ret;
601 
602 	ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
603 		"SHARED:DIODE", range);
604 	if (ret != SR_OK)
605 		return ret;
606 
607 	if (range <= 0) {
608 		devc->channel_autorange[1] = autorange_channel2_diode;
609 		devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
610 	} else {
611 		devc->channel_autorange[1] = NULL;
612 		devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
613 	}
614 
615 	devc->channel_meaning[1].mqflags |= SR_MQFLAG_DIODE;
616 	devc->channel_meaning[1].mq = SR_MQ_VOLTAGE;
617 	devc->channel_meaning[1].unit = SR_UNIT_VOLT;
618 
619 	return SR_OK;
620 }
621 
622 /*
623  * Full string: CH1,CH2
624  * Each channel: MODE[:RANGE[:ANALYSIS]]
625  * Channel 1 mode:
626  * 	Current, A
627  * 	Temperature, T, K
628  * 	Resistance, Ohm, W
629  * 	Diode, D
630  * 	Aux, LV
631  * Channel 2 mode:
632  * 	Voltage, V
633  * 	Temperature, T, K
634  * 	Resistance, Ohm, W
635  * 	Diode, D
636  * 	Aux, LV
637  * Range is the upper bound of the range (e.g. 60 for 0-60 V or 600 for 0-600),
638  * 	zero or absent for autoranging
639  * Analysis:
640  * 	Mean, DC
641  * 	RMS, AC
642  * 	Buffer, Samples
643  */
apply_channel_config(const struct sr_dev_inst * sdi,const char * config)644 static int apply_channel_config(const struct sr_dev_inst *sdi,
645 	const char *config)
646 {
647 	gchar **channel_config;
648 	gchar **parameters;
649 	const gchar *param;
650 	int ret = SR_ERR;
651 	float range;
652 	gboolean shared_in_use = FALSE;
653 
654 	channel_config = g_strsplit_set(config, ",/", -1);
655 	if (!channel_config[0])
656 		goto err_free_channel_config;
657 
658 	parameters = g_strsplit_set(channel_config[0], ":;", -1);
659 	if (parameters[0] && parameters[0][0]) {
660 		range = 0;
661 		if (parameters[1])
662 			range = g_ascii_strtod(parameters[1], NULL);
663 
664 		param = parameters[0];
665 		if (!g_ascii_strncasecmp(param, "Resistance", 10) ||
666 			!g_ascii_strncasecmp(param, "Ohm", 3) ||
667 			!g_ascii_strncasecmp(param, "W", 1) ||
668 			!g_ascii_strncasecmp(param, "R", 1)) {
669 			ret = configure_channel1_resistance(sdi, range);
670 			if (ret != SR_OK)
671 				goto err_free_parameters;
672 			shared_in_use = TRUE;
673 		} else if (!g_ascii_strncasecmp(param, "Diode", 5) ||
674 			!g_ascii_strncasecmp(param, "D", 1)) {
675 			ret = configure_channel1_diode(sdi, range);
676 			if (ret != SR_OK)
677 				goto err_free_parameters;
678 			shared_in_use = TRUE;
679 		} else if (!g_ascii_strncasecmp(param, "Aux", 3) ||
680 			!g_ascii_strncasecmp(param, "LV", 2)) {
681 			ret = configure_channel1_auxv(sdi, range);
682 			if (ret != SR_OK)
683 				goto err_free_parameters;
684 			shared_in_use = TRUE;
685 		} else if (!g_ascii_strncasecmp(param, "T", 1) ||
686 			!g_ascii_strncasecmp(param, "K", 1)) {
687 			ret = configure_channel1_temperature(sdi, range);
688 			if (ret != SR_OK)
689 				goto err_free_parameters;
690 		} else if (!g_ascii_strncasecmp(param, "Current", 7) ||
691 			!g_ascii_strncasecmp(param, "A", 1) ||
692 			*parameters[0]) {
693 			ret = configure_channel1_current(sdi, range);
694 			if (ret != SR_OK)
695 				goto err_free_parameters;
696 		} else {
697 			sr_info("Unrecognized mode for CH1: %s.", param);
698 			ret = configure_channel1_current(sdi, range);
699 			if (ret != SR_OK)
700 				goto err_free_parameters;
701 		}
702 
703 		if (parameters[1] && parameters[2]) {
704 			param = parameters[2];
705 			if (!g_ascii_strcasecmp(param, "RMS") ||
706 				!g_ascii_strcasecmp(param, "AC")) {
707 				ret = set_channel1_rms(sdi);
708 				if (ret != SR_OK)
709 					goto err_free_parameters;
710 			} else if (!g_ascii_strcasecmp(param, "Buffer") ||
711 				!g_ascii_strcasecmp(param, "Samples")) {
712 				ret = set_channel1_buffer(sdi);
713 				if (ret != SR_OK)
714 					goto err_free_parameters;
715 			} else {
716 				ret = set_channel1_mean(sdi);
717 				if (ret != SR_OK)
718 					goto err_free_parameters;
719 			}
720 		}
721 	}
722 	g_strfreev(parameters);
723 
724 	if (!channel_config[1]) {
725 		g_strfreev(channel_config);
726 		return SR_OK;
727 	}
728 
729 	parameters = g_strsplit_set(channel_config[1], ":;", -1);
730 	if (parameters[0] && parameters[0][0]) {
731 		range = 0;
732 		if (parameters[1])
733 			range = g_ascii_strtod(parameters[1], NULL);
734 
735 		param = parameters[0];
736 		if (!g_ascii_strncasecmp(param, "Resistance", 10) ||
737 			!g_ascii_strncasecmp(param, "Ohm", 3) ||
738 			!g_ascii_strncasecmp(param, "W", 1) ||
739 			!g_ascii_strncasecmp(param, "R", 1)) {
740 			if (shared_in_use) {
741 				ret = SR_ERR;
742 				goto err_free_parameters;
743 			}
744 			ret = configure_channel2_resistance(sdi, range);
745 			if (ret != SR_OK)
746 				goto err_free_parameters;
747 		} else if (!g_ascii_strncasecmp(param, "Diode", 5) ||
748 			!g_ascii_strncasecmp(param, "D", 1)) {
749 			if (shared_in_use) {
750 				ret = SR_ERR;
751 				goto err_free_parameters;
752 			}
753 			ret = configure_channel2_diode(sdi, range);
754 			if (ret != SR_OK)
755 				goto err_free_parameters;
756 		} else if (!g_ascii_strncasecmp(param, "Aux", 3) ||
757 			!g_ascii_strncasecmp(param, "LV", 2)) {
758 			if (shared_in_use) {
759 				ret = SR_ERR;
760 				goto err_free_parameters;
761 			}
762 			ret = configure_channel2_auxv(sdi, range);
763 			if (ret != SR_OK)
764 				goto err_free_parameters;
765 		} else if (!g_ascii_strncasecmp(param, "T", 1) ||
766 			!g_ascii_strncasecmp(param, "K", 1)) {
767 			ret = configure_channel2_temperature(sdi, range);
768 			if (ret != SR_OK)
769 				goto err_free_parameters;
770 		} else if (!g_ascii_strncasecmp(param, "V", 1) ||
771 			!param[0]) {
772 			ret = configure_channel2_voltage(sdi, range);
773 			if (ret != SR_OK)
774 				goto err_free_parameters;
775 		} else {
776 			sr_info("Unrecognized mode for CH2: %s.", param);
777 			ret = configure_channel2_voltage(sdi, range);
778 			if (ret != SR_OK)
779 				goto err_free_parameters;
780 		}
781 
782 		if (parameters[1] && parameters[2]) {
783 			param = parameters[2];
784 			if (!g_ascii_strcasecmp(param, "RMS") ||
785 				!g_ascii_strcasecmp(param, "AC")) {
786 				ret = set_channel2_rms(sdi);
787 				if (ret != SR_OK)
788 					goto err_free_parameters;
789 			} else if (!g_ascii_strcasecmp(param, "Buffer") ||
790 				!g_ascii_strcasecmp(param, "Samples")) {
791 				ret = set_channel2_buffer(sdi);
792 				if (ret != SR_OK)
793 					goto err_free_parameters;
794 			} else {
795 				ret = set_channel2_mean(sdi);
796 				if (ret != SR_OK)
797 					goto err_free_parameters;
798 			}
799 		}
800 	}
801 	g_strfreev(parameters);
802 
803 	g_strfreev(channel_config);
804 	return SR_OK;
805 
806 err_free_parameters:
807 	g_strfreev(parameters);
808 err_free_channel_config:
809 	g_strfreev(channel_config);
810 	return ret;
811 }
812 
dev_open(struct sr_dev_inst * sdi)813 static int dev_open(struct sr_dev_inst *sdi)
814 {
815 	int ret;
816 
817 	ret = mooshimeter_dmm_open(sdi);
818 	if (ret != SR_OK)
819 		return ret;
820 
821 	sdi->status = SR_ST_INACTIVE;
822 
823 	ret = mooshimeter_dmm_set_chooser(sdi, "SAMPLING:TRIGGER",
824 		"SAMPLING:TRIGGER:OFF");
825 	if (ret != SR_OK)
826 		return ret;
827 
828 	ret = mooshimeter_dmm_set_larger_number(sdi, "SAMPLING:RATE",
829 		"SAMPLING:RATE", 125);
830 	if (ret != SR_OK)
831 		return ret;
832 
833 	ret = mooshimeter_dmm_set_larger_number(sdi, "SAMPLING:DEPTH",
834 		"SAMPLING:DEPTH", 64);
835 	if (ret != SR_OK)
836 		return ret;
837 
838 	/* Looks like these sometimes get set to 8, somehow? */
839 	ret = mooshimeter_dmm_set_integer(sdi, "CH1:BUF_BPS", 24);
840 	if (ret != SR_OK)
841 		return ret;
842 
843 	ret = mooshimeter_dmm_set_integer(sdi, "CH2:BUF_BPS", 24);
844 	if (ret != SR_OK)
845 		return ret;
846 
847 	ret = configure_channel1_current(sdi, 0);
848 	if (ret != SR_OK)
849 		return ret;
850 
851 	ret = set_channel1_mean(sdi);
852 	if (ret != SR_OK)
853 		return ret;
854 
855 	ret = configure_channel2_voltage(sdi, 0);
856 	if (ret != SR_OK)
857 		return ret;
858 
859 	ret = set_channel2_mean(sdi);
860 	if (ret != SR_OK)
861 		return ret;
862 
863 	sdi->status = SR_ST_ACTIVE;
864 
865 	return SR_OK;
866 }
867 
dev_close(struct sr_dev_inst * sdi)868 static int dev_close(struct sr_dev_inst *sdi)
869 {
870 	struct dev_context *devc = sdi->priv;
871 
872 	sdi->status = SR_ST_INACTIVE;
873 
874 	g_slist_free(devc->channel_meaning[0].channels);
875 	devc->channel_meaning[0].channels = NULL;
876 
877 	g_slist_free(devc->channel_meaning[1].channels);
878 	devc->channel_meaning[1].channels = NULL;
879 
880 	g_slist_free(devc->channel_meaning[2].channels);
881 	devc->channel_meaning[2].channels = NULL;
882 
883 	return mooshimeter_dmm_close(sdi);
884 }
885 
config_get(uint32_t key,GVariant ** data,const struct sr_dev_inst * sdi,const struct sr_channel_group * cg)886 static int config_get(uint32_t key, GVariant **data,
887 	const struct sr_dev_inst *sdi,
888 	const struct sr_channel_group *cg)
889 {
890 	struct dev_context *devc = sdi->priv;
891 	int ret;
892 	float value;
893 
894 	(void)cg;
895 
896 	switch (key) {
897 	case SR_CONF_SAMPLERATE:
898 		ret = mooshimeter_dmm_get_chosen_number(sdi, "SAMPLING:RATE",
899 			"SAMPLING:RATE", &value);
900 		if (ret != SR_OK)
901 			return ret;
902 		*data = g_variant_new_uint64((guint64)value);
903 		return SR_OK;
904 	case SR_CONF_AVG_SAMPLES:
905 		ret = mooshimeter_dmm_get_chosen_number(sdi, "SAMPLING:DEPTH",
906 			"SAMPLING:DEPTH", &value);
907 		if (ret != SR_OK)
908 			return ret;
909 		*data = g_variant_new_uint64((guint64)value);
910 		return SR_OK;
911 	case SR_CONF_CHANNEL_CONFIG:
912 		return SR_ERR_NA;
913 	default:
914 		break;
915 	}
916 
917 	return sr_sw_limits_config_get(&devc->limits, key, data);
918 }
919 
config_set(uint32_t key,GVariant * data,const struct sr_dev_inst * sdi,const struct sr_channel_group * cg)920 static int config_set(uint32_t key, GVariant *data,
921 	const struct sr_dev_inst *sdi,
922 	const struct sr_channel_group *cg)
923 {
924 	struct dev_context *devc = sdi->priv;
925 
926 	(void)cg;
927 
928 	switch (key) {
929 	case SR_CONF_SAMPLERATE:
930 		return mooshimeter_dmm_set_larger_number(sdi, "SAMPLING:RATE",
931 			"SAMPLING:RATE", g_variant_get_uint64(data));
932 	case SR_CONF_AVG_SAMPLES:
933 		return mooshimeter_dmm_set_larger_number(sdi, "SAMPLING:DEPTH",
934 			"SAMPLING:DEPTH", g_variant_get_uint64(data));
935 	case SR_CONF_CHANNEL_CONFIG:
936 		return apply_channel_config(sdi, g_variant_get_string(data, NULL));
937 	default:
938 		break;
939 	}
940 
941 	return sr_sw_limits_config_set(&devc->limits, key, data);
942 }
943 
config_list(uint32_t key,GVariant ** data,const struct sr_dev_inst * sdi,const struct sr_channel_group * cg)944 static int config_list(uint32_t key, GVariant **data,
945 	const struct sr_dev_inst *sdi,
946 	const struct sr_channel_group *cg)
947 {
948 	int ret;
949 	float *values;
950 	size_t count;
951 	uint64_t *integers;
952 
953 	switch (key) {
954 	case SR_CONF_SAMPLERATE:
955 		ret = mooshimeter_dmm_get_available_number_choices(sdi,
956 			"SAMPLING:RATE", &values, &count);
957 		if (ret != SR_OK)
958 			return ret;
959 		integers = g_malloc(sizeof(uint64_t) * count);
960 		for (size_t i = 0; i < count; i++)
961 			integers[i] = (uint64_t)values[i];
962 		g_free(values);
963 		*data = std_gvar_samplerates(integers, count);
964 		g_free(integers);
965 		return SR_OK;
966 	case SR_CONF_AVG_SAMPLES:
967 		ret = mooshimeter_dmm_get_available_number_choices(sdi,
968 			"SAMPLING:DEPTH", &values, &count);
969 		if (ret != SR_OK)
970 			return ret;
971 		integers = g_malloc(sizeof(uint64_t) * count);
972 		for (size_t i = 0; i < count; i++)
973 			integers[i] = (uint64_t)values[i];
974 		g_free(values);
975 		*data = std_gvar_array_u64(integers, count);
976 		g_free(integers);
977 		return SR_OK;
978 	case SR_CONF_CHANNEL_CONFIG:
979 		return SR_ERR_NA;
980 	default:
981 		break;
982 	}
983 
984 	return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
985 }
986 
dev_acquisition_start(const struct sr_dev_inst * sdi)987 static int dev_acquisition_start(const struct sr_dev_inst *sdi)
988 {
989 	struct dev_context *devc = sdi->priv;
990 	int ret;
991 
992 	ret = mooshimeter_dmm_set_chooser(sdi, "SAMPLING:TRIGGER",
993 		"SAMPLING:TRIGGER:CONTINUOUS");
994 	if (ret)
995 		return ret;
996 
997 	sr_sw_limits_acquisition_start(&devc->limits);
998 	std_session_send_df_header(sdi);
999 
1000 	sr_session_source_add(sdi->session, -1, 0, 10000,
1001 		mooshimeter_dmm_heartbeat, (void *)sdi);
1002 
1003 	/* The Bluetooth socket isn't exposed, so just poll for data. */
1004 	sr_session_source_add(sdi->session, -2, 0, 50,
1005 		mooshimeter_dmm_poll, (void *)sdi);
1006 
1007 	devc->enable_value_stream = TRUE;
1008 
1009 	return SR_OK;
1010 }
1011 
dev_acquisition_stop(struct sr_dev_inst * sdi)1012 static int dev_acquisition_stop(struct sr_dev_inst *sdi)
1013 {
1014 	struct dev_context *devc = sdi->priv;
1015 
1016 	sr_session_source_remove(sdi->session, -1);
1017 	sr_session_source_remove(sdi->session, -2);
1018 	devc->enable_value_stream = FALSE;
1019 
1020 	mooshimeter_dmm_set_chooser(sdi, "SAMPLING:TRIGGER",
1021 		"SAMPLING:TRIGGER:OFF");
1022 
1023 	return SR_OK;
1024 }
1025 
1026 static struct sr_dev_driver mooshimeter_dmm_driver_info = {
1027 	.name = "mooshimeter-dmm",
1028 	.longname = "Mooshimeter DMM",
1029 	.api_version = 1,
1030 	.init = std_init,
1031 	.cleanup = std_cleanup,
1032 	.scan = scan,
1033 	.dev_list = std_dev_list,
1034 	.dev_clear = dev_clear,
1035 	.config_get = config_get,
1036 	.config_set = config_set,
1037 	.config_list = config_list,
1038 	.dev_open = dev_open,
1039 	.dev_close = dev_close,
1040 	.dev_acquisition_start = dev_acquisition_start,
1041 	.dev_acquisition_stop = dev_acquisition_stop,
1042 	.context = NULL,
1043 };
1044 SR_REGISTER_DEV_DRIVER(mooshimeter_dmm_driver_info);
1045