]> sigrok.org Git - libsigrok.git/blob - src/hardware/hp-3457a/api.c
hp-3457a: Implement basic configuration and sampling
[libsigrok.git] / src / hardware / hp-3457a / api.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2016 Alexandru Gagniuc <mr.nuke.me@gmail.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 <config.h>
21 #include <scpi.h>
22 #include <string.h>
23 #include "protocol.h"
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 | SR_CONF_SET,
35         SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
36         SR_CONF_MEASURED_QUANTITY | SR_CONF_SET,
37         SR_CONF_ADC_POWERLINE_CYCLES | SR_CONF_SET | SR_CONF_GET,
38 };
39
40 SR_PRIV struct sr_dev_driver hp_3457a_driver_info;
41
42 static int create_front_channel(struct sr_dev_inst *sdi, int chan_idx)
43 {
44         struct sr_channel *channel;
45         struct sr_channel_group *front;
46
47         channel = sr_channel_new(sdi, chan_idx++, SR_CHANNEL_ANALOG,
48                                  TRUE, "Front");
49
50         front = g_malloc0(sizeof(*front));
51         front->name = g_strdup("Front");
52         front->channels = g_slist_append(front->channels, channel);
53         sdi->channel_groups = g_slist_append(sdi->channel_groups, front);
54
55         return chan_idx;
56 }
57
58 static int create_rear_channels(struct sr_dev_inst *sdi, int chan_idx,
59                                  const struct rear_card_info *card)
60 {
61         (void) sdi;
62
63         /* When card is NULL, we couldn't identify the type of card. */
64         if (!card)
65                 return chan_idx;
66
67         /* TODO: Create channel descriptor for plug-in cards here. */
68         return chan_idx;
69 }
70
71 static gchar *get_revision(struct sr_scpi_dev_inst *scpi)
72 {
73         int ret, major, minor;
74         GArray *rev_numbers;
75
76         /* Report a version of '0.0' if we can't parse the response. */
77         major = minor = 0;
78
79         ret = sr_scpi_get_floatv(scpi, "REV?", &rev_numbers);
80         if ((ret == SR_OK) && (rev_numbers->len >= 2)) {
81                 major = (int)g_array_index(rev_numbers, float, 0);
82                 minor = (int)g_array_index(rev_numbers, float, 1);
83         }
84
85         g_array_free(rev_numbers, TRUE);
86
87         return g_strdup_printf("%d.%d", major, minor);
88 }
89
90 static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
91 {
92         int ret, idx;
93         char *response;
94         struct sr_dev_inst *sdi;
95         struct dev_context *devc;
96
97         /*
98          * This command ensures we receive an EOI after every response, so that
99          * we don't wait the entire timeout after the response is received.
100          */
101         if (sr_scpi_send(scpi, "END ALWAYS") != SR_OK)
102                 return NULL;
103
104         ret = sr_scpi_get_string(scpi, "ID?", &response);
105         if ((ret != SR_OK) || !response)
106                 return NULL;
107
108         if (strcmp(response, "HP3457A"))
109                 return NULL;
110
111         g_free(response);
112
113         devc = g_malloc0(sizeof(struct dev_context));
114         sdi = g_malloc0(sizeof(struct sr_dev_inst));
115         sdi->vendor = g_strdup("Hewlett-Packard");
116         sdi->model = g_strdup("3457A");
117         sdi->version = get_revision(scpi);
118         sdi->conn = scpi;
119         sdi->driver = &hp_3457a_driver_info;
120         sdi->inst_type = SR_INST_SCPI;
121         sdi->priv = devc;
122
123         /* There is no way to probe the measurement mode. It must be set. */
124         devc->measurement_mq = 0;
125         devc->measurement_unit = 0;
126
127         /* Probe rear card option and create channels accordingly (TODO). */
128         devc->rear_card = hp_3457a_probe_rear_card(scpi);
129         idx = 0;
130         idx = create_front_channel(sdi, idx);
131         create_rear_channels(sdi, idx, devc->rear_card);
132
133         return sdi;
134 }
135
136 static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx)
137 {
138         return std_init(sr_ctx, di, LOG_PREFIX);
139 }
140
141 static GSList *scan(struct sr_dev_driver *di, GSList *options)
142 {
143         return sr_scpi_scan(di->context, options, probe_device);
144 }
145
146 static GSList *dev_list(const struct sr_dev_driver *di)
147 {
148         return ((struct drv_context *)(di->context))->instances;
149 }
150
151 static int dev_clear(const struct sr_dev_driver *di)
152 {
153         return std_dev_clear(di, NULL);
154 }
155
156 /*
157  * We need to set the HP 3457A to a known state, and there are quite a number
158  * of knobs to tweak. Here's a brief explanation of what's going on. For more
159  * details, print out and consult the user manual.
160  *   PRESET
161  *     Set the instrument to a pre-determined state. This is easier and faster
162  *     than sending a few dozen commands. Some of the PRESET defaults include
163  *     ASCII output format, and synchronous triggering. See user manual for
164  *     more details.
165  *
166  * After the PRESET command, the instrument is in a known state, and only those
167  * parameters for which the default is unsuitable are modified:
168  *   INBUF ON
169  *     Enable the HP-IB input buffer. This allows the instrument to release the
170  *     HP-IB bus before processing the command, and increases throughput on
171  *     GPIB buses with more than one device.
172  *   TRIG HOLD
173  *     Do not trigger new measurements until instructed to do so.
174  */
175 static int dev_open(struct sr_dev_inst *sdi)
176 {
177         struct sr_scpi_dev_inst *scpi = sdi->conn;
178         struct dev_context *devc;
179
180         if (sr_scpi_open(scpi) != SR_OK)
181                 return SR_ERR;
182
183         devc=sdi->priv;
184
185         sr_scpi_send(scpi, "PRESET");
186         sr_scpi_send(scpi, "INBUF ON");
187         sr_scpi_send(scpi, "TRIG HOLD");
188         sr_scpi_get_float(scpi, "NPLC?", &devc->nplc);
189
190         sdi->status = SR_ST_ACTIVE;
191
192         return SR_OK;
193 }
194
195 static int dev_close(struct sr_dev_inst *sdi)
196 {
197         struct sr_scpi_dev_inst *scpi = sdi->conn;
198
199         if (sdi->status != SR_ST_ACTIVE)
200                 return SR_ERR_DEV_CLOSED;
201
202         /* Switch back to auto-triggering. */
203         sr_scpi_send(scpi, "TRIG AUTO");
204
205         sr_scpi_close(scpi);
206
207         sdi->status = SR_ST_INACTIVE;
208
209         return SR_OK;
210 }
211
212 static int cleanup(const struct sr_dev_driver *di)
213 {
214         return dev_clear(di);
215 }
216
217 static int config_get(uint32_t key, GVariant **data,
218         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
219 {
220         int ret;
221         struct dev_context *devc;
222
223         (void)cg;
224
225         devc = sdi->priv;
226
227         ret = SR_OK;
228         switch (key) {
229         case SR_CONF_ADC_POWERLINE_CYCLES:
230                 *data = g_variant_new_double(devc->nplc);
231                 break;
232         default:
233                 return SR_ERR_NA;
234         }
235
236         return ret;
237 }
238
239 static int config_set(uint32_t key, GVariant *data,
240                       const struct sr_dev_inst *sdi,
241                       const struct sr_channel_group *cg)
242 {
243         int ret;
244         enum sr_mq mq;
245         struct dev_context *devc;
246         GVariant *tuple_child;
247
248         (void)cg;
249
250         if (sdi->status != SR_ST_ACTIVE)
251                 return SR_ERR_DEV_CLOSED;
252
253         devc = sdi->priv;
254
255         ret = SR_OK;
256         switch (key) {
257         case SR_CONF_LIMIT_SAMPLES:
258                 devc->limit_samples = g_variant_get_uint64(data);
259                 break;
260         case SR_CONF_MEASURED_QUANTITY:
261                 tuple_child = g_variant_get_child_value(data, 0);
262                 mq = g_variant_get_uint32(tuple_child);
263                 ret = hp_3457a_set_mq(sdi, mq);
264                 g_variant_unref(tuple_child);
265                 break;
266         case SR_CONF_ADC_POWERLINE_CYCLES:
267                 ret = hp_3457a_set_nplc(sdi, g_variant_get_double(data));
268                 break;
269         default:
270                 ret = SR_ERR_NA;
271         }
272
273         return ret;
274 }
275
276 static int config_list(uint32_t key, GVariant **data,
277         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
278 {
279         int ret;
280
281         if (key == SR_CONF_SCAN_OPTIONS) {
282                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
283                         scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
284                 return SR_OK;
285         } else if ((key == SR_CONF_DEVICE_OPTIONS) && !sdi) {
286                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
287                         drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
288                 return SR_OK;
289         } else if ((key == SR_CONF_DEVICE_OPTIONS) && !cg) {
290                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
291                         devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
292                 return SR_OK;
293         }
294
295         /* From here on, we're only concerned with channel group config. */
296         if (!cg)
297                 return SR_ERR_NA;
298
299         /*
300          * TODO: Implement channel group configuration when adding support for
301          * plug-in cards.
302          */
303
304         ret = SR_OK;
305         switch (key) {
306         default:
307                 ret = SR_ERR_NA;
308         }
309
310         return ret;
311 }
312
313 /*
314  * TRIG SGL
315  *   Trigger the first measurement, then hold. We can't let the instrument
316  *   auto-trigger because we read several registers to make a complete
317  *   reading. If the instrument were auto-triggering, we could get the
318  *   reading for sample N, but a new measurement is made and when we read the
319  *   HIRES register, it contains data for sample N+1. This would produce
320  *   wrong readings.
321  */
322 static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
323 {
324         int ret;
325         struct sr_scpi_dev_inst *scpi;
326         struct dev_context *devc;
327
328         (void)cb_data;
329
330         if (sdi->status != SR_ST_ACTIVE)
331                 return SR_ERR_DEV_CLOSED;
332
333         scpi = sdi->conn;
334         devc = sdi->priv;
335
336         ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 100,
337                                  hp_3457a_receive_data, (void *)sdi);
338         if (ret != SR_OK)
339                 return ret;
340
341         std_session_send_df_header(sdi, LOG_PREFIX);
342
343         /* Start first measurement. */
344         sr_scpi_send(scpi, "TRIG SGL");
345         devc->acq_state = ACQ_TRIGGERED_MEASUREMENT;
346         devc->num_samples = 0;
347
348         return SR_OK;
349 }
350
351 static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
352 {
353         (void)cb_data;
354
355         if (sdi->status != SR_ST_ACTIVE)
356                 return SR_ERR_DEV_CLOSED;
357
358         return SR_OK;
359 }
360
361 SR_PRIV struct sr_dev_driver hp_3457a_driver_info = {
362         .name = "hp-3457a",
363         .longname = "HP 3457A",
364         .api_version = 1,
365         .init = init,
366         .cleanup = cleanup,
367         .scan = scan,
368         .dev_list = dev_list,
369         .dev_clear = dev_clear,
370         .config_get = config_get,
371         .config_set = config_set,
372         .config_list = config_list,
373         .dev_open = dev_open,
374         .dev_close = dev_close,
375         .dev_acquisition_start = dev_acquisition_start,
376         .dev_acquisition_stop = dev_acquisition_stop,
377         .context = NULL,
378 };