]> sigrok.org Git - libsigrok.git/blame - src/hardware/rigol-dg/protocol.c
uni-t-ut181a: silence compiler warning, use of uninitialized variable
[libsigrok.git] / src / hardware / rigol-dg / protocol.c
CommitLineData
068db0fb
TK
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2020 Timo Kokkonen <tjko@iki.fi>
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>
02feeb30
TK
21#include <string.h>
22#include "scpi.h"
068db0fb
TK
23#include "protocol.h"
24
02feeb30
TK
25SR_PRIV const char *rigol_dg_waveform_to_string(enum waveform_type type)
26{
27 switch (type) {
28 case WF_DC:
29 return "DC";
30 case WF_SINE:
31 return "Sine";
32 case WF_SQUARE:
33 return "Square";
34 case WF_RAMP:
35 return "Ramp";
36 case WF_PULSE:
37 return "Pulse";
38 case WF_NOISE:
39 return "Noise";
40 case WF_ARB:
41 return "Arb";
42 }
43
44 return "Unknown";
45}
46
47SR_PRIV const struct waveform_spec *rigol_dg_get_waveform_spec(
48 const struct channel_spec *ch, enum waveform_type wf)
49{
50 const struct waveform_spec *spec;
51 unsigned int i;
52
53 spec = NULL;
54 for (i = 0; i < ch->num_waveforms; i++) {
55 if (ch->waveforms[i].waveform == wf) {
56 spec = &ch->waveforms[i];
57 break;
58 }
59 }
60
61 return spec;
62}
63
64SR_PRIV int rigol_dg_get_channel_state(const struct sr_dev_inst *sdi,
65 const struct sr_channel_group *cg)
66{
67 struct dev_context *devc;
68 struct sr_scpi_dev_inst *scpi;
69 struct sr_channel *ch;
70 struct channel_status *ch_status;
71 const char *command;
72 GVariant *data;
73 gchar *response, **params;
74 const gchar *s;
75 enum waveform_type wf;
76 double freq, ampl, offset, phase;
77 int ret;
78
79 devc = sdi->priv;
80 scpi = sdi->conn;
81 data = NULL;
82 params = NULL;
83 response = NULL;
84 ret = SR_ERR_NA;
85
86 if (!sdi || !cg)
87 return SR_ERR_BUG;
88
89 ch = cg->channels->data;
90 ch_status = &devc->ch_status[ch->index];
91
92 command = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_GET_SOURCE);
93 if (command && *command) {
94 sr_scpi_get_opc(scpi);
95 ret = sr_scpi_cmd_resp(sdi, devc->cmdset,
96 PSG_CMD_SELECT_CHANNEL, cg->name, &data,
97 G_VARIANT_TYPE_STRING, PSG_CMD_GET_SOURCE, cg->name);
98 if (ret != SR_OK)
99 goto done;
100 response = g_variant_dup_string(data, NULL);
101 g_strstrip(response);
102 s = sr_scpi_unquote_string(response);
103 sr_spew("Channel state: '%s'", s);
104 params = g_strsplit(s, ",", 0);
105 if (!params[0])
106 goto done;
107
108 /* First parameter is the waveform type */
109 if (!(s = params[0]))
110 goto done;
111 if (g_ascii_strncasecmp(s, "SIN", strlen("SIN")) == 0)
112 wf = WF_SINE;
113 else if (g_ascii_strncasecmp(s, "SQU", strlen("SQU")) == 0)
114 wf = WF_SQUARE;
115 else if (g_ascii_strncasecmp(s, "RAMP", strlen("RAMP")) == 0)
116 wf = WF_RAMP;
117 else if (g_ascii_strncasecmp(s, "PULSE", strlen("PULSE")) == 0)
118 wf = WF_PULSE;
119 else if (g_ascii_strncasecmp(s, "NOISE", strlen("NOISE")) == 0)
120 wf = WF_NOISE;
121 else if (g_ascii_strncasecmp(s, "USER", strlen("USER")) == 0)
122 wf = WF_ARB;
123 else if (g_ascii_strncasecmp(s, "DC", strlen("DC")) == 0)
124 wf = WF_DC;
125 else
126 goto done;
127 ch_status->wf = wf;
128 ch_status->wf_spec = rigol_dg_get_waveform_spec(
129 &devc->device->channels[ch->index], wf);
130
131 /* Second parameter if the frequency (or "DEF" if not applicable) */
132 if (!(s = params[1]))
133 goto done;
134 freq = g_ascii_strtod(s, NULL);
135 ch_status->freq = freq;
136
137 /* Third parameter if the amplitude (or "DEF" if not applicable) */
138 if (!(s = params[2]))
139 goto done;
140 ampl = g_ascii_strtod(s, NULL);
141 ch_status->ampl = ampl;
142
143 /* Fourth parameter if the offset (or "DEF" if not applicable) */
144 if (!(s = params[3]))
145 goto done;
146 offset = g_ascii_strtod(s, NULL);
147 ch_status->offset = offset;
148
149 /* Fifth parameter if the phase (or "DEF" if not applicable) */
150 if (!(s = params[4]))
151 goto done;
152 phase = g_ascii_strtod(s, NULL);
153 ch_status->phase = phase;
154
155 ret = SR_OK;
156 }
157
158done:
159 g_variant_unref(data);
160 g_free(response);
161 g_strfreev(params);
162 return ret;
163}
164
165static void rigol_dg_send_channel_value(const struct sr_dev_inst *sdi,
166 struct sr_channel *ch, double value, enum sr_mq mq,
167 enum sr_unit unit, int digits)
168{
169 struct sr_datafeed_packet packet;
170 struct sr_datafeed_analog analog;
171 struct sr_analog_encoding encoding;
172 struct sr_analog_meaning meaning;
173 struct sr_analog_spec spec;
174 double val;
175
176 val = value;
177 sr_analog_init(&analog, &encoding, &meaning, &spec, digits);
178 analog.meaning->channels = g_slist_append(NULL, ch);
179 analog.num_samples = 1;
180 analog.data = &val;
181 analog.encoding->unitsize = sizeof(val);
182 analog.encoding->is_float = TRUE;
183 analog.encoding->digits = digits;
184 analog.meaning->mq = mq;
185 analog.meaning->unit = unit;
186
187 packet.type = SR_DF_ANALOG;
188 packet.payload = &analog;
189 sr_session_send(sdi, &packet);
190 g_slist_free(analog.meaning->channels);
191}
192
068db0fb
TK
193SR_PRIV int rigol_dg_receive_data(int fd, int revents, void *cb_data)
194{
02feeb30
TK
195 struct sr_dev_inst *sdi;
196 struct sr_scpi_dev_inst *scpi;
068db0fb 197 struct dev_context *devc;
02feeb30
TK
198 const char *cmd, *s;
199 char *response, **params;
200 double meas[5];
201 GSList *l;
202 int i, start_idx, ret;
068db0fb
TK
203
204 (void)fd;
02feeb30
TK
205 (void)revents;
206 response = NULL;
207 params = NULL;
068db0fb 208
02feeb30
TK
209 sdi = cb_data;
210 if (!sdi)
211 return TRUE;
212 scpi = sdi->conn;
213 devc = sdi->priv;
214 if (!scpi || !devc)
068db0fb
TK
215 return TRUE;
216
02feeb30
TK
217 cmd = sr_scpi_cmd_get(devc->cmdset, PSG_CMD_COUNTER_MEASURE);
218 if (!cmd || !*cmd)
068db0fb
TK
219 return TRUE;
220
02feeb30
TK
221 sr_scpi_get_opc(scpi);
222 ret = sr_scpi_get_string(scpi, cmd, &response);
223 if (ret != SR_OK) {
224 sr_info("Error getting measurement from counter: %d", ret);
225 sr_dev_acquisition_stop(sdi);
226 return TRUE;
227 }
228 g_strstrip(response);
229
230 /*
231 * Parse measurement string:
232 * frequency, period, duty cycle, width+, width-
233 */
234 params = g_strsplit(response, ",", 0);
235 for (i = 0; i < 5; i++) {
236 if (!(s = params[i]))
237 goto done;
238 meas[i] = g_ascii_strtod(s, NULL);
068db0fb 239 }
02feeb30
TK
240 sr_spew("%s: freq=%.10E, period=%.10E, duty=%.10E, width+=%.10E,"
241 "width-=%.10E", __func__,
242 meas[0], meas[1], meas[2], meas[3], meas[4]);
243
244 std_session_send_df_frame_begin(sdi);
245 start_idx = devc->device->num_channels;
246
247 /* Frequency */
248 l = g_slist_nth(sdi->channels, start_idx++);
249 rigol_dg_send_channel_value(sdi, l->data, meas[0], SR_MQ_FREQUENCY,
250 SR_UNIT_HERTZ, 10);
251
252 /* Period */
253 l = g_slist_nth(sdi->channels, start_idx++);
254 rigol_dg_send_channel_value(sdi, l->data, meas[1], SR_MQ_TIME,
255 SR_UNIT_SECOND, 10);
256
257 /* Duty Cycle */
258 l = g_slist_nth(sdi->channels, start_idx++);
259 rigol_dg_send_channel_value(sdi, l->data, meas[2], SR_MQ_DUTY_CYCLE,
260 SR_UNIT_PERCENTAGE, 3);
261
262 /* Pulse Width */
263 l = g_slist_nth(sdi->channels, start_idx++);
264 rigol_dg_send_channel_value(sdi, l->data, meas[3], SR_MQ_PULSE_WIDTH,
265 SR_UNIT_SECOND, 10);
266
267 std_session_send_df_frame_end(sdi);
268 sr_sw_limits_update_samples_read(&devc->limits, 1);
269
270 if (sr_sw_limits_check(&devc->limits))
271 sr_dev_acquisition_stop(sdi);
068db0fb 272
02feeb30
TK
273done:
274 g_free(response);
275 g_strfreev(params);
068db0fb
TK
276 return TRUE;
277}