2 * This file is part of the libsigrok project.
4 * Copyright (C) 2019 Derek Hageman <hageman@inthat.cloud>
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.
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/>.
23 static struct sr_dev_driver mooshimeter_dmm_driver_info;
25 static const uint32_t scanopts[] = {
29 static const uint32_t drvopts[] = {
33 static const uint32_t devopts[] = {
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,
42 static void init_dev(struct sr_dev_inst *sdi)
44 struct dev_context *devc;
45 struct sr_channel *chan;
47 devc = g_new0(struct dev_context, 1);
49 sdi->status = SR_ST_INITIALIZING;
50 sdi->vendor = g_strdup("Mooshim Engineering");
51 sdi->model = g_strdup("Mooshimeter");
53 sr_sw_limits_init(&devc->limits);
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);
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);
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);
74 static GSList *scan(struct sr_dev_driver *di, GSList *options)
76 struct sr_bt_desc *desc;
78 struct sr_config *src;
83 for (l = options; l; l = l->next) {
87 conn = g_variant_get_string(src->data, NULL);
95 desc = sr_bt_desc_new();
99 ret = sr_bt_config_addr_remote(desc, conn);
104 * These handles where queried with btgatt-client, since the
105 * documentation specifies them in terms of UUIDs.
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
114 ret = sr_bt_config_notify(desc, 0x0015, 0x0012, 0x0016, 0x0001);
118 ret = sr_bt_connect_ble(desc);
121 sr_bt_disconnect(desc);
123 struct sr_dev_inst *sdi = g_malloc0(sizeof(struct sr_dev_inst));
124 struct dev_context *devc = g_malloc0(sizeof(struct dev_context));
127 sdi->inst_type = SR_INST_USER;
128 sdi->connection_id = g_strdup(conn);
133 return std_scan_complete(di, g_slist_prepend(NULL, sdi));
136 sr_bt_desc_free(desc);
140 static int dev_clear(const struct sr_dev_driver *di)
142 struct drv_context *drvc = di->context;
143 struct sr_dev_inst *sdi;
147 for (l = drvc->instances; l; l = l->next) {
149 struct sr_bt_desc *desc = sdi->conn;
151 sr_bt_desc_free(desc);
156 return std_dev_clear(di);
159 static int set_channel1_mean(const struct sr_dev_inst *sdi)
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;
165 return mooshimeter_dmm_set_chooser(sdi, "CH1:ANALYSIS",
166 "CH1:ANALYSIS:MEAN");
169 static int set_channel1_rms(const struct sr_dev_inst *sdi)
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;
175 return mooshimeter_dmm_set_chooser(sdi, "CH1:ANALYSIS",
179 static int set_channel1_buffer(const struct sr_dev_inst *sdi)
181 struct dev_context *devc = sdi->priv;
182 devc->channel_meaning[0].mqflags &= ~(SR_MQFLAG_DC | SR_MQFLAG_RMS);
184 return mooshimeter_dmm_set_chooser(sdi, "CH1:ANALYSIS",
185 "CH1:ANALYSIS:BUFFER");
188 static int set_channel2_mean(const struct sr_dev_inst *sdi)
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;
194 return mooshimeter_dmm_set_chooser(sdi, "CH2:ANALYSIS",
195 "CH2:ANALYSIS:MEAN");
198 static int set_channel2_rms(const struct sr_dev_inst *sdi)
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;
204 return mooshimeter_dmm_set_chooser(sdi, "CH2:ANALYSIS",
208 static int set_channel2_buffer(const struct sr_dev_inst *sdi)
210 struct dev_context *devc = sdi->priv;
212 devc->channel_meaning[1].mqflags &= ~(SR_MQFLAG_DC | SR_MQFLAG_RMS);
214 return mooshimeter_dmm_set_chooser(sdi, "CH2:ANALYSIS",
215 "CH2:ANALYSIS:BUFFER");
218 static void autorange_channel1_current(const struct sr_dev_inst *sdi,
221 mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
222 "CH1:MAPPING:CURRENT", value);
225 static int configure_channel1_current(const struct sr_dev_inst *sdi,
228 struct dev_context *devc = sdi->priv;
231 ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
232 "CH1:MAPPING:CURRENT");
236 ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
237 "CH1:MAPPING:CURRENT", range);
242 devc->channel_autorange[0] = autorange_channel1_current;
243 devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
245 devc->channel_autorange[0] = NULL;
246 devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
256 static void autorange_channel1_temperature(const struct sr_dev_inst *sdi,
259 mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
260 "CH1:MAPPING:TEMP", value);
263 static int configure_channel1_temperature(const struct sr_dev_inst *sdi,
266 struct dev_context *devc = sdi->priv;
269 ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
274 ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
275 "CH1:MAPPING:TEMP", range);
280 devc->channel_autorange[0] = autorange_channel1_temperature;
281 devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
283 devc->channel_autorange[0] = NULL;
284 devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
294 static void autorange_channel1_auxv(const struct sr_dev_inst *sdi,
297 mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
298 "SHARED:AUX_V", value);
301 static int configure_channel1_auxv(const struct sr_dev_inst *sdi,
304 struct dev_context *devc = sdi->priv;
307 ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:AUX_V");
311 ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
312 "CH1:MAPPING:SHARED");
316 ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
317 "SHARED:AUX_V", range);
322 devc->channel_autorange[0] = autorange_channel1_auxv;
323 devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
325 devc->channel_autorange[0] = NULL;
326 devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
336 static void autorange_channel1_resistance(const struct sr_dev_inst *sdi,
339 mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
340 "SHARED:RESISTANCE", value);
343 static int configure_channel1_resistance(const struct sr_dev_inst *sdi,
346 struct dev_context *devc = sdi->priv;
349 ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:RESISTANCE");
353 ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
354 "CH1:MAPPING:SHARED");
358 ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
359 "SHARED:RESISTANCE", range);
364 devc->channel_autorange[0] = autorange_channel1_resistance;
365 devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
367 devc->channel_autorange[0] = NULL;
368 devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
378 static void autorange_channel1_diode(const struct sr_dev_inst *sdi,
381 mooshimeter_dmm_set_autorange(sdi, "CH1:RANGE_I",
382 "SHARED:DIODE", value);
385 static int configure_channel1_diode(const struct sr_dev_inst *sdi,
388 struct dev_context *devc = sdi->priv;
391 ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:DIODE");
395 ret = mooshimeter_dmm_set_chooser(sdi, "CH1:MAPPING",
396 "CH1:MAPPING:SHARED");
400 ret = mooshimeter_dmm_set_larger_number(sdi, "CH1:RANGE_I",
401 "SHARED:DIODE", range);
406 devc->channel_autorange[0] = autorange_channel1_diode;
407 devc->channel_meaning[0].mqflags |= SR_MQFLAG_AUTORANGE;
409 devc->channel_autorange[0] = NULL;
410 devc->channel_meaning[0].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
420 static void autorange_channel2_voltage(const struct sr_dev_inst *sdi,
423 mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
424 "CH2:MAPPING:VOLTAGE", value);
427 static int configure_channel2_voltage(const struct sr_dev_inst *sdi,
430 struct dev_context *devc = sdi->priv;
433 ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
434 "CH2:MAPPING:VOLTAGE");
438 ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
439 "CH2:MAPPING:VOLTAGE", range);
444 devc->channel_autorange[1] = autorange_channel2_voltage;
445 devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
447 devc->channel_autorange[1] = NULL;
448 devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
458 static void autorange_channel2_temperature(const struct sr_dev_inst *sdi,
461 mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
462 "CH2:MAPPING:TEMP", value);
465 static int configure_channel2_temperature(const struct sr_dev_inst *sdi,
468 struct dev_context *devc = sdi->priv;
471 ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
476 ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
477 "CH2:MAPPING:TEMP", range);
482 devc->channel_autorange[1] = autorange_channel2_temperature;
483 devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
485 devc->channel_autorange[1] = NULL;
486 devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
496 static void autorange_channel2_auxv(const struct sr_dev_inst *sdi,
499 mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
500 "SHARED:AUX_V", value);
503 static int configure_channel2_auxv(const struct sr_dev_inst *sdi,
506 struct dev_context *devc = sdi->priv;
509 ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:AUX_V");
513 ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
514 "CH2:MAPPING:SHARED");
518 ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
519 "SHARED:AUX_V", range);
524 devc->channel_autorange[1] = autorange_channel2_auxv;
525 devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
527 devc->channel_autorange[1] = NULL;
528 devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
538 static void autorange_channel2_resistance(const struct sr_dev_inst *sdi,
541 mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
542 "SHARED:RESISTANCE", value);
545 static int configure_channel2_resistance(const struct sr_dev_inst *sdi,
548 struct dev_context *devc = sdi->priv;
551 ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:RESISTANCE");
555 ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
556 "CH2:MAPPING:SHARED");
560 ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
561 "SHARED:RESISTANCE", range);
566 devc->channel_autorange[1] = autorange_channel2_resistance;
567 devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
569 devc->channel_autorange[1] = NULL;
570 devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
580 static void autorange_channel2_diode(const struct sr_dev_inst *sdi,
583 mooshimeter_dmm_set_autorange(sdi, "CH2:RANGE_I",
584 "SHARED:DIODE", value);
587 static int configure_channel2_diode(const struct sr_dev_inst *sdi,
590 struct dev_context *devc = sdi->priv;
593 ret = mooshimeter_dmm_set_chooser(sdi, "SHARED", "SHARED:DIODE");
597 ret = mooshimeter_dmm_set_chooser(sdi, "CH2:MAPPING",
598 "CH2:MAPPING:SHARED");
602 ret = mooshimeter_dmm_set_larger_number(sdi, "CH2:RANGE_I",
603 "SHARED:DIODE", range);
608 devc->channel_autorange[1] = autorange_channel2_diode;
609 devc->channel_meaning[1].mqflags |= SR_MQFLAG_AUTORANGE;
611 devc->channel_autorange[1] = NULL;
612 devc->channel_meaning[1].mqflags &= ~SR_MQFLAG_AUTORANGE;
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;
623 * Full string: CH1,CH2
624 * Each channel: MODE[:RANGE[:ANALYSIS]]
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
644 static int apply_channel_config(const struct sr_dev_inst *sdi,
647 gchar **channel_config;
652 gboolean shared_in_use = FALSE;
654 channel_config = g_strsplit_set(config, ",/", -1);
655 if (!channel_config[0])
656 goto err_free_channel_config;
658 parameters = g_strsplit_set(channel_config[0], ":;", -1);
659 if (parameters[0] && parameters[0][0]) {
662 range = g_ascii_strtod(parameters[1], NULL);
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);
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);
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);
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);
689 goto err_free_parameters;
690 } else if (!g_ascii_strncasecmp(param, "Current", 7) ||
691 !g_ascii_strncasecmp(param, "A", 1) ||
693 ret = configure_channel1_current(sdi, range);
695 goto err_free_parameters;
697 sr_info("Unrecognized mode for CH1: %s.", param);
698 ret = configure_channel1_current(sdi, range);
700 goto err_free_parameters;
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);
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);
714 goto err_free_parameters;
716 ret = set_channel1_mean(sdi);
718 goto err_free_parameters;
722 g_strfreev(parameters);
724 if (!channel_config[1]) {
725 g_strfreev(channel_config);
729 parameters = g_strsplit_set(channel_config[1], ":;", -1);
730 if (parameters[0] && parameters[0][0]) {
733 range = g_ascii_strtod(parameters[1], NULL);
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)) {
742 goto err_free_parameters;
744 ret = configure_channel2_resistance(sdi, range);
746 goto err_free_parameters;
747 } else if (!g_ascii_strncasecmp(param, "Diode", 5) ||
748 !g_ascii_strncasecmp(param, "D", 1)) {
751 goto err_free_parameters;
753 ret = configure_channel2_diode(sdi, range);
755 goto err_free_parameters;
756 } else if (!g_ascii_strncasecmp(param, "Aux", 3) ||
757 !g_ascii_strncasecmp(param, "LV", 2)) {
760 goto err_free_parameters;
762 ret = configure_channel2_auxv(sdi, range);
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);
769 goto err_free_parameters;
770 } else if (!g_ascii_strncasecmp(param, "V", 1) ||
772 ret = configure_channel2_voltage(sdi, range);
774 goto err_free_parameters;
776 sr_info("Unrecognized mode for CH2: %s.", param);
777 ret = configure_channel2_voltage(sdi, range);
779 goto err_free_parameters;
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);
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);
793 goto err_free_parameters;
795 ret = set_channel2_mean(sdi);
797 goto err_free_parameters;
801 g_strfreev(parameters);
803 g_strfreev(channel_config);
807 g_strfreev(parameters);
808 err_free_channel_config:
809 g_strfreev(channel_config);
813 static int dev_open(struct sr_dev_inst *sdi)
817 ret = mooshimeter_dmm_open(sdi);
821 sdi->status = SR_ST_INACTIVE;
823 ret = mooshimeter_dmm_set_chooser(sdi, "SAMPLING:TRIGGER",
824 "SAMPLING:TRIGGER:OFF");
828 ret = mooshimeter_dmm_set_larger_number(sdi, "SAMPLING:RATE",
829 "SAMPLING:RATE", 125);
833 ret = mooshimeter_dmm_set_larger_number(sdi, "SAMPLING:DEPTH",
834 "SAMPLING:DEPTH", 64);
838 /* Looks like these sometimes get set to 8, somehow? */
839 ret = mooshimeter_dmm_set_integer(sdi, "CH1:BUF_BPS", 24);
843 ret = mooshimeter_dmm_set_integer(sdi, "CH2:BUF_BPS", 24);
847 ret = configure_channel1_current(sdi, 0);
851 ret = set_channel1_mean(sdi);
855 ret = configure_channel2_voltage(sdi, 0);
859 ret = set_channel2_mean(sdi);
863 sdi->status = SR_ST_ACTIVE;
868 static int dev_close(struct sr_dev_inst *sdi)
870 struct dev_context *devc = sdi->priv;
872 sdi->status = SR_ST_INACTIVE;
874 g_slist_free(devc->channel_meaning[0].channels);
875 devc->channel_meaning[0].channels = NULL;
877 g_slist_free(devc->channel_meaning[1].channels);
878 devc->channel_meaning[1].channels = NULL;
880 g_slist_free(devc->channel_meaning[2].channels);
881 devc->channel_meaning[2].channels = NULL;
883 return mooshimeter_dmm_close(sdi);
886 static int config_get(uint32_t key, GVariant **data,
887 const struct sr_dev_inst *sdi,
888 const struct sr_channel_group *cg)
890 struct dev_context *devc = sdi->priv;
897 case SR_CONF_SAMPLERATE:
898 ret = mooshimeter_dmm_get_chosen_number(sdi, "SAMPLING:RATE",
899 "SAMPLING:RATE", &value);
902 *data = g_variant_new_uint64((guint64)value);
904 case SR_CONF_AVG_SAMPLES:
905 ret = mooshimeter_dmm_get_chosen_number(sdi, "SAMPLING:DEPTH",
906 "SAMPLING:DEPTH", &value);
909 *data = g_variant_new_uint64((guint64)value);
911 case SR_CONF_CHANNEL_CONFIG:
917 return sr_sw_limits_config_get(&devc->limits, key, data);
920 static int config_set(uint32_t key, GVariant *data,
921 const struct sr_dev_inst *sdi,
922 const struct sr_channel_group *cg)
924 struct dev_context *devc = sdi->priv;
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));
941 return sr_sw_limits_config_set(&devc->limits, key, data);
944 static int config_list(uint32_t key, GVariant **data,
945 const struct sr_dev_inst *sdi,
946 const struct sr_channel_group *cg)
954 case SR_CONF_SAMPLERATE:
955 ret = mooshimeter_dmm_get_available_number_choices(sdi,
956 "SAMPLING:RATE", &values, &count);
959 integers = g_malloc(sizeof(uint64_t) * count);
960 for (size_t i = 0; i < count; i++)
961 integers[i] = (uint64_t)values[i];
963 *data = std_gvar_samplerates(integers, count);
966 case SR_CONF_AVG_SAMPLES:
967 ret = mooshimeter_dmm_get_available_number_choices(sdi,
968 "SAMPLING:DEPTH", &values, &count);
971 integers = g_malloc(sizeof(uint64_t) * count);
972 for (size_t i = 0; i < count; i++)
973 integers[i] = (uint64_t)values[i];
975 *data = std_gvar_array_u64(integers, count);
978 case SR_CONF_CHANNEL_CONFIG:
984 return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
987 static int dev_acquisition_start(const struct sr_dev_inst *sdi)
989 struct dev_context *devc = sdi->priv;
992 ret = mooshimeter_dmm_set_chooser(sdi, "SAMPLING:TRIGGER",
993 "SAMPLING:TRIGGER:CONTINUOUS");
997 sr_sw_limits_acquisition_start(&devc->limits);
998 std_session_send_df_header(sdi);
1000 sr_session_source_add(sdi->session, -1, 0, 10000,
1001 mooshimeter_dmm_heartbeat, (void *)sdi);
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);
1007 devc->enable_value_stream = TRUE;
1012 static int dev_acquisition_stop(struct sr_dev_inst *sdi)
1014 struct dev_context *devc = sdi->priv;
1016 sr_session_source_remove(sdi->session, -1);
1017 sr_session_source_remove(sdi->session, -2);
1018 devc->enable_value_stream = FALSE;
1020 mooshimeter_dmm_set_chooser(sdi, "SAMPLING:TRIGGER",
1021 "SAMPLING:TRIGGER:OFF");
1026 static struct sr_dev_driver mooshimeter_dmm_driver_info = {
1027 .name = "mooshimeter-dmm",
1028 .longname = "Mooshimeter DMM",
1031 .cleanup = std_cleanup,
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,
1044 SR_REGISTER_DEV_DRIVER(mooshimeter_dmm_driver_info);