]> sigrok.org Git - libsigrok.git/blob - src/hardware/hp-3478a/api.c
resource.c: Fix firmware loading bug (#1140)
[libsigrok.git] / src / hardware / hp-3478a / api.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2017 Frank Stettner <frank-stettner@gmx.net>
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 "protocol.h"
23
24 static const uint32_t scanopts[] = {
25         SR_CONF_CONN,
26 };
27
28 static const uint32_t drvopts[] = {
29         SR_CONF_MULTIMETER,
30 };
31
32 static const uint32_t devopts[] = {
33         SR_CONF_CONTINUOUS,
34         SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
35         SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
36         SR_CONF_MEASURED_QUANTITY | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
37 };
38
39 static const struct {
40         enum sr_mq mq;
41         enum sr_mqflag mqflag;
42 } mqopts[] = {
43         {SR_MQ_VOLTAGE, SR_MQFLAG_DC},
44         {SR_MQ_VOLTAGE, SR_MQFLAG_DC | SR_MQFLAG_AUTORANGE},
45         {SR_MQ_VOLTAGE, SR_MQFLAG_AC | SR_MQFLAG_RMS},
46         {SR_MQ_VOLTAGE, SR_MQFLAG_AC | SR_MQFLAG_RMS | SR_MQFLAG_AUTORANGE},
47         {SR_MQ_CURRENT, SR_MQFLAG_DC},
48         {SR_MQ_CURRENT, SR_MQFLAG_DC | SR_MQFLAG_AUTORANGE},
49         {SR_MQ_CURRENT, SR_MQFLAG_AC | SR_MQFLAG_RMS},
50         {SR_MQ_CURRENT, SR_MQFLAG_AC | SR_MQFLAG_RMS | SR_MQFLAG_AUTORANGE},
51         {SR_MQ_RESISTANCE, 0},
52         {SR_MQ_RESISTANCE, 0 | SR_MQFLAG_AUTORANGE},
53         {SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE},
54         {SR_MQ_RESISTANCE, SR_MQFLAG_FOUR_WIRE | SR_MQFLAG_AUTORANGE},
55 };
56
57 SR_PRIV struct sr_dev_driver hp_3478a_driver_info;
58
59 static int create_front_channel(struct sr_dev_inst *sdi, int chan_idx)
60 {
61         struct sr_channel *channel;
62         struct channel_context *chanc;
63
64         chanc = g_malloc(sizeof(*chanc));
65         chanc->location = TERMINAL_FRONT;
66
67         channel = sr_channel_new(sdi, chan_idx++, SR_CHANNEL_ANALOG, TRUE, "P1");
68         channel->priv = chanc;
69
70         return chan_idx;
71 }
72
73 static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
74 {
75         int ret;
76         struct sr_dev_inst *sdi;
77         struct dev_context *devc;
78
79         sdi = g_malloc0(sizeof(struct sr_dev_inst));
80         sdi->vendor = g_strdup("Hewlett-Packard");
81         sdi->model = g_strdup("3478A");
82         sdi->conn = scpi;
83         sdi->driver = &hp_3478a_driver_info;
84         sdi->inst_type = SR_INST_SCPI;
85
86         devc = g_malloc0(sizeof(struct dev_context));
87         sr_sw_limits_init(&devc->limits);
88         sdi->priv = devc;
89
90         /* Get actual status (function, digits, ...). */
91         ret = hp_3478a_get_status_bytes(sdi);
92         if (ret != SR_OK)
93                 return NULL;
94
95         create_front_channel(sdi, 0);
96
97         return sdi;
98 }
99
100 static GSList *scan(struct sr_dev_driver *di, GSList *options)
101 {
102         return sr_scpi_scan(di->context, options, probe_device);
103 }
104
105 static int dev_open(struct sr_dev_inst *sdi)
106 {
107         return sr_scpi_open(sdi->conn);
108 }
109
110 static int dev_close(struct sr_dev_inst *sdi)
111 {
112         return sr_scpi_close(sdi->conn);
113 }
114
115 static int config_get(uint32_t key, GVariant **data,
116         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
117 {
118         struct dev_context *devc;
119         int ret;
120         GVariant *arr[2];
121
122         (void)cg;
123
124         devc = sdi->priv;
125
126         switch (key) {
127         case SR_CONF_LIMIT_SAMPLES:
128         case SR_CONF_LIMIT_MSEC:
129                 return sr_sw_limits_config_get(&devc->limits, key, data);
130         case SR_CONF_MEASURED_QUANTITY:
131                 ret = hp_3478a_get_status_bytes(sdi);
132                 if (ret != SR_OK)
133                         return ret;
134                 arr[0] = g_variant_new_uint32(devc->measurement_mq);
135                 arr[1] = g_variant_new_uint64(devc->measurement_mq_flags);
136                 *data = g_variant_new_tuple(arr, 2);
137                 break;
138         default:
139                 return SR_ERR_NA;
140         }
141
142         return SR_OK;
143 }
144
145 static int config_set(uint32_t key, GVariant *data,
146         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
147 {
148         struct dev_context *devc;
149         enum sr_mq mq;
150         enum sr_mqflag mq_flags;
151         GVariant *tuple_child;
152
153         (void)cg;
154
155         devc = sdi->priv;
156
157         switch (key) {
158         case SR_CONF_LIMIT_SAMPLES:
159         case SR_CONF_LIMIT_MSEC:
160                 return sr_sw_limits_config_set(&devc->limits, key, data);
161         case SR_CONF_MEASURED_QUANTITY:
162                 tuple_child = g_variant_get_child_value(data, 0);
163                 mq = g_variant_get_uint32(tuple_child);
164                 tuple_child = g_variant_get_child_value(data, 1);
165                 mq_flags = g_variant_get_uint64(tuple_child);
166                 g_variant_unref(tuple_child);
167                 return hp_3478a_set_mq(sdi, mq, mq_flags);
168         default:
169                 return SR_ERR_NA;
170         }
171
172         return SR_OK;
173 }
174
175 static int config_list(uint32_t key, GVariant **data,
176         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
177 {
178         unsigned int i;
179         GVariant *gvar, *arr[2];
180         GVariantBuilder gvb;
181
182         switch (key) {
183         case SR_CONF_SCAN_OPTIONS:
184         case SR_CONF_DEVICE_OPTIONS:
185                 return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
186         case SR_CONF_MEASURED_QUANTITY:
187                 /*
188                  * TODO: move to std.c as
189                  *       SR_PRIV GVariant *std_gvar_measured_quantities()
190                  */
191                 g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
192                 for (i = 0; i < ARRAY_SIZE(mqopts); i++) {
193                         arr[0] = g_variant_new_uint32(mqopts[i].mq);
194                         arr[1] = g_variant_new_uint64(mqopts[i].mqflag);
195                         gvar = g_variant_new_tuple(arr, 2);
196                         g_variant_builder_add_value(&gvb, gvar);
197                 }
198                 *data = g_variant_builder_end(&gvb);
199                 break;
200         default:
201                 return SR_ERR_NA;
202         }
203
204         return SR_OK;
205 }
206
207 static int dev_acquisition_start(const struct sr_dev_inst *sdi)
208 {
209         struct sr_scpi_dev_inst *scpi;
210         struct dev_context *devc;
211
212         scpi = sdi->conn;
213         devc = sdi->priv;
214
215         sr_sw_limits_acquisition_start(&devc->limits);
216         std_session_send_df_header(sdi);
217
218         /*
219          * NOTE: For faster readings, there are some things one can do:
220          *     - Turn off the display: sr_scpi_send(scpi, "D3SIGROK").
221          *     - Set the line frequency to 60Hz via switch (back of the unit).
222          *     - Set to 3.5 digits measurement (add config key SR_CONF_DIGITS).
223          */
224
225         /* Set to internal trigger. */
226         sr_scpi_send(scpi, "T1");
227         /* Get device status. */
228         hp_3478a_get_status_bytes(sdi);
229
230         return sr_scpi_source_add(sdi->session, scpi, G_IO_IN, 100,
231                         hp_3478a_receive_data, (void *)sdi);
232 }
233
234 static int dev_acquisition_stop(struct sr_dev_inst *sdi)
235 {
236         struct sr_scpi_dev_inst *scpi;
237
238         scpi = sdi->conn;
239
240         sr_scpi_source_remove(sdi->session, scpi);
241         std_session_send_df_end(sdi);
242
243         /* Set to internal trigger. */
244         sr_scpi_send(scpi, "T1");
245         /* Turn on display. */
246         sr_scpi_send(scpi, "D1");
247
248         return SR_OK;
249 }
250
251 SR_PRIV struct sr_dev_driver hp_3478a_driver_info = {
252         .name = "hp-3478a",
253         .longname = "HP 3478A",
254         .api_version = 1,
255         .init = std_init,
256         .cleanup = std_cleanup,
257         .scan = scan,
258         .dev_list = std_dev_list,
259         .dev_clear = std_dev_clear,
260         .config_get = config_get,
261         .config_set = config_set,
262         .config_list = config_list,
263         .dev_open = dev_open,
264         .dev_close = dev_close,
265         .dev_acquisition_start = dev_acquisition_start,
266         .dev_acquisition_stop = dev_acquisition_stop,
267         .context = NULL,
268 };
269
270 SR_REGISTER_DEV_DRIVER(hp_3478a_driver_info);