]> sigrok.org Git - libsigrok.git/blob - src/hardware/scpi-pps/api.c
scpi-pps: Simplify SCPI command handling.
[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         const GVariantType *gvtype;
175         unsigned int i;
176         int cmd, ret;
177         char *s;
178
179         if (!sdi)
180                 return SR_ERR_ARG;
181
182         devc = sdi->priv;
183         scpi = sdi->conn;
184
185         if (cg) {
186                 /*
187                  * These options only apply to channel groups with a single
188                  * channel -- they're per-channel settings for the device.
189                  */
190                 if (g_slist_length(cg->channels) > 1)
191                         return SR_ERR_NA;
192
193                 /*
194                  * Config keys are handled below depending on whether a channel
195                  * group was provided by the frontend. However some of these
196                  * take a CG on one PPS but not on others. Check the device's
197                  * profile for that here, and NULL out the channel group as needed.
198                  */
199                 for (i = 0; i < devc->device->num_devopts; i++) {
200                         if (devc->device->devopts[i] == key) {
201                                 cg = NULL;
202                                 break;
203                         }
204                 }
205
206                 ch = cg->channels->data;
207         }
208
209         gvtype = NULL;
210         cmd = -1;
211         switch (key) {
212         case SR_CONF_OUTPUT_ENABLED:
213                 gvtype = G_VARIANT_TYPE_BOOLEAN;
214                 cmd = SCPI_CMD_GET_OUTPUT_ENABLED;
215                 break;
216         case SR_CONF_OUTPUT_VOLTAGE:
217                 gvtype = G_VARIANT_TYPE_DOUBLE;
218                 cmd = SCPI_CMD_GET_MEAS_VOLTAGE;
219                 break;
220         case SR_CONF_OUTPUT_VOLTAGE_MAX:
221                 gvtype = G_VARIANT_TYPE_DOUBLE;
222                 cmd = SCPI_CMD_GET_VOLTAGE_MAX;
223                 break;
224         case SR_CONF_OUTPUT_CURRENT:
225                 gvtype = G_VARIANT_TYPE_DOUBLE;
226                 cmd = SCPI_CMD_GET_MEAS_CURRENT;
227                 break;
228         case SR_CONF_OUTPUT_CURRENT_MAX:
229                 gvtype = G_VARIANT_TYPE_DOUBLE;
230                 cmd = SCPI_CMD_GET_CURRENT_MAX;
231                 break;
232         case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
233                 gvtype = G_VARIANT_TYPE_BOOLEAN;
234                 cmd = SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ENABLED;
235                 break;
236         case SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE:
237                 gvtype = G_VARIANT_TYPE_BOOLEAN;
238                 cmd = SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_ACTIVE;
239                 break;
240         case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
241                 gvtype = G_VARIANT_TYPE_DOUBLE;
242                 cmd = SCPI_CMD_GET_OVER_VOLTAGE_PROTECTION_THRESHOLD;
243                 break;
244         case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
245                 gvtype = G_VARIANT_TYPE_BOOLEAN;
246                 cmd = SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ENABLED;
247                 break;
248         case SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE:
249                 gvtype = G_VARIANT_TYPE_BOOLEAN;
250                 cmd = SCPI_CMD_GET_OVER_CURRENT_PROTECTION_ACTIVE;
251                 break;
252         case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
253                 gvtype = G_VARIANT_TYPE_DOUBLE;
254                 cmd = SCPI_CMD_GET_OVER_CURRENT_PROTECTION_THRESHOLD;
255                 break;
256         case SR_CONF_OVER_TEMPERATURE_PROTECTION:
257                 gvtype = G_VARIANT_TYPE_BOOLEAN;
258                 cmd = SCPI_CMD_GET_OVER_TEMPERATURE_PROTECTION;
259                 break;
260         }
261         if (gvtype) {
262                 if (cg)
263                         ret = scpi_cmd_resp(sdi, data, gvtype, cmd, ch->name);
264                 else
265                         ret = scpi_cmd_resp(sdi, data, gvtype, cmd);
266         } else if (cg) {
267                 switch (key) {
268                 case SR_CONF_OUTPUT_REGULATION:
269                         ret = SR_ERR;
270                         if (scpi_cmd(sdi, SCPI_CMD_GET_OUTPUT_REGULATION, ch->name) == SR_OK) {
271                                 if (sr_scpi_get_string(scpi, NULL, &s) == SR_OK) {
272                                         if (strcmp(s, "CC") && strcmp(s, "CV") && strcmp(s, "UR")) {
273                                                 sr_dbg("Unknown response to SCPI_CMD_GET_OUTPUT_REGULATION: %s", s);
274                                         } else {
275                                                 *data = g_variant_new_string(s);
276                                                 g_free(s);
277                                                 ret = SR_OK;
278                                         }
279                                 }
280                         }
281                         break;
282                 default:
283                         ret = SR_ERR_NA;
284                 }
285         } else
286                 ret = SR_ERR_NA;
287
288         return ret;
289 }
290
291 static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
292                 const struct sr_channel_group *cg)
293 {
294         struct sr_channel *ch;
295         double d;
296         int ret;
297         const char *s;
298
299         if (sdi->status != SR_ST_ACTIVE)
300                 return SR_ERR_DEV_CLOSED;
301
302         ret = SR_OK;
303         if (!cg) {
304                 switch (key) {
305                 /* No channel group: global options. */
306                 case SR_CONF_OUTPUT_ENABLED:
307                         s = g_variant_get_boolean(data) ? "ON" : "OFF";
308                         ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_ENABLED, s);
309                         break;
310                 case SR_CONF_OUTPUT_VOLTAGE_MAX:
311                         d = g_variant_get_double(data);
312                         ret = scpi_cmd(sdi, SCPI_CMD_SET_VOLTAGE_MAX, d);
313                         break;
314                 case SR_CONF_OUTPUT_CURRENT_MAX:
315                         d = g_variant_get_double(data);
316                         ret = scpi_cmd(sdi, SCPI_CMD_SET_CURRENT_MAX, d);
317                         break;
318                 case SR_CONF_OVER_TEMPERATURE_PROTECTION:
319                         s = g_variant_get_boolean(data) ? "ON" : "OFF";
320                         ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_TEMPERATURE_PROTECTION, s);
321                         break;
322                 default:
323                         ret = SR_ERR_NA;
324                 }
325         } else {
326                 /* Channel group specified. */
327                 if (!sdi)
328                         return SR_ERR_ARG;
329                 if (g_slist_length(cg->channels) > 1)
330                         return SR_ERR_NA;
331                 ch = cg->channels->data;
332                 switch (key) {
333                 case SR_CONF_OUTPUT_ENABLED:
334                         s = g_variant_get_boolean(data) ? "ON" : "OFF";
335                         ret = scpi_cmd(sdi, SCPI_CMD_SET_OUTPUT_ENABLED, ch->name, s);
336                         break;
337                 case SR_CONF_OUTPUT_VOLTAGE_MAX:
338                         d = g_variant_get_double(data);
339                         ret = scpi_cmd(sdi, SCPI_CMD_SET_VOLTAGE_MAX, ch->name, d);
340                         break;
341                 case SR_CONF_OUTPUT_CURRENT_MAX:
342                         d = g_variant_get_double(data);
343                         ret = scpi_cmd(sdi, SCPI_CMD_SET_CURRENT_MAX, ch->name, d);
344                         break;
345                 case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
346                         s = g_variant_get_boolean(data) ? "ON" : "OFF";
347                         ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_ENABLED,
348                                         ch->name, s);
349                         break;
350                 case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
351                         d = g_variant_get_double(data);
352                         ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_VOLTAGE_PROTECTION_THRESHOLD,
353                                         ch->name, d);
354                         break;
355                 case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
356                         s = g_variant_get_boolean(data) ? "ON" : "OFF";
357                         ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_CURRENT_PROTECTION_ENABLED,
358                                         ch->name, s);
359                         break;
360                 case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
361                         d = g_variant_get_double(data);
362                         ret = scpi_cmd(sdi, SCPI_CMD_SET_OVER_CURRENT_PROTECTION_THRESHOLD,
363                                         ch->name, d);
364                         break;
365                 default:
366                         ret = SR_ERR_NA;
367                 }
368         }
369
370         return ret;
371 }
372
373 static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
374                 const struct sr_channel_group *cg)
375 {
376         struct dev_context *devc;
377         struct sr_channel *ch;
378         struct channel_spec *ch_spec;
379         GVariant *gvar;
380         GVariantBuilder gvb;
381         int ret, i;
382         const char *s[16];
383
384         /* Always available, even without sdi. */
385         if (key == SR_CONF_SCAN_OPTIONS) {
386                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
387                                 scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
388                 return SR_OK;
389         }
390
391         if (!sdi)
392                 return SR_ERR_ARG;
393         devc = sdi->priv;
394
395         ret = SR_OK;
396         if (!cg) {
397                 /* No channel group: global options. */
398                 switch (key) {
399                 case SR_CONF_DEVICE_OPTIONS:
400                         *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
401                                         devc->device->devopts, devc->device->num_devopts,
402                                         sizeof(int32_t));
403                         break;
404                 case SR_CONF_OUTPUT_CHANNEL_CONFIG:
405                         /* Not used. */
406                         i = 0;
407                         if (devc->device->features & PPS_INDEPENDENT)
408                                 s[i++] = "Independent";
409                         if (devc->device->features & PPS_SERIES)
410                                 s[i++] = "Series";
411                         if (devc->device->features & PPS_PARALLEL)
412                                 s[i++] = "Parallel";
413                         if (i == 0) {
414                                 /*
415                                  * Shouldn't happen: independent-only devices
416                                  * shouldn't advertise this option at all.
417                                  */
418                                 return SR_ERR_NA;
419                         }
420                         *data = g_variant_new_strv(s, i);
421                         break;
422                 default:
423                         return SR_ERR_NA;
424                 }
425         } else {
426                 /* Channel group specified. */
427                 if (!sdi)
428                         return SR_ERR_ARG;
429                 /*
430                  * Per-channel-group options depending on a channel are actually
431                  * done with the first channel. Channel groups in PPS can have
432                  * more than one channel, but they will typically be of equal
433                  * specification for use in series or parallel mode. Drop requests
434                  * for groups with more than one channel just to make sure.
435                  */
436                 if (g_slist_length(cg->channels) > 1)
437                         return SR_ERR_NA;
438                 ch = cg->channels->data;
439
440                 switch (key) {
441                 case SR_CONF_DEVICE_OPTIONS:
442                         *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
443                                         devc->device->devopts_cg, devc->device->num_devopts_cg,
444                                         sizeof(int32_t));
445                         break;
446                 case SR_CONF_OUTPUT_VOLTAGE_MAX:
447                         ch_spec = &(devc->device->channels[ch->index]);
448                         g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
449                         /* Min, max, write resolution. */
450                         for (i = 0; i < 3; i++) {
451                                 gvar = g_variant_new_double(ch_spec->voltage[i]);
452                                 g_variant_builder_add_value(&gvb, gvar);
453                         }
454                         *data = g_variant_builder_end(&gvb);
455                         break;
456                 case SR_CONF_OUTPUT_CURRENT_MAX:
457                         g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
458                         /* Min, max, step. */
459                         for (i = 0; i < 3; i++) {
460                                 ch_spec = &(devc->device->channels[ch->index]);
461                                 gvar = g_variant_new_double(ch_spec->current[i]);
462                                 g_variant_builder_add_value(&gvb, gvar);
463                         }
464                         *data = g_variant_builder_end(&gvb);
465                         break;
466                 default:
467                         return SR_ERR_NA;
468                 }
469         }
470
471         return ret;
472 }
473
474 static int dev_acquisition_start(const struct sr_dev_inst *sdi,
475                 void *cb_data)
476 {
477         struct dev_context *devc;
478         struct sr_scpi_dev_inst *scpi;
479         struct sr_channel *ch;
480         int ret;
481
482         if (sdi->status != SR_ST_ACTIVE)
483                 return SR_ERR_DEV_CLOSED;
484
485         devc = sdi->priv;
486         scpi = sdi->conn;
487         devc->cb_data = cb_data;
488
489         if ((ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 100,
490                         scpi_pps_receive_data, (void *)sdi)) != SR_OK)
491                 return ret;
492         std_session_send_df_header(sdi, LOG_PREFIX);
493
494         /* Prime the pipe. */
495         devc->state = STATE_VOLTAGE;
496         ch = sdi->channels->data;
497         devc->cur_channel = ch;
498         scpi_cmd(sdi, SCPI_CMD_GET_MEAS_VOLTAGE, ch->name);
499
500         return SR_OK;
501 }
502
503 static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
504 {
505         struct dev_context *devc;
506         struct sr_scpi_dev_inst *scpi;
507         float f;
508
509         (void)cb_data;
510
511         if (sdi->status != SR_ST_ACTIVE)
512                 return SR_ERR_DEV_CLOSED;
513
514         devc = sdi->priv;
515         scpi = sdi->conn;
516
517         /*
518          * A requested value is certainly on the way. Retrieve it now,
519          * to avoid leaving the device in a state where it's not expecting
520          * commands.
521          */
522         sr_scpi_get_float(scpi, NULL, &f);
523         sr_scpi_source_remove(sdi->session, scpi);
524
525         /* Just in case something is queued up. */
526         devc->state = STATE_STOP;
527
528         return SR_OK;
529 }
530
531 SR_PRIV struct sr_dev_driver scpi_pps_driver_info = {
532         .name = "scpi-pps",
533         .longname = "SCPI PPS",
534         .api_version = 1,
535         .init = init,
536         .cleanup = cleanup,
537         .scan = scan,
538         .dev_list = dev_list,
539         .dev_clear = dev_clear,
540         .config_get = config_get,
541         .config_set = config_set,
542         .config_list = config_list,
543         .dev_open = dev_open,
544         .dev_close = dev_close,
545         .dev_acquisition_start = dev_acquisition_start,
546         .dev_acquisition_stop = dev_acquisition_stop,
547         .priv = NULL,
548 };