]> sigrok.org Git - libsigrok.git/blob - src/hardware/hp-3457a/api.c
hp-3457a: Implement AC, ACDC, and four-wire resistance modes
[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         enum sr_mqflag mq_flags;
246         struct dev_context *devc;
247         GVariant *tuple_child;
248
249         (void)cg;
250
251         if (sdi->status != SR_ST_ACTIVE)
252                 return SR_ERR_DEV_CLOSED;
253
254         devc = sdi->priv;
255
256         ret = SR_OK;
257         switch (key) {
258         case SR_CONF_LIMIT_SAMPLES:
259                 devc->limit_samples = g_variant_get_uint64(data);
260                 break;
261         case SR_CONF_MEASURED_QUANTITY:
262                 tuple_child = g_variant_get_child_value(data, 0);
263                 mq = g_variant_get_uint32(tuple_child);
264                 tuple_child = g_variant_get_child_value(data, 1);
265                 mq_flags = g_variant_get_uint64(tuple_child);
266                 ret = hp_3457a_set_mq(sdi, mq, mq_flags);
267                 g_variant_unref(tuple_child);
268                 break;
269         case SR_CONF_ADC_POWERLINE_CYCLES:
270                 ret = hp_3457a_set_nplc(sdi, g_variant_get_double(data));
271                 break;
272         default:
273                 ret = SR_ERR_NA;
274         }
275
276         return ret;
277 }
278
279 static int config_list(uint32_t key, GVariant **data,
280         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
281 {
282         int ret;
283
284         if (key == SR_CONF_SCAN_OPTIONS) {
285                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
286                         scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
287                 return SR_OK;
288         } else if ((key == SR_CONF_DEVICE_OPTIONS) && !sdi) {
289                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
290                         drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
291                 return SR_OK;
292         } else if ((key == SR_CONF_DEVICE_OPTIONS) && !cg) {
293                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
294                         devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
295                 return SR_OK;
296         }
297
298         /* From here on, we're only concerned with channel group config. */
299         if (!cg)
300                 return SR_ERR_NA;
301
302         /*
303          * TODO: Implement channel group configuration when adding support for
304          * plug-in cards.
305          */
306
307         ret = SR_OK;
308         switch (key) {
309         default:
310                 ret = SR_ERR_NA;
311         }
312
313         return ret;
314 }
315
316 /*
317  * TRIG SGL
318  *   Trigger the first measurement, then hold. We can't let the instrument
319  *   auto-trigger because we read several registers to make a complete
320  *   reading. If the instrument were auto-triggering, we could get the
321  *   reading for sample N, but a new measurement is made and when we read the
322  *   HIRES register, it contains data for sample N+1. This would produce
323  *   wrong readings.
324  */
325 static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
326 {
327         int ret;
328         struct sr_scpi_dev_inst *scpi;
329         struct dev_context *devc;
330
331         (void)cb_data;
332
333         if (sdi->status != SR_ST_ACTIVE)
334                 return SR_ERR_DEV_CLOSED;
335
336         scpi = sdi->conn;
337         devc = sdi->priv;
338
339         ret = sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 100,
340                                  hp_3457a_receive_data, (void *)sdi);
341         if (ret != SR_OK)
342                 return ret;
343
344         std_session_send_df_header(sdi, LOG_PREFIX);
345
346         /* Start first measurement. */
347         sr_scpi_send(scpi, "TRIG SGL");
348         devc->acq_state = ACQ_TRIGGERED_MEASUREMENT;
349         devc->num_samples = 0;
350
351         return SR_OK;
352 }
353
354 static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
355 {
356         (void)cb_data;
357
358         if (sdi->status != SR_ST_ACTIVE)
359                 return SR_ERR_DEV_CLOSED;
360
361         return SR_OK;
362 }
363
364 SR_PRIV struct sr_dev_driver hp_3457a_driver_info = {
365         .name = "hp-3457a",
366         .longname = "HP 3457A",
367         .api_version = 1,
368         .init = init,
369         .cleanup = cleanup,
370         .scan = scan,
371         .dev_list = dev_list,
372         .dev_clear = dev_clear,
373         .config_get = config_get,
374         .config_set = config_set,
375         .config_list = config_list,
376         .dev_open = dev_open,
377         .dev_close = dev_close,
378         .dev_acquisition_start = dev_acquisition_start,
379         .dev_acquisition_stop = dev_acquisition_stop,
380         .context = NULL,
381 };