]> sigrok.org Git - libsigrok.git/blob - src/hardware/scpi-pps/api.c
scpi-pps: Add support for Rigol DP831A/DP832A.
[libsigrok.git] / src / hardware / scpi-pps / api.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
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 <string.h>
21 #include "protocol.h"
22
23 SR_PRIV struct sr_dev_driver scpi_pps_driver_info;
24 static struct sr_dev_driver *di = &scpi_pps_driver_info;
25 extern unsigned int num_pps_profiles;
26 extern const struct scpi_pps pps_profiles[];
27
28 static const int32_t scanopts[] = {
29         SR_CONF_CONN,
30         SR_CONF_SERIALCOMM,
31 };
32
33 static int init(struct sr_context *sr_ctx)
34 {
35         return std_init(sr_ctx, di, LOG_PREFIX);
36 }
37
38 static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
39 {
40         struct dev_context *devc;
41         struct sr_dev_inst *sdi;
42         struct sr_scpi_hw_info *hw_info;
43         struct sr_channel_group *cg;
44         struct sr_channel *ch;
45         const struct scpi_pps *device;
46         const struct channel_group_spec *cgs;
47         struct pps_channel_group *pcg;
48         GRegex *model_re;
49         GMatchInfo *model_mi;
50         uint64_t mask;
51         unsigned int i, j;
52         const char *vendor;
53
54         if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
55                 sr_info("Couldn't get IDN response.");
56                 return NULL;
57         }
58
59         device = NULL;
60         for (i = 0; i < num_pps_profiles; i++) {
61                 vendor = get_vendor(hw_info->manufacturer);
62                 if (strcasecmp(vendor, pps_profiles[i].vendor))
63                         continue;
64                 model_re = g_regex_new(pps_profiles[i].model, 0, 0, NULL);
65                 if (g_regex_match(model_re, hw_info->model, 0, &model_mi))
66                         device = &pps_profiles[i];
67                 g_match_info_unref(model_mi);
68                 g_regex_unref(model_re);
69                 if (device)
70                         break;
71         }
72         if (!device) {
73                 sr_scpi_hw_info_free(hw_info);
74                 return NULL;
75         }
76
77         sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, vendor, hw_info->model,
78                         hw_info->firmware_version);
79         sdi->conn = scpi;
80         sdi->driver = di;
81         sdi->inst_type = SR_INST_SCPI;
82         devc = g_malloc0(sizeof(struct dev_context));
83         devc->device = device;
84         sdi->priv = devc;
85
86         for (i = 0; i < device->num_channels; i++) {
87                 ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
88                                 device->channels[i].name);
89                 sdi->channels = g_slist_append(sdi->channels, ch);
90         }
91
92         for (i = 0; i < device->num_channel_groups; i++) {
93                 cgs = &device->channel_groups[i];
94                 cg = g_malloc0(sizeof(struct sr_channel_group));
95                 cg->name = g_strdup(cgs->name);
96                 for (j = 0, mask = 1; j < 64; j++, mask <<= 1) {
97                         if (cgs->channel_index_mask & mask) {
98                                 ch = g_slist_nth_data(sdi->channels, j);
99                                 cg->channels = g_slist_append(cg->channels, ch);
100                         }
101                 }
102                 pcg = g_malloc0(sizeof(struct pps_channel_group));
103                 pcg->features = cgs->features;
104                 cg->priv = pcg;
105                 sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
106         }
107
108         /* SCPI devices commonly lock the panel keys when accessed remotely. */
109         scpi_cmd(sdi, SCPI_CMD_KEY_UNLOCK);
110         sr_scpi_close(scpi);
111
112         return sdi;
113 }
114
115 static GSList *scan(GSList *options)
116 {
117         return sr_scpi_scan(di->priv, options, probe_device);
118 }
119
120 static GSList *dev_list(void)
121 {
122         return ((struct drv_context *)(di->priv))->instances;
123 }
124
125 static int dev_clear(void)
126 {
127         return std_dev_clear(di, NULL);
128 }
129
130 static int dev_open(struct sr_dev_inst *sdi)
131 {
132         struct sr_scpi_dev_inst *scpi;
133
134         if (sdi->status != SR_ST_ACTIVE)
135                 return SR_ERR;
136
137         scpi = sdi->conn;
138         if (sr_scpi_open(scpi) < 0)
139                 return SR_ERR;
140
141         sdi->status = SR_ST_ACTIVE;
142
143         return SR_OK;
144 }
145
146 static int dev_close(struct sr_dev_inst *sdi)
147 {
148         struct sr_scpi_dev_inst *scpi;
149
150         if (sdi->status != SR_ST_ACTIVE)
151                 return SR_ERR_DEV_CLOSED;
152
153         scpi = sdi->conn;
154         if (scpi) {
155                 scpi_cmd(sdi, SCPI_CMD_KEY_UNLOCK);
156                 sr_scpi_close(scpi);
157                 sdi->status = SR_ST_INACTIVE;
158         }
159
160         return SR_OK;
161 }
162
163 static int cleanup(void)
164 {
165         return SR_OK;
166 }
167
168 static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
169                 const struct sr_channel_group *cg)
170 {
171         struct dev_context *devc;
172         struct sr_scpi_dev_inst *scpi;
173         struct sr_channel *ch;
174         double d;
175         int ret;
176         char *s;
177
178         if (!sdi)
179                 return SR_ERR_ARG;
180
181         devc = sdi->priv;
182         scpi = sdi->conn;
183
184         ret = SR_OK;
185         if (!cg) {
186                 /* No channel group: global options. */
187                 switch (key) {
188                 case SR_CONF_OVER_TEMPERATURE_PROTECTION:
189                         ret = SR_ERR;
190                         if (scpi_cmd(sdi, SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION) == SR_OK) {
191                                 if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
192                                         *data = g_variant_new_boolean(!strcmp(s, "ON"));
193                                         ret = SR_OK;
194                                 }
195                         }
196                         break;
197                         return SR_ERR_NA;
198                         break;
199                 case SR_CONF_OUTPUT_CHANNEL_CONFIG:
200                         ret = SR_ERR;
201                         if (scpi_cmd(sdi, SCPI_CMD_GET_OUTPUT_CHANNEL_CONFIG) == SR_OK) {
202                                 if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
203                                         *data = g_variant_new_string(s);
204                                         g_free(s);
205                                         ret = SR_OK;
206                                 }
207                         }
208                         break;
209                 default:
210                         return SR_ERR_NA;
211                 }
212         } else {
213                 /*
214                  * These options only apply to channel groups with a single
215                  * channel -- they're per-channel settings for the device.
216                  */
217                 if (g_slist_length(cg->channels) > 1)
218                         return SR_ERR_NA;
219                 ch = cg->channels->data;
220
221                 switch (key) {
222                 case SR_CONF_OUTPUT_REGULATION:
223                         ret = SR_ERR;
224                         if (scpi_cmd(sdi, SCPI_CMD_GET_OUTPUT_REGULATION, ch->name) == SR_OK) {
225                                 if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
226                                         if (strcmp(s, "CC") && strcmp(s, "CV") && strcmp(s, "UR")) {
227                                                 sr_dbg("Unknown response to SCPI_CMD_GET_OUTPUT_REGULATION: %s", s);
228                                         } else {
229                                                 *data = g_variant_new_string(s);
230                                                 g_free(s);
231                                                 ret = SR_OK;
232                                         }
233                                 }
234                         }
235                         break;
236                 case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
237                         ret = SR_ERR;
238                         if (scpi_cmd(sdi, SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ENABLED,
239                                         ch->name) == SR_OK) {
240                                 if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
241                                         *data = g_variant_new_boolean(!strcmp(s, "ON"));
242                                         ret = SR_OK;
243                                 }
244                         }
245                         break;
246                 case SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE:
247                         ret = SR_ERR;
248                         if (scpi_cmd(sdi, SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE,
249                                         ch->name) == SR_OK) {
250                                 if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
251                                         *data = g_variant_new_boolean(!strcmp(s, "YES"));
252                                         ret = SR_OK;
253                                 }
254                         }
255                         break;
256                 case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
257                         ret = SR_ERR;
258                         if (scpi_cmd(sdi, SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_THRESHOLD,
259                                         ch->name) == SR_OK) {
260                                 if (sr_scpi_get_double(scpi, NULL, &d) == SR_OK) {
261                                         *data = g_variant_new_double(d);
262                                         ret = SR_OK;
263                                 }
264                         }
265                         break;
266                 case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
267                         ret = SR_ERR;
268                         if (scpi_cmd(sdi, SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ENABLED,
269                                         ch->name) == SR_OK) {
270                                 if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
271                                         *data = g_variant_new_boolean(!strcmp(s, "ON"));
272                                         ret = SR_OK;
273                                 }
274                         }
275                         break;
276                 case SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE:
277                         ret = SR_ERR;
278                         if (scpi_cmd(sdi, SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE,
279                                         ch->name) == SR_OK) {
280                                 if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
281                                         *data = g_variant_new_boolean(!strcmp(s, "YES"));
282                                         ret = SR_OK;
283                                 }
284                         }
285                         break;
286                 case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
287                         ret = SR_ERR;
288                         if (scpi_cmd(sdi, SCPI_CMD_GET_OVER_CURRENT_PROTECTION_THRESHOLD,
289                                         ch->name) == SR_OK) {
290                                 if (sr_scpi_get_double(scpi, NULL, &d) == SR_OK) {
291                                         *data = g_variant_new_double(d);
292                                         ret = SR_OK;
293                                 }
294                         }
295                         break;
296                 case SR_CONF_OUTPUT_VOLTAGE:
297                         ret = SR_ERR;
298                         if (scpi_cmd(sdi, SCPI_CMD_GET_MEAS_VOLTAGE, ch->name) == SR_OK) {
299                                 if (sr_scpi_get_double(scpi, NULL, &d) == SR_OK) {
300                                         *data = g_variant_new_double(d);
301                                         ret = SR_OK;
302                                 }
303                         }
304                         break;
305                 case SR_CONF_OUTPUT_VOLTAGE_MAX:
306                         ret = SR_ERR;
307                         if (scpi_cmd(sdi, SCPI_CMD_GET_VOLTAGE_MAX, ch->name) == SR_OK) {
308                                 if (sr_scpi_get_double(scpi, NULL, &d) == SR_OK) {
309                                         *data = g_variant_new_double(d);
310                                         ret = SR_OK;
311                                 }
312                         }
313                         break;
314                 case SR_CONF_OUTPUT_CURRENT:
315                         ret = SR_ERR;
316                         if (scpi_cmd(sdi, SCPI_CMD_GET_MEAS_CURRENT, ch->name) == SR_OK) {
317                                 if (sr_scpi_get_double(scpi, NULL, &d) == SR_OK) {
318                                         *data = g_variant_new_double(d);
319                                         ret = SR_OK;
320                                 }
321                         }
322                         break;
323                 case SR_CONF_OUTPUT_CURRENT_MAX:
324                         ret = SR_ERR;
325                         if (scpi_cmd(sdi, SCPI_CMD_GET_CURRENT_MAX, ch->name) == SR_OK) {
326                                 if (sr_scpi_get_double(scpi, NULL, &d) == SR_OK) {
327                                         *data = g_variant_new_double(d);
328                                         ret = SR_OK;
329                                 }
330                         }
331                         break;
332                 case SR_CONF_OUTPUT_ENABLED:
333                         ret = SR_ERR;
334                         if (scpi_cmd(sdi, SCPI_CMD_GET_OUTPUT_ENABLED, ch->name) == SR_OK) {
335                                 if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
336                                         *data = g_variant_new_boolean(!strcmp(s, "ON"));
337                                         ret = SR_OK;
338                                 }
339                         }
340                         break;
341                 default:
342                         return SR_ERR_NA;
343                 }
344         }
345
346         return ret;
347 }
348
349 static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
350                 const struct sr_channel_group *cg)
351 {
352         struct sr_channel *ch;
353         double d;
354         int ret;
355         const char *s;
356
357         if (sdi->status != SR_ST_ACTIVE)
358                 return SR_ERR_DEV_CLOSED;
359
360
361         ret = SR_OK;
362         if (!cg) {
363                 switch (key) {
364                 /* No channel group: global options. */
365                 case SR_CONF_OVER_TEMPERATURE_PROTECTION:
366                         s = g_variant_get_boolean(data) ? "ON" : "OFF";
367                         if (scpi_cmd(sdi, SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION, s) < 0)
368                                 ret = SR_ERR;
369                         break;
370                 case SR_CONF_OUTPUT_CHANNEL_CONFIG:
371                         s = g_variant_get_string(data, NULL);
372                         if (scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_CHANNEL_CONFIG, s) < 0)
373                                 ret = SR_ERR;
374                         break;
375                 default:
376                         ret = SR_ERR_NA;
377                 }
378         } else {
379                 /* Channel group specified. */
380                 if (!sdi)
381                         return SR_ERR_ARG;
382                 if (g_slist_length(cg->channels) > 1)
383                         return SR_ERR_NA;
384                 ch = cg->channels->data;
385                 switch (key) {
386                 case SR_CONF_OUTPUT_VOLTAGE_MAX:
387                         d = g_variant_get_double(data);
388                         if (scpi_cmd(sdi, SCPI_CMD_SET_VOLTAGE_MAX, ch->name, d) < 0)
389                                 ret = SR_ERR;
390                         break;
391                 case SR_CONF_OUTPUT_CURRENT_MAX:
392                         d = g_variant_get_double(data);
393                         if (scpi_cmd(sdi, SCPI_CMD_SET_CURRENT_MAX, ch->name, d) < 0)
394                                 ret = SR_ERR;
395                         break;
396                 case SR_CONF_OUTPUT_ENABLED:
397                         s = g_variant_get_boolean(data) ? "ON" : "OFF";
398                         if (scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_ENABLED, ch->name, s) < 0)
399                                 ret = SR_ERR;
400                         break;
401                 case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
402                         s = g_variant_get_boolean(data) ? "ON" : "OFF";
403                         if (scpi_cmd(sdi, SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_ENABLED,
404                                         ch->name, s) < 0)
405                                 ret = SR_ERR;
406                         break;
407                 case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
408                         d = g_variant_get_double(data);
409                         if (scpi_cmd(sdi, SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD,
410                                         ch->name, d) < 0)
411                                 ret = SR_ERR;
412                         break;
413                 case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
414                         s = g_variant_get_boolean(data) ? "ON" : "OFF";
415                         if (scpi_cmd(sdi, SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLED,
416                                         ch->name, s) < 0)
417                                 ret = SR_ERR;
418                         break;
419                 case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
420                         d = g_variant_get_double(data);
421                         if (scpi_cmd(sdi, SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD,
422                                         ch->name, d) < 0)
423                                 ret = SR_ERR;
424                         break;
425                 default:
426                         ret = SR_ERR_NA;
427                 }
428         }
429
430         return ret;
431 }
432
433 static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
434                 const struct sr_channel_group *cg)
435 {
436         struct dev_context *devc;
437         struct sr_channel *ch;
438         struct channel_spec *ch_spec;
439         GVariant *gvar;
440         GVariantBuilder gvb;
441         int ret, i;
442         const char *s[16];
443
444         /* Always available, even without sdi. */
445         if (key == SR_CONF_SCAN_OPTIONS) {
446                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
447                                 scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
448                 return SR_OK;
449         }
450
451         if (!sdi)
452                 return SR_ERR_ARG;
453         devc = sdi->priv;
454
455         ret = SR_OK;
456         if (!cg) {
457                 /* No channel group: global options. */
458                 switch (key) {
459                 case SR_CONF_DEVICE_OPTIONS:
460                         *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
461                                         devc->device->devopts, devc->device->num_devopts,
462                                         sizeof(int32_t));
463                         break;
464                 case SR_CONF_OUTPUT_CHANNEL_CONFIG:
465                         i = 0;
466                         if (devc->device->features & PPS_INDEPENDENT)
467                                 s[i++] = "Independent";
468                         if (devc->device->features & PPS_SERIES)
469                                 s[i++] = "Series";
470                         if (devc->device->features & PPS_PARALLEL)
471                                 s[i++] = "Parallel";
472                         if (i == 0) {
473                                 /*
474                                  * Shouldn't happen: independent-only devices
475                                  * shouldn't advertise this option at all.
476                                  */
477                                 return SR_ERR_NA;
478                         }
479                         *data = g_variant_new_strv(s, i);
480                         break;
481                 default:
482                         return SR_ERR_NA;
483                 }
484         } else {
485                 /* Channel group specified. */
486                 if (!sdi)
487                         return SR_ERR_ARG;
488                 /*
489                  * Per-channel-group options depending on a channel are actually
490                  * done with the first channel. Channel groups in PPS can have
491                  * more than one channel, but they will typically be of equal
492                  * specification for use in series or parallel mode. Drop requests
493                  * for groups with more than one channel just to make sure.
494                  */
495                 if (g_slist_length(cg->channels) > 1)
496                         return SR_ERR_NA;
497                 ch = cg->channels->data;
498
499                 switch (key) {
500                 case SR_CONF_DEVICE_OPTIONS:
501                         *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
502                                         devc->device->devopts_cg, devc->device->num_devopts_cg,
503                                         sizeof(int32_t));
504                         break;
505                 case SR_CONF_OUTPUT_VOLTAGE_MAX:
506                         ch_spec = &(devc->device->channels[ch->index]);
507                         g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
508                         /* Min, max, write resolution. */
509                         for (i = 0; i < 3; i++) {
510                                 gvar = g_variant_new_double(ch_spec->voltage[i]);
511                                 g_variant_builder_add_value(&gvb, gvar);
512                         }
513                         *data = g_variant_builder_end(&gvb);
514                         break;
515                 case SR_CONF_OUTPUT_CURRENT_MAX:
516                         g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
517                         /* Min, max, step. */
518                         for (i = 0; i < 3; i++) {
519                                 ch_spec = &(devc->device->channels[ch->index]);
520                                 gvar = g_variant_new_double(ch_spec->current[i]);
521                                 g_variant_builder_add_value(&gvb, gvar);
522                         }
523                         *data = g_variant_builder_end(&gvb);
524                         break;
525                 default:
526                         return SR_ERR_NA;
527                 }
528         }
529
530         return ret;
531 }
532
533 static int dev_acquisition_start(const struct sr_dev_inst *sdi,
534                 void *cb_data)
535 {
536         struct dev_context *devc;
537         struct sr_scpi_dev_inst *scpi;
538         struct sr_channel *ch;
539         int ret;
540
541         if (sdi->status != SR_ST_ACTIVE)
542                 return SR_ERR_DEV_CLOSED;
543
544         devc = sdi->priv;
545         scpi = sdi->conn;
546         devc->cb_data = cb_data;
547
548         if ((ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 100,
549                         scpi_pps_receive_data, (void *)sdi)) != SR_OK)
550                 return ret;
551         std_session_send_df_header(sdi, LOG_PREFIX);
552
553         /* Prime the pipe. */
554         devc->state = STATE_VOLTAGE;
555         ch = sdi->channels->data;
556         devc->cur_channel = ch;
557         scpi_cmd(sdi, SCPI_CMD_GET_MEAS_VOLTAGE, ch->name);
558
559         return SR_OK;
560 }
561
562 static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
563 {
564         struct dev_context *devc;
565         struct sr_scpi_dev_inst *scpi;
566         float f;
567
568         (void)cb_data;
569
570         if (sdi->status != SR_ST_ACTIVE)
571                 return SR_ERR_DEV_CLOSED;
572
573         devc = sdi->priv;
574         scpi = sdi->conn;
575
576         /*
577          * A requested value is certainly on the way. Retrieve it now,
578          * to avoid leaving the device in a state where it's not expecting
579          * commands.
580          */
581         sr_scpi_get_float(scpi, NULL, &f);
582         sr_scpi_source_remove(sdi->session, scpi);
583
584         /* Just in case something is queued up. */
585         devc->state = STATE_STOP;
586
587         return SR_OK;
588 }
589
590 SR_PRIV struct sr_dev_driver scpi_pps_driver_info = {
591         .name = "scpi-pps",
592         .longname = "SCPI PPS",
593         .api_version = 1,
594         .init = init,
595         .cleanup = cleanup,
596         .scan = scan,
597         .dev_list = dev_list,
598         .dev_clear = dev_clear,
599         .config_get = config_get,
600         .config_set = config_set,
601         .config_list = config_list,
602         .dev_open = dev_open,
603         .dev_close = dev_close,
604         .dev_acquisition_start = dev_acquisition_start,
605         .dev_acquisition_stop = dev_acquisition_stop,
606         .priv = NULL,
607 };