]>
Commit | Line | Data |
---|---|---|
b1fa9aac GS |
1 | /* |
2 | * This file is part of the libsigrok project. | |
3 | * | |
4 | * Copyright (C) 2023 Gerhard Sittig <gerhard.sittig@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 | ||
18baeeed GS |
20 | /* |
21 | * Juntek JDS6600 is a DDS signal generator. | |
22 | * Often rebranded, goes by different names, among them Joy-IT JDS6600. | |
23 | * | |
24 | * This driver was built using Kristoff Bonne's knowledge as seen in his | |
25 | * MIT licensed Python code for JDS6600 control. For details see the | |
26 | * https://github.com/on1arf/jds6600_python repository. | |
27 | * | |
28 | * Supported features: | |
29 | * - Model detection, which determines the upper output frequency limit | |
30 | * (15..60MHz models exist). | |
31 | * - Assumes exactly two channels. Other models were not seen out there. | |
32 | * - Per channel configuration of: Waveform, output frequency, amplitude, | |
33 | * offset, duty cycle. | |
34 | * - Phase between channels is a global property and affects multiple | |
35 | * channels at the same time (their relation to each other). | |
36 | * | |
37 | * TODO | |
38 | * - Add support for the frequency measurement and/or the counter. This | |
39 | * feature's availability may depend on or interact with the state of | |
40 | * other generator channels. Needs consideration of constraints. | |
1711287e GS |
41 | * - Add support for "modes" (sweep, pulse, burst; modulation if the |
42 | * device supports it). | |
18baeeed GS |
43 | * - Add support for download/upload of arbitrary waveforms. This needs |
44 | * infrastructure in common libsigrok code as well as in applications. | |
45 | * At the moment "blob transfer" (waveform upload/download) appears to | |
46 | * not be supported. | |
47 | * - Re-consider parameter value ranges. Frequency depends on the model. | |
1711287e GS |
48 | * Amplitude depends on the model and frequencies. Can be -20..+20, |
49 | * or -10..+10, or -5..+5. Could be affected by offsets and further | |
50 | * get clipped. This implementation caps application's input to the | |
51 | * -20..+20 range, and sends the set request to the device. If any | |
52 | * further transformation happens in the device then applications | |
53 | * need to read back, this library driver doesn't. | |
18baeeed GS |
54 | * |
55 | * Implementation details: | |
916cea58 GS |
56 | * - Communicates via USB CDC at 115200/8n1 (virtual COM port). The user |
57 | * perceives a USB attached device (full speed, CDC/ACM class). The | |
58 | * implementation needs to remember that a WCH CH340G forwards data | |
59 | * to a microcontroller. Maximum throughput is in the 10KiB/s range. | |
18baeeed GS |
60 | * - Requests are in text format. Start with a ':' colon, followed by a |
61 | * single letter instruction opcode, followed by a number which either | |
62 | * addresses a parameter (think hardware register) or storage slot for | |
63 | * an arbitrary waveform. Can be followed by an '=' equals sign and a | |
64 | * value. Multiple values are comma separated. The line may end in a | |
65 | * '.' period. Several end-of-line conventions are supported by the | |
66 | * devices' firmware versions, LF and CR/LF are reported to work. | |
67 | * - Responses also are in text format. Start with a ':' colon, followed | |
68 | * by an instruction letter, followed by a number (a parameter index, | |
69 | * or a waveform index), followed by '=' equal sign and one or more | |
70 | * values. Optionally ending in a '.' period. And ending in the | |
1711287e GS |
71 | * firmware's end-of-line. Read responses will have this format. |
72 | * Responses to write requests might just have the ":ok." literal. | |
18baeeed | 73 | * - There are four instructions: 'r' to read and 'w' to write parameters |
1711287e GS |
74 | * (think "hardware registers", optionaly multi-valued), 'a' to write |
75 | * and 'b' to read arbitrary waveform data (sequence of sample values). | |
18baeeed GS |
76 | * - Am not aware of a vendor's documentation for the protocol. Joy-IT |
77 | * provides the JT-JDS6600-Communication-protocol.pdf document which | |
78 | * leaves a lot of questions. This sigrok driver implementation used | |
79 | * a lot of https://github.com/on1arf/jds6600_python knowledge for | |
80 | * the initial version (MIT licenced Python code by Kristoff Bonne). | |
81 | * - The requests take effect when sent from application code. While | |
82 | * the requests remain uneffective when typed in interactive terminal | |
83 | * sessions. Though there are ":ok" responses, the action would not | |
84 | * happen in the device. It's assumed to be a firmware implementation | |
85 | * constraint that is essential to keep in mind. | |
86 | * - The right hand side of write requests or read responses can carry | |
87 | * any number of values, both numbers and text, integers and floats. | |
88 | * Still some of the parameters (voltages, times, frequencies) come in | |
89 | * interesting formats. A floating point "mantissa" and an integer code | |
90 | * for scaling the value. Not an exponent, but some kind of index. In | |
91 | * addition to an open coded "fixed point" style multiplier that is | |
92 | * implied and essential, but doesn't show on the wire. Interpretation | |
93 | * of responses and phrasing of values in requests is arbitrary, this | |
94 | * "black magic" was found by local experimentation (reading back the | |
95 | * values which were configured by local UI interaction). | |
1711287e GS |
96 | * - Communication is more reliable when the host unconditionally sends |
97 | * "function codes" (register and waveform indices) in two-digit form. | |
98 | * Device firmware might implement rather specific assumptions. | |
99 | * - Semantics of the right hand side in :rNN= and :bNN= read requests | |
100 | * is uncertain. Just passing 0 in all situations worked in a local | |
101 | * setup. As did omitting the value during interactive exploration. | |
102 | * | |
103 | * Example requests and responses. | |
104 | * - Get model identification (max output frequency) | |
105 | * TX text: --> :r00=0. | |
106 | * TX bytes: --> 3a 72 30 30 3d 30 2e 0d 0a | |
107 | * RX bytes: <-- 3a 72 30 30 3d 36 30 2e 0d 0a | |
108 | * RX text: <-- :r00=60. | |
109 | * - Get all channels' enabled state | |
110 | * TX text: --> :r20=0. | |
111 | * TX bytes: --> 3a 72 32 30 3d 30 2e 0d 0a | |
112 | * RX bytes: <-- 3a 72 32 30 3d 31 2c 31 2e 0d 0a | |
113 | * RX text: <-- :r20=1,1. | |
114 | * - Get first channel's waveform selection | |
115 | * TX text: --> :r21=0. | |
116 | * TX bytes: --> 3a 72 32 31 3d 30 2e 0d 0a | |
117 | * RX bytes: <-- 3a 72 32 31 3d 31 30 33 2e 0d 0a | |
118 | * RX text: <-- :r21=103. | |
119 | * - Set second channel's output frequency | |
120 | * TX text: --> :w24=1234500,0. | |
121 | * TX bytes: --> 3a 77 32 34 3d 31 32 33 34 35 30 30 2c 30 2e 0d 0a | |
122 | * RX bytes: <-- 3a 6f 6b 0d 0a | |
123 | * RX text: <-- :ok | |
124 | * - Read arbitrary waveform number 13 | |
125 | * TX text: --> :b13=0. | |
126 | * TX bytes: --> 3a 62 31 33 3d 30 2e 0d 0a | |
127 | * RX bytes: <-- 3a 62 31 33 3d 34 30 39 35 2c 34 30 39 35 2c ... 2c 34 30 39 35 2c 34 30 39 35 2c 0d 0a | |
128 | * RX text: <-- :b13=4095,4095,...,4095,4095, | |
18baeeed GS |
129 | */ |
130 | ||
131 | #include "config.h" | |
132 | ||
133 | #include <glib.h> | |
134 | #include <math.h> | |
135 | #include <string.h> | |
136 | ||
b1fa9aac GS |
137 | #include "protocol.h" |
138 | ||
1711287e | 139 | #define WITH_SERIAL_RAW_DUMP 0 /* Includes EOL and non-printables. */ |
18baeeed GS |
140 | #define WITH_ARBWAVE_DOWNLOAD 0 /* Development HACK */ |
141 | ||
142 | /* | |
143 | * The firmware's maximum response length. Seen when an arbitrary | |
144 | * waveform gets retrieved. Carries 2048 samples in the 0..4095 range. | |
145 | * Plus some decoration around that data. | |
146 | * :b01=4095,4095,...,4095,<CRLF> | |
147 | */ | |
148 | #define MAX_RSP_LENGTH (8 + 2048 * 5) | |
149 | ||
916cea58 GS |
150 | /* |
151 | * Times are in milliseconds. | |
152 | * - Delay after transmission was an option during initial development. | |
153 | * Has become obsolete. Support remains because it doesn't harm. | |
154 | * - Delay after flash is essential when writing multiple waveforms to | |
155 | * the device. Not letting more idle time pass after successful write | |
156 | * and reception of the "ok" response, and before the next write, will | |
157 | * result in corrupted waveform storage in the device. The next wave | |
158 | * that is written waveform will start with several hundred samples | |
159 | * of all-one bits. | |
160 | * - Timeout per receive attempt at the physical layer can be short. | |
161 | * Experience suggests that 2ms are a good value. Reception ends when | |
162 | * the response termination was seen. Or when no receive data became | |
163 | * available within that per-attemt timeout, and no higher level total | |
164 | * timeout was specified. Allow some slack for USB FS frame intervals. | |
165 | * - Timeout for identify attempts at the logical level can be short. | |
166 | * Captures of the microcontroller communication suggest that firmware | |
167 | * responds immediately (within 2ms). So 10ms per identify attempt | |
168 | * are plenty for successful communication, yet quick enough to not | |
169 | * stall on missing peripherals. | |
170 | * - Timeout for waveform upload/download needs to be huge. Textual | |
171 | * presentation of 2k samples with 12 significant bits (0..4095 range) | |
172 | * combined with 115200bps UART communication result in a 1s maximum | |
173 | * transfer time per waveform. So 1.2s is a good value. | |
174 | */ | |
175 | #define DELAY_AFTER_SEND 0 | |
18baeeed | 176 | #define DELAY_AFTER_FLASH 100 |
916cea58 GS |
177 | #define TIMEOUT_READ_CHUNK 2 |
178 | #define TIMEOUT_IDENTIFY 10 | |
179 | #define TIMEOUT_WAVEFORM 1200 | |
18baeeed GS |
180 | |
181 | /* Instruction codes. Read/write parameters/waveforms. */ | |
182 | #define INSN_WRITE_PARA 'w' | |
183 | #define INSN_READ_PARA 'r' | |
184 | #define INSN_WRITE_WAVE 'a' | |
185 | #define INSN_READ_WAVE 'b' | |
186 | ||
187 | /* Indices for "register access". */ | |
188 | enum param_index { | |
189 | IDX_DEVICE_TYPE = 0, | |
190 | IDX_SERIAL_NUMBER = 1, | |
191 | IDX_CHANNELS_ENABLE = 20, | |
192 | IDX_WAVEFORM_CH1 = 21, | |
193 | IDX_WAVEFORM_CH2 = 22, | |
194 | IDX_FREQUENCY_CH1 = 23, | |
195 | IDX_FREQUENCY_CH2 = 24, | |
196 | IDX_AMPLITUDE_CH1 = 25, | |
197 | IDX_AMPLITUDE_CH2 = 26, | |
198 | IDX_OFFSET_CH1 = 27, | |
199 | IDX_OFFSET_CH2 = 28, | |
200 | IDX_DUTYCYCLE_CH1 = 29, | |
201 | IDX_DUTYCYCLE_CH2 = 30, | |
202 | IDX_PHASE_CHANNELS = 31, | |
203 | IDX_ACTION = 32, | |
204 | IDX_MODE = 33, | |
205 | IDX_INPUT_COUPLING = 36, | |
206 | IDX_MEASURE_GATE = 37, | |
207 | IDX_MEASURE_MODE = 38, | |
208 | IDX_COUNTER_RESET = 39, | |
209 | IDX_SWEEP_STARTFREQ = 40, | |
210 | IDX_SWEEP_ENDFREQ = 41, | |
211 | IDX_SWEEP_TIME = 42, | |
212 | IDX_SWEEP_DIRECTION = 43, | |
213 | IDX_SWEEP_MODE = 44, | |
214 | IDX_PULSE_WIDTH = 45, | |
215 | IDX_PULSE_PERIOD = 46, | |
216 | IDX_PULSE_OFFSET = 47, | |
217 | IDX_PULSE_AMPLITUDE = 48, | |
218 | IDX_BURST_COUNT = 49, | |
219 | IDX_BURST_MODE = 50, | |
220 | IDX_SYSTEM_SOUND = 51, | |
221 | IDX_SYSTEM_BRIGHTNESS = 52, | |
222 | IDX_SYSTEM_LANGUAGE = 53, | |
223 | IDX_SYSTEM_SYNC = 54, /* "Tracking" channels? */ | |
224 | IDX_SYSTEM_ARBMAX = 55, | |
225 | IDX_PROFILE_SAVE = 70, | |
226 | IDX_PROFILE_LOAD = 71, | |
227 | IDX_PROFILE_CLEAR = 72, | |
228 | IDX_COUNTER_VALUE = 80, | |
229 | IDX_MEAS_VALUE_FREQLOW = 81, | |
230 | IDX_MEAS_VALUE_FREQHI = 82, | |
231 | IDX_MEAS_VALUE_WIDTHHI = 83, | |
232 | IDX_MEAS_VALUE_WIDTHLOW = 84, | |
233 | IDX_MEAS_VALUE_PERIOD = 85, | |
234 | IDX_MEAS_VALUE_DUTYCYCLE = 86, | |
235 | IDX_MEAS_VALUE_U1 = 87, | |
236 | IDX_MEAS_VALUE_U2 = 88, | |
237 | IDX_MEAS_VALUE_U3 = 89, | |
238 | }; | |
239 | ||
240 | /* Firmware's codes for waveform selection. */ | |
241 | enum waveform_index_t { | |
242 | /* 17 pre-defined waveforms. */ | |
243 | WAVE_SINE = 0, | |
244 | WAVE_SQUARE = 1, | |
245 | WAVE_PULSE = 2, | |
246 | WAVE_TRIANGLE = 3, | |
247 | WAVE_PARTIAL_SINE = 4, | |
248 | WAVE_CMOS = 5, | |
249 | WAVE_DC = 6, | |
250 | WAVE_HALF_WAVE = 7, | |
251 | WAVE_FULL_WAVE = 8, | |
252 | WAVE_POS_LADDER = 9, | |
253 | WAVE_NEG_LADDER = 10, | |
254 | WAVE_NOISE = 11, | |
255 | WAVE_EXP_RISE = 12, | |
256 | WAVE_EXP_DECAY = 13, | |
257 | WAVE_MULTI_TONE = 14, | |
258 | WAVE_SINC = 15, | |
259 | WAVE_LORENZ = 16, | |
260 | WAVES_COUNT_BUILTIN, | |
261 | /* Up to 60 arbitrary waveforms. */ | |
262 | WAVES_ARB_BASE = 100, | |
263 | WAVE_ARB01 = WAVES_ARB_BASE + 1, | |
264 | /* ... */ | |
265 | WAVE_ARB60 = WAVES_ARB_BASE + 60, | |
266 | WAVES_PAST_LAST_ARB, | |
267 | }; | |
268 | #define WAVES_COUNT_ARBITRARY (WAVES_PAST_LAST_ARB - WAVE_ARB01) | |
269 | ||
270 | static const char *waveform_names[] = { | |
271 | [WAVE_SINE] = "sine", | |
272 | [WAVE_SQUARE] = "square", | |
273 | [WAVE_PULSE] = "pulse", | |
274 | [WAVE_TRIANGLE] = "triangle", | |
275 | [WAVE_PARTIAL_SINE] = "partial-sine", | |
276 | [WAVE_CMOS] = "cmos", | |
277 | [WAVE_DC] = "dc", | |
278 | [WAVE_HALF_WAVE] = "half-wave", | |
279 | [WAVE_FULL_WAVE] = "full-wave", | |
280 | [WAVE_POS_LADDER] = "pos-ladder", | |
281 | [WAVE_NEG_LADDER] = "neg-ladder", | |
282 | [WAVE_NOISE] = "noise", | |
283 | [WAVE_EXP_RISE] = "exp-rise", | |
284 | [WAVE_EXP_DECAY] = "exp-decay", | |
285 | [WAVE_MULTI_TONE] = "multi-tone", | |
286 | [WAVE_SINC] = "sinc", | |
287 | [WAVE_LORENZ] = "lorenz", | |
288 | }; | |
289 | #define WAVEFORM_ARB_NAME_FMT "arb-%02zu" | |
290 | ||
1711287e GS |
291 | static void log_raw_bytes(const char *caption, GString *buff) |
292 | { | |
293 | GString *text; | |
294 | ||
295 | if (!WITH_SERIAL_RAW_DUMP) | |
296 | return; | |
297 | if (sr_log_loglevel_get() < SR_LOG_SPEW) | |
298 | return; | |
299 | ||
300 | if (!caption) | |
301 | caption = ""; | |
302 | text = sr_hexdump_new((const uint8_t *)buff->str, buff->len); | |
303 | sr_spew("%s%s", caption, text->str); | |
304 | sr_hexdump_free(text); | |
305 | } | |
306 | ||
18baeeed GS |
307 | /* |
308 | * Writes a text line to the serial port. Normalizes end-of-line | |
309 | * including trailing period. | |
1711287e GS |
310 | * |
311 | * Accepts: | |
312 | * ":r01=0.<CR><LF>" | |
313 | * ":r01=0." | |
314 | * ":r01=0<LF>" | |
315 | * ":r01=0" | |
316 | * Normalizes to: | |
317 | * ":r01=0.<CR><LF>" | |
18baeeed GS |
318 | */ |
319 | static int serial_send_textline(const struct sr_dev_inst *sdi, | |
320 | GString *s, unsigned int delay_ms) | |
321 | { | |
322 | struct sr_serial_dev_inst *conn; | |
323 | const char *rdptr; | |
324 | size_t padlen, rdlen, wrlen; | |
325 | int ret; | |
326 | ||
327 | if (!sdi) | |
328 | return SR_ERR_ARG; | |
329 | conn = sdi->conn; | |
330 | if (!conn) | |
331 | return SR_ERR_ARG; | |
332 | if (!s) | |
333 | return SR_ERR_ARG; | |
334 | ||
1711287e GS |
335 | /* |
336 | * Trim surrounding whitespace. Normalize to canonical format. | |
337 | * Make sure there is enough room for the period and CR/LF | |
338 | * (and NUL termination). Use a glib API that's easy to adjust | |
339 | * the padded length of. Performance is not a priority here. | |
340 | */ | |
18baeeed GS |
341 | padlen = 4; |
342 | while (padlen--) | |
343 | g_string_append_c(s, '\0'); | |
344 | rdptr = sr_text_trim_spaces(s->str); | |
345 | rdlen = strlen(rdptr); | |
346 | if (rdlen && rdptr[rdlen - 1] == '.') | |
347 | rdlen--; | |
348 | g_string_set_size(s, rdlen); | |
349 | g_string_append_c(s, '.'); | |
1711287e | 350 | sr_spew("serial TX text: --> %s", rdptr); |
18baeeed GS |
351 | g_string_append_c(s, '\r'); |
352 | g_string_append_c(s, '\n'); | |
353 | rdlen = strlen(rdptr); | |
1711287e | 354 | log_raw_bytes("serial TX bytes: --> ", s); |
18baeeed GS |
355 | |
356 | /* Handle chunked writes, check for transmission errors. */ | |
357 | while (rdlen) { | |
358 | ret = serial_write_blocking(conn, rdptr, rdlen, 0); | |
359 | if (ret < 0) | |
360 | return SR_ERR_IO; | |
361 | wrlen = (size_t)ret; | |
362 | if (wrlen > rdlen) | |
363 | wrlen = rdlen; | |
364 | rdptr += wrlen; | |
365 | rdlen -= wrlen; | |
366 | } | |
367 | ||
368 | if (delay_ms) | |
369 | g_usleep(delay_ms * 1000); | |
370 | ||
371 | return SR_OK; | |
372 | } | |
373 | ||
374 | /* | |
375 | * Reads a text line from the serial port. Assumes that only a single | |
376 | * response text line is in flight (does not handle the case of more | |
377 | * receive data following after the first EOL). Transparently deals | |
378 | * with trailing period and end-of-line, so callers need not bother. | |
379 | * | |
380 | * Checks plausibility when the caller specifies conditions to check. | |
381 | * Optionally returns references (and lengths) to the response's RHS. | |
382 | * That's fine because data resides in a caller provided buffer. | |
383 | */ | |
384 | static int serial_recv_textline(const struct sr_dev_inst *sdi, | |
385 | GString *s, unsigned int delay_ms, unsigned int timeout_ms, | |
386 | gboolean *is_ok, char wants_insn, size_t wants_index, | |
387 | char **rhs_start, size_t *rhs_length) | |
388 | { | |
389 | struct sr_serial_dev_inst *ser; | |
390 | char *rdptr; | |
391 | size_t rdlen, got; | |
392 | int ret; | |
393 | guint64 now_us, deadline_us; | |
394 | gboolean has_timedout; | |
395 | char *eol_pos, *endptr; | |
396 | char got_insn; | |
397 | unsigned long got_index; | |
398 | ||
399 | if (is_ok) | |
400 | *is_ok = FALSE; | |
401 | if (rhs_start) | |
402 | *rhs_start = NULL; | |
403 | if (rhs_length) | |
404 | *rhs_length = 0; | |
405 | ||
406 | if (!sdi) | |
407 | return SR_ERR_ARG; | |
408 | ser = sdi->conn; | |
409 | if (!ser) | |
410 | return SR_ERR_ARG; | |
1711287e GS |
411 | if (!s) |
412 | return SR_ERR_ARG; | |
18baeeed GS |
413 | |
414 | g_string_set_size(s, MAX_RSP_LENGTH); | |
415 | g_string_truncate(s, 0); | |
416 | ||
417 | /* Arrange for overall receive timeout when caller specified. */ | |
418 | now_us = deadline_us = 0; | |
419 | if (timeout_ms) { | |
420 | now_us = g_get_monotonic_time(); | |
421 | deadline_us = now_us; | |
422 | deadline_us += timeout_ms * 1000; | |
423 | } | |
424 | ||
425 | rdptr = s->str; | |
426 | rdlen = s->allocated_len - 1 - s->len; | |
427 | while (rdlen) { | |
428 | /* Get another chunk of receive data. Check for EOL. */ | |
429 | ret = serial_read_blocking(ser, rdptr, rdlen, delay_ms); | |
430 | if (ret < 0) | |
431 | return SR_ERR_IO; | |
432 | got = (size_t)ret; | |
433 | if (got > rdlen) | |
434 | got = rdlen; | |
435 | rdptr[got] = '\0'; | |
436 | eol_pos = strchr(rdptr, '\n'); | |
437 | rdptr += got; | |
438 | rdlen -= got; | |
1711287e | 439 | g_string_set_size(s, s->len + got); |
18baeeed GS |
440 | /* Check timeout expiration upon empty reception. */ |
441 | has_timedout = FALSE; | |
442 | if (timeout_ms && !got) { | |
443 | now_us = g_get_monotonic_time(); | |
444 | if (now_us >= deadline_us) | |
445 | has_timedout = TRUE; | |
446 | } | |
447 | if (!eol_pos) { | |
448 | if (has_timedout) | |
449 | break; | |
450 | continue; | |
451 | } | |
1711287e | 452 | log_raw_bytes("serial RX bytes: <-- ", s); |
18baeeed GS |
453 | |
454 | /* Normalize the received text line. */ | |
455 | *eol_pos++ = '\0'; | |
456 | rdptr = s->str; | |
457 | (void)sr_text_trim_spaces(rdptr); | |
458 | rdlen = strlen(rdptr); | |
1711287e | 459 | sr_spew("serial RX text: <-- %s", rdptr); |
18baeeed GS |
460 | if (rdlen && rdptr[rdlen - 1] == '.') |
461 | rdptr[--rdlen] = '\0'; | |
462 | ||
463 | /* Check conditions as requested by the caller. */ | |
464 | if (is_ok || wants_insn || rhs_start) { | |
465 | if (*rdptr != ':') { | |
466 | sr_dbg("serial read, colon missing"); | |
467 | return SR_ERR_DATA; | |
468 | } | |
469 | rdptr++; | |
470 | rdlen--; | |
471 | } | |
472 | /* | |
473 | * The check for 'ok' is terminal. Does not combine with | |
474 | * responses which carry payload data on their RHS. | |
475 | */ | |
476 | if (is_ok) { | |
477 | *is_ok = strcmp(rdptr, "ok") == 0; | |
478 | sr_dbg("serial read, 'ok' check %d", *is_ok); | |
479 | return *is_ok ? SR_OK : SR_ERR_DATA; | |
480 | } | |
481 | /* | |
482 | * Conditional strict checks for caller's expected fields. | |
483 | * Unconditional weaker checks for general structure. | |
484 | */ | |
485 | if (wants_insn && *rdptr != wants_insn) { | |
486 | sr_dbg("serial read, unexpected insn"); | |
487 | return SR_ERR_DATA; | |
488 | } | |
489 | got_insn = *rdptr++; | |
490 | switch (got_insn) { | |
491 | case INSN_WRITE_PARA: | |
492 | case INSN_READ_PARA: | |
493 | case INSN_WRITE_WAVE: | |
494 | case INSN_READ_WAVE: | |
495 | /* EMPTY */ | |
496 | break; | |
497 | default: | |
498 | sr_dbg("serial read, unknown insn %c", got_insn); | |
499 | return SR_ERR_DATA; | |
500 | } | |
501 | endptr = NULL; | |
502 | ret = sr_atoul_base(rdptr, &got_index, &endptr, 10); | |
503 | if (ret != SR_OK || !endptr) | |
504 | return SR_ERR_DATA; | |
505 | if (wants_index && got_index != wants_index) { | |
1711287e | 506 | sr_dbg("serial read, unexpected index %lu", got_index); |
18baeeed GS |
507 | return SR_ERR_DATA; |
508 | } | |
509 | rdptr = endptr; | |
510 | if (rhs_start || rhs_length) { | |
511 | if (*rdptr != '=') { | |
512 | sr_dbg("serial read, equals sign missing"); | |
513 | return SR_ERR_DATA; | |
514 | } | |
515 | } | |
516 | if (*rdptr) | |
517 | rdptr++; | |
518 | ||
519 | /* Response is considered plausible here. */ | |
520 | if (rhs_start) | |
521 | *rhs_start = rdptr; | |
522 | if (rhs_length) | |
523 | *rhs_length = strlen(rdptr); | |
524 | return SR_OK; | |
525 | } | |
1711287e GS |
526 | log_raw_bytes("serial RX bytes: <-- ", s); |
527 | sr_dbg("serial read, unterminated response, discarded"); | |
18baeeed | 528 | |
18baeeed GS |
529 | return SR_ERR_DATA; |
530 | } | |
531 | ||
532 | /* Formatting helpers for request construction. */ | |
533 | ||
534 | static void append_insn_read_para(GString *s, char insn, size_t idx) | |
535 | { | |
1711287e | 536 | g_string_append_printf(s, ":%c%02zu=0", insn, idx & 0xff); |
18baeeed GS |
537 | } |
538 | ||
539 | static void append_insn_write_para_va(GString *s, char insn, size_t idx, | |
540 | const char *fmt, va_list args) ATTR_FMT_PRINTF(4, 0); | |
541 | static void append_insn_write_para_va(GString *s, char insn, size_t idx, | |
542 | const char *fmt, va_list args) | |
543 | { | |
1711287e | 544 | g_string_append_printf(s, ":%c%02zu=", insn, idx & 0xff); |
18baeeed GS |
545 | g_string_append_vprintf(s, fmt, args); |
546 | } | |
547 | ||
548 | static void append_insn_write_para_dots(GString *s, char insn, size_t idx, | |
549 | const char *fmt, ...) ATTR_FMT_PRINTF(4, 5); | |
550 | static void append_insn_write_para_dots(GString *s, char insn, size_t idx, | |
551 | const char *fmt, ...) | |
552 | { | |
553 | va_list args; | |
554 | ||
555 | va_start(args, fmt); | |
556 | append_insn_write_para_va(s, insn, idx, fmt, args); | |
557 | va_end(args); | |
558 | } | |
559 | ||
560 | /* | |
561 | * Turn comma separators into whitespace. Simplifies the interpretation | |
562 | * of multi-value response payloads. Also replaces any trailing period | |
563 | * in case callers kept one in the receive buffer. | |
564 | */ | |
565 | static void replace_separators(char *s) | |
566 | { | |
567 | ||
568 | while (s && *s) { | |
569 | if (s[0] == ',') { | |
570 | *s++ = ' '; | |
571 | continue; | |
572 | } | |
573 | if (s[0] == '.' && s[1] == '\0') { | |
574 | *s++ = ' '; | |
575 | continue; | |
576 | } | |
577 | s++; | |
578 | } | |
579 | } | |
580 | ||
581 | /* | |
582 | * Convenience to interpret responses' values. Also concentrates the | |
583 | * involved magic and simplifies diagnostics. It's essential to apply | |
584 | * implicit multipliers, and to properly combine multiple fields into | |
585 | * the resulting parameter's value (think scaling and offsetting). | |
586 | */ | |
587 | ||
588 | static const double scales_freq[] = { | |
589 | 1, 1, 1, 1e-3, 1e-6, | |
590 | }; | |
591 | ||
592 | static int parse_freq_text(char *s, double *value) | |
593 | { | |
594 | char *word; | |
595 | int ret; | |
596 | double dvalue; | |
597 | unsigned long scale; | |
598 | ||
599 | replace_separators(s); | |
600 | ||
601 | /* First word is a mantissa, in centi-Hertz. :-O */ | |
602 | word = sr_text_next_word(s, &s); | |
603 | ret = sr_atod(word, &dvalue); | |
604 | if (ret != SR_OK) | |
605 | return ret; | |
606 | ||
607 | /* Next word is an encoded scaling factor. */ | |
608 | word = sr_text_next_word(s, &s); | |
609 | ret = sr_atoul_base(word, &scale, NULL, 10); | |
610 | if (ret != SR_OK) | |
611 | return ret; | |
1711287e | 612 | sr_spew("parse freq, mant %f, scale %lu", dvalue, scale); |
18baeeed GS |
613 | if (scale >= ARRAY_SIZE(scales_freq)) |
614 | return SR_ERR_DATA; | |
615 | ||
616 | /* Do scale the mantissa's value. */ | |
617 | dvalue /= 100.0; | |
618 | dvalue /= scales_freq[scale]; | |
1711287e | 619 | sr_spew("parse freq, value %f", dvalue); |
18baeeed GS |
620 | |
621 | if (value) | |
622 | *value = dvalue; | |
623 | return SR_OK; | |
624 | } | |
625 | ||
626 | static int parse_volt_text(char *s, double *value) | |
627 | { | |
628 | int ret; | |
629 | double dvalue; | |
630 | ||
631 | /* Single value, in units of mV. */ | |
632 | ret = sr_atod(s, &dvalue); | |
633 | if (ret != SR_OK) | |
634 | return ret; | |
1711287e | 635 | sr_spew("parse volt, mant %f", dvalue); |
18baeeed | 636 | dvalue /= 1000.0; |
1711287e | 637 | sr_spew("parse volt, value %f", dvalue); |
18baeeed GS |
638 | |
639 | if (value) | |
640 | *value = dvalue; | |
641 | return SR_OK; | |
642 | } | |
643 | ||
644 | static int parse_bias_text(char *s, double *value) | |
645 | { | |
646 | int ret; | |
647 | double dvalue; | |
648 | ||
649 | /* | |
650 | * Single value, in units of 10mV with a 10V offset. Capped to | |
651 | * the +9.99V..-9.99V range. The Joy-IT PDF is a little weird | |
652 | * suggesting that ":w27=9999." translates to 9.99 volts. | |
653 | */ | |
654 | ret = sr_atod(s, &dvalue); | |
655 | if (ret != SR_OK) | |
656 | return ret; | |
1711287e | 657 | sr_spew("parse bias, mant %f", dvalue); |
18baeeed GS |
658 | dvalue /= 100.0; |
659 | dvalue -= 10.0; | |
660 | if (dvalue >= 9.99) | |
661 | dvalue = 9.99; | |
662 | if (dvalue <= -9.99) | |
663 | dvalue = -9.99; | |
1711287e | 664 | sr_spew("parse bias, value %f", dvalue); |
18baeeed GS |
665 | |
666 | if (value) | |
667 | *value = dvalue; | |
668 | return SR_OK; | |
669 | } | |
670 | ||
671 | static int parse_duty_text(char *s, double *value) | |
672 | { | |
673 | int ret; | |
674 | double dvalue; | |
675 | ||
676 | /* | |
677 | * Single value, in units of 0.1% (permille). | |
678 | * Scale to the 0.0..1.0 range. | |
679 | */ | |
680 | ret = sr_atod(s, &dvalue); | |
681 | if (ret != SR_OK) | |
682 | return ret; | |
1711287e | 683 | sr_spew("parse duty, mant %f", dvalue); |
18baeeed | 684 | dvalue /= 1000.0; |
1711287e | 685 | sr_spew("parse duty, value %f", dvalue); |
18baeeed GS |
686 | |
687 | if (value) | |
688 | *value = dvalue; | |
689 | return SR_OK; | |
690 | } | |
691 | ||
692 | static int parse_phase_text(char *s, double *value) | |
693 | { | |
694 | int ret; | |
695 | double dvalue; | |
696 | ||
697 | /* Single value, in units of deci-degrees. */ | |
698 | ret = sr_atod(s, &dvalue); | |
699 | if (ret != SR_OK) | |
700 | return ret; | |
1711287e | 701 | sr_spew("parse phase, mant %f", dvalue); |
18baeeed | 702 | dvalue /= 10.0; |
1711287e | 703 | sr_spew("parse phase, value %f", dvalue); |
18baeeed GS |
704 | |
705 | if (value) | |
706 | *value = dvalue; | |
707 | return SR_OK; | |
708 | } | |
709 | ||
710 | /* | |
711 | * Convenience to generate request presentations. Also concentrates the | |
712 | * involved magic and simplifies diagnostics. It's essential to apply | |
713 | * implicit multipliers, and to properly create all request fields that | |
714 | * communicate a value to the device's firmware (think scale and offset). | |
715 | */ | |
716 | ||
717 | static void write_freq_text(GString *s, double freq) | |
718 | { | |
719 | unsigned long scale_idx; | |
720 | const char *text_pos; | |
721 | ||
1711287e | 722 | sr_spew("write freq, value %f", freq); |
18baeeed GS |
723 | text_pos = &s->str[s->len]; |
724 | ||
725 | /* | |
726 | * First word is mantissa in centi-Hertz. Second word is a | |
727 | * scaling factor code. Keep scaling simple, always scale | |
728 | * by a factor of 1.0. | |
729 | */ | |
730 | scale_idx = 0; | |
731 | freq *= scales_freq[scale_idx]; | |
732 | freq *= 100.0; | |
733 | ||
1711287e | 734 | g_string_append_printf(s, "%.0f,%lu", freq, scale_idx); |
18baeeed GS |
735 | sr_spew("write freq, text %s", text_pos); |
736 | } | |
737 | ||
738 | static void write_volt_text(GString *s, double volt) | |
739 | { | |
740 | const char *text_pos; | |
741 | ||
1711287e | 742 | sr_spew("write volt, value %f", volt); |
18baeeed GS |
743 | text_pos = &s->str[s->len]; |
744 | ||
745 | /* | |
746 | * Single value in units of 1mV. | |
747 | * Limit input values to the 0..+20 range. This writer is only | |
748 | * used by the amplitude setter. | |
749 | */ | |
750 | if (volt > 20.0) | |
751 | volt = 20.0; | |
752 | if (volt < 0.0) | |
753 | volt = 0.0; | |
754 | volt *= 1000.0; | |
1711287e | 755 | g_string_append_printf(s, "%.0f", volt); |
18baeeed GS |
756 | sr_spew("write volt, text %s", text_pos); |
757 | } | |
758 | ||
759 | static void write_bias_text(GString *s, double volt) | |
760 | { | |
761 | const char *text_pos; | |
762 | ||
1711287e | 763 | sr_spew("write bias, value %f", volt); |
18baeeed GS |
764 | text_pos = &s->str[s->len]; |
765 | ||
766 | /* | |
767 | * Single value in units of 10mV with a 10V offset. Capped to | |
768 | * the +9.99..-9.99 range. | |
769 | */ | |
770 | if (volt > 9.99) | |
771 | volt = 9.99; | |
772 | if (volt < -9.99) | |
773 | volt = -9.99; | |
774 | volt += 10.0; | |
775 | volt *= 100.0; | |
776 | ||
1711287e | 777 | g_string_append_printf(s, "%.0f", volt); |
18baeeed GS |
778 | sr_spew("write bias, text %s", text_pos); |
779 | } | |
780 | ||
781 | static void write_duty_text(GString *s, double duty) | |
782 | { | |
783 | const char *text_pos; | |
784 | ||
1711287e | 785 | sr_spew("write duty, value %f", duty); |
18baeeed GS |
786 | text_pos = &s->str[s->len]; |
787 | ||
788 | /* | |
789 | * Single value in units of 0.1% (permille). Capped to the | |
790 | * 0.0..1.0 range. | |
791 | */ | |
792 | if (duty < 0.0) | |
793 | duty = 0.0; | |
794 | if (duty > 1.0) | |
795 | duty = 1.0; | |
796 | duty *= 1000.0; | |
797 | ||
1711287e | 798 | g_string_append_printf(s, "%.0f", duty); |
18baeeed GS |
799 | sr_spew("write duty, text %s", text_pos); |
800 | } | |
801 | ||
802 | static void write_phase_text(GString *s, double phase) | |
803 | { | |
804 | const char *text_pos; | |
805 | ||
1711287e | 806 | sr_spew("write phase, value %f", phase); |
18baeeed GS |
807 | text_pos = &s->str[s->len]; |
808 | ||
809 | /* | |
810 | * Single value in units of deci-degrees. | |
811 | * Kept to the 0..360 range by means of a modulo operation. | |
812 | */ | |
813 | phase = fmod(phase, 360.0); | |
814 | phase *= 10.0; | |
815 | ||
1711287e | 816 | g_string_append_printf(s, "%.0f", phase); |
18baeeed GS |
817 | sr_spew("write phase, text %s", text_pos); |
818 | } | |
819 | ||
820 | /* | |
821 | * Convenience communication wrapper. Re-uses a buffer in devc, which | |
822 | * simplifies resource handling in error paths. Sends a parameter-less | |
823 | * read-request. Then receives a response which can carry values. | |
824 | */ | |
825 | static int quick_send_read_then_recv(const struct sr_dev_inst *sdi, | |
826 | char insn, size_t idx, | |
827 | unsigned int read_timeout_ms, | |
828 | char **rhs_start, size_t *rhs_length) | |
829 | { | |
830 | struct dev_context *devc; | |
831 | GString *s; | |
832 | int ret; | |
833 | ||
834 | if (!sdi) | |
835 | return SR_ERR_ARG; | |
836 | devc = sdi->priv; | |
837 | if (!devc) | |
838 | return SR_ERR_ARG; | |
839 | if (!devc->quick_req) | |
840 | devc->quick_req = g_string_sized_new(MAX_RSP_LENGTH); | |
841 | s = devc->quick_req; | |
842 | ||
843 | g_string_truncate(s, 0); | |
844 | append_insn_read_para(s, insn, idx); | |
916cea58 | 845 | ret = serial_send_textline(sdi, s, DELAY_AFTER_SEND); |
18baeeed GS |
846 | if (ret != SR_OK) |
847 | return ret; | |
848 | ||
849 | ret = serial_recv_textline(sdi, s, | |
850 | TIMEOUT_READ_CHUNK, read_timeout_ms, | |
851 | NULL, insn, idx, rhs_start, rhs_length); | |
852 | if (ret != SR_OK) | |
853 | return ret; | |
854 | ||
855 | return SR_OK; | |
856 | } | |
857 | ||
858 | /* | |
859 | * Convenience communication wrapper, re-uses a buffer in devc. Sends a | |
860 | * write-request with parameters. Then receives an "ok" style response. | |
861 | * Had to put the request details after the response related parameters | |
862 | * because of the va_list API. | |
863 | */ | |
864 | static int quick_send_write_then_recv_ok(const struct sr_dev_inst *sdi, | |
865 | unsigned int read_timeout_ms, gboolean *is_ok, | |
866 | char insn, size_t idx, const char *fmt, ...) ATTR_FMT_PRINTF(6, 7); | |
867 | static int quick_send_write_then_recv_ok(const struct sr_dev_inst *sdi, | |
868 | unsigned int read_timeout_ms, gboolean *is_ok, | |
869 | char insn, size_t idx, const char *fmt, ...) | |
870 | { | |
871 | struct dev_context *devc; | |
872 | GString *s; | |
873 | va_list args; | |
874 | int ret; | |
875 | gboolean ok; | |
876 | ||
877 | if (!sdi) | |
878 | return SR_ERR_ARG; | |
879 | devc = sdi->priv; | |
880 | if (!devc) | |
881 | return SR_ERR_ARG; | |
882 | if (!devc->quick_req) | |
883 | devc->quick_req = g_string_sized_new(MAX_RSP_LENGTH); | |
884 | s = devc->quick_req; | |
885 | ||
886 | g_string_truncate(s, 0); | |
887 | va_start(args, fmt); | |
888 | append_insn_write_para_va(s, insn, idx, fmt, args); | |
889 | va_end(args); | |
916cea58 | 890 | ret = serial_send_textline(sdi, s, DELAY_AFTER_SEND); |
18baeeed GS |
891 | if (ret != SR_OK) |
892 | return ret; | |
893 | ||
894 | ret = serial_recv_textline(sdi, s, | |
895 | TIMEOUT_READ_CHUNK, read_timeout_ms, | |
896 | &ok, '\0', 0, NULL, NULL); | |
897 | if (is_ok) | |
898 | *is_ok = ok; | |
899 | if (ret != SR_OK) | |
900 | return ret; | |
901 | ||
902 | return SR_OK; | |
903 | } | |
904 | ||
905 | /* | |
906 | * High level getters/setters for device properties. | |
907 | * To be used by the api.c config get/set infrastructure. | |
908 | */ | |
909 | ||
910 | SR_PRIV int jds6600_get_chans_enable(const struct sr_dev_inst *sdi) | |
911 | { | |
912 | struct dev_context *devc; | |
913 | int ret; | |
914 | char *rdptr, *word, *endptr; | |
915 | struct devc_dev *device; | |
916 | struct devc_chan *chans; | |
917 | size_t idx; | |
918 | unsigned long on; | |
919 | ||
920 | devc = sdi->priv; | |
921 | if (!devc) | |
922 | return SR_ERR_ARG; | |
923 | ||
924 | /* Transmit the request, receive the response. */ | |
925 | ret = quick_send_read_then_recv(sdi, | |
926 | INSN_READ_PARA, IDX_CHANNELS_ENABLE, | |
927 | 0, &rdptr, NULL); | |
928 | if (ret != SR_OK) | |
929 | return ret; | |
930 | sr_dbg("get enabled, response text: %s", rdptr); | |
931 | ||
932 | /* Interpret the response (multiple values, boolean). */ | |
933 | replace_separators(rdptr); | |
934 | device = &devc->device; | |
935 | chans = devc->channel_config; | |
936 | for (idx = 0; idx < device->channel_count_gen; idx++) { | |
937 | word = sr_text_next_word(rdptr, &rdptr); | |
938 | if (!word || !*word) | |
939 | return SR_ERR_DATA; | |
940 | endptr = NULL; | |
941 | ret = sr_atoul_base(word, &on, &endptr, 10); | |
942 | if (ret != SR_OK || !endptr || *endptr) | |
943 | return SR_ERR_DATA; | |
944 | chans[idx].enabled = on; | |
945 | } | |
946 | ||
947 | return SR_OK; | |
948 | } | |
949 | ||
950 | SR_PRIV int jds6600_get_waveform(const struct sr_dev_inst *sdi, size_t ch_idx) | |
951 | { | |
952 | struct dev_context *devc; | |
953 | int ret; | |
954 | char *rdptr, *endptr; | |
955 | struct devc_wave *waves; | |
956 | struct devc_chan *chan; | |
957 | unsigned long code; | |
958 | size_t idx; | |
959 | ||
960 | if (!sdi) | |
961 | return SR_ERR_ARG; | |
962 | devc = sdi->priv; | |
963 | if (!devc) | |
964 | return SR_ERR_ARG; | |
965 | waves = &devc->waveforms; | |
966 | if (ch_idx >= ARRAY_SIZE(devc->channel_config)) | |
967 | return SR_ERR_ARG; | |
968 | chan = &devc->channel_config[ch_idx]; | |
969 | ||
970 | /* Transmit the request, receive the response. */ | |
971 | ret = quick_send_read_then_recv(sdi, | |
972 | INSN_READ_PARA, IDX_WAVEFORM_CH1 + ch_idx, | |
973 | 0, &rdptr, NULL); | |
974 | if (ret != SR_OK) | |
975 | return ret; | |
976 | sr_dbg("get waveform, response text: %s", rdptr); | |
977 | ||
978 | /* | |
979 | * Interpret the response (integer value, waveform code). | |
980 | * Lookup the firmware's code for that waveform in the | |
981 | * list of user perceivable names for waveforms. | |
982 | */ | |
983 | endptr = NULL; | |
984 | ret = sr_atoul_base(rdptr, &code, &endptr, 10); | |
985 | if (ret != SR_OK) | |
986 | return SR_ERR_DATA; | |
987 | for (idx = 0; idx < waves->names_count; idx++) { | |
988 | if (code != waves->fw_codes[idx]) | |
989 | continue; | |
990 | chan->waveform_code = code; | |
991 | chan->waveform_index = idx; | |
992 | sr_dbg("get waveform, code %lu, idx %zu, name %s", | |
993 | code, idx, waves->names[idx]); | |
994 | return SR_OK; | |
995 | } | |
996 | ||
997 | return SR_ERR_DATA; | |
998 | } | |
999 | ||
1000 | #if WITH_ARBWAVE_DOWNLOAD | |
1001 | /* | |
1002 | * Development HACK. Get a waveform from the device. Uncertain where to | |
1003 | * dump it though. Have yet to identify a sigrok API for waveforms. | |
1004 | */ | |
1005 | static int jds6600_get_arb_waveform(const struct sr_dev_inst *sdi, size_t idx) | |
1006 | { | |
1007 | struct dev_context *devc; | |
1008 | struct devc_wave *waves; | |
1009 | int ret; | |
1010 | char *rdptr, *word, *endptr; | |
1011 | size_t sample_count; | |
1012 | unsigned long value; | |
1013 | ||
1014 | if (!sdi) | |
1015 | return SR_ERR_ARG; | |
1016 | devc = sdi->priv; | |
1017 | if (!devc) | |
1018 | return SR_ERR_ARG; | |
1019 | waves = &devc->waveforms; | |
1020 | ||
1021 | if (idx >= waves->arbitrary_count) | |
1022 | return SR_ERR_ARG; | |
1023 | ||
1024 | /* Transmit the request, receive the response. */ | |
1025 | ret = quick_send_read_then_recv(sdi, | |
1026 | INSN_READ_WAVE, idx, | |
1027 | 0, &rdptr, NULL); | |
1028 | if (ret != SR_OK) | |
1029 | return ret; | |
1030 | sr_dbg("get arb wave, response text: %s", rdptr); | |
1031 | ||
1032 | /* Extract the sequence of samples for the waveform. */ | |
1033 | replace_separators(rdptr); | |
1034 | sample_count = 0; | |
1035 | while (rdptr && *rdptr) { | |
1036 | word = sr_text_next_word(rdptr, &rdptr); | |
1037 | if (!word) | |
1038 | break; | |
1039 | endptr = NULL; | |
1040 | ret = sr_atoul_base(word, &value, &endptr, 10); | |
1041 | if (ret != SR_OK || !endptr || *endptr) { | |
1042 | sr_dbg("get arb wave, conv error: %s", word); | |
1043 | return SR_ERR_DATA; | |
1044 | } | |
1045 | sample_count++; | |
1046 | } | |
1047 | sr_dbg("get arb wave, samples count: %zu", sample_count); | |
1048 | ||
1049 | return SR_OK; | |
1050 | } | |
1051 | #endif | |
1052 | ||
1053 | SR_PRIV int jds6600_get_frequency(const struct sr_dev_inst *sdi, size_t ch_idx) | |
1054 | { | |
1055 | struct dev_context *devc; | |
1056 | struct devc_chan *chan; | |
1057 | int ret; | |
1058 | char *rdptr; | |
1059 | double freq; | |
1060 | ||
1061 | devc = sdi->priv; | |
1062 | if (!devc) | |
1063 | return SR_ERR_ARG; | |
1064 | if (ch_idx >= ARRAY_SIZE(devc->channel_config)) | |
1065 | return SR_ERR_ARG; | |
1066 | chan = &devc->channel_config[ch_idx]; | |
1067 | ||
1068 | /* Transmit the request, receive the response. */ | |
1069 | ret = quick_send_read_then_recv(sdi, | |
1070 | INSN_READ_PARA, IDX_FREQUENCY_CH1 + ch_idx, | |
1071 | 0, &rdptr, NULL); | |
1072 | if (ret != SR_OK) | |
1073 | return ret; | |
1074 | sr_dbg("get frequency, response text: %s", rdptr); | |
1075 | ||
1076 | /* Interpret the response (value and scale, frequency). */ | |
1077 | ret = parse_freq_text(rdptr, &freq); | |
1078 | if (ret != SR_OK) | |
1079 | return SR_ERR_DATA; | |
1711287e | 1080 | sr_dbg("get frequency, value %f", freq); |
18baeeed GS |
1081 | chan->output_frequency = freq; |
1082 | return SR_OK; | |
1083 | } | |
1084 | ||
1085 | SR_PRIV int jds6600_get_amplitude(const struct sr_dev_inst *sdi, size_t ch_idx) | |
1086 | { | |
1087 | struct dev_context *devc; | |
1088 | struct devc_chan *chan; | |
1089 | int ret; | |
1090 | char *rdptr; | |
1091 | double amp; | |
1092 | ||
1093 | devc = sdi->priv; | |
1094 | if (!devc) | |
1095 | return SR_ERR_ARG; | |
1096 | if (ch_idx >= ARRAY_SIZE(devc->channel_config)) | |
1097 | return SR_ERR_ARG; | |
1098 | chan = &devc->channel_config[ch_idx]; | |
1099 | ||
1100 | /* Transmit the request, receive the response. */ | |
1101 | ret = quick_send_read_then_recv(sdi, | |
1102 | INSN_READ_PARA, IDX_AMPLITUDE_CH1 + ch_idx, | |
1103 | 0, &rdptr, NULL); | |
1104 | if (ret != SR_OK) | |
1105 | return ret; | |
1106 | sr_dbg("get amplitude, response text: %s", rdptr); | |
1107 | ||
1108 | /* Interpret the response (single value, a voltage). */ | |
1109 | ret = parse_volt_text(rdptr, &); | |
1110 | if (ret != SR_OK) | |
1111 | return SR_ERR_DATA; | |
1711287e | 1112 | sr_dbg("get amplitude, value %f", amp); |
18baeeed GS |
1113 | chan->amplitude = amp; |
1114 | return SR_OK; | |
1115 | } | |
1116 | ||
1117 | SR_PRIV int jds6600_get_offset(const struct sr_dev_inst *sdi, size_t ch_idx) | |
1118 | { | |
1119 | struct dev_context *devc; | |
1120 | struct devc_chan *chan; | |
1121 | int ret; | |
1122 | char *rdptr; | |
1123 | double off; | |
1124 | ||
1125 | devc = sdi->priv; | |
1126 | if (!devc) | |
1127 | return SR_ERR_ARG; | |
1128 | if (ch_idx >= ARRAY_SIZE(devc->channel_config)) | |
1129 | return SR_ERR_ARG; | |
1130 | chan = &devc->channel_config[ch_idx]; | |
1131 | ||
1132 | /* Transmit the request, receive the response. */ | |
1133 | ret = quick_send_read_then_recv(sdi, | |
1134 | INSN_READ_PARA, IDX_OFFSET_CH1 + ch_idx, | |
1135 | 0, &rdptr, NULL); | |
1136 | if (ret != SR_OK) | |
1137 | return ret; | |
1138 | sr_dbg("get offset, response text: %s", rdptr); | |
1139 | ||
1140 | /* Interpret the response (single value, an offset). */ | |
1141 | ret = parse_bias_text(rdptr, &off); | |
1142 | if (ret != SR_OK) | |
1143 | return SR_ERR_DATA; | |
1711287e | 1144 | sr_dbg("get offset, value %f", off); |
18baeeed GS |
1145 | chan->offset = off; |
1146 | return SR_OK; | |
1147 | } | |
1148 | ||
1149 | SR_PRIV int jds6600_get_dutycycle(const struct sr_dev_inst *sdi, size_t ch_idx) | |
b1fa9aac | 1150 | { |
b1fa9aac | 1151 | struct dev_context *devc; |
18baeeed GS |
1152 | struct devc_chan *chan; |
1153 | int ret; | |
1154 | char *rdptr; | |
1155 | double duty; | |
b1fa9aac | 1156 | |
18baeeed GS |
1157 | devc = sdi->priv; |
1158 | if (!devc) | |
1159 | return SR_ERR_ARG; | |
1160 | if (ch_idx >= ARRAY_SIZE(devc->channel_config)) | |
1161 | return SR_ERR_ARG; | |
1162 | chan = &devc->channel_config[ch_idx]; | |
1163 | ||
1164 | /* Transmit the request, receive the response. */ | |
1165 | ret = quick_send_read_then_recv(sdi, | |
1166 | INSN_READ_PARA, IDX_DUTYCYCLE_CH1 + ch_idx, | |
1167 | 0, &rdptr, NULL); | |
1168 | if (ret != SR_OK) | |
1169 | return ret; | |
1170 | sr_dbg("get duty cycle, response text: %s", rdptr); | |
1171 | ||
1172 | /* Interpret the response (single value, a percentage). */ | |
1173 | ret = parse_duty_text(rdptr, &duty); | |
1174 | if (ret != SR_OK) | |
1175 | return SR_ERR_DATA; | |
1711287e | 1176 | sr_dbg("get duty cycle, value %f", duty); |
18baeeed GS |
1177 | chan->dutycycle = duty; |
1178 | return SR_OK; | |
1179 | } | |
1180 | ||
1181 | SR_PRIV int jds6600_get_phase_chans(const struct sr_dev_inst *sdi) | |
1182 | { | |
1183 | struct dev_context *devc; | |
1184 | int ret; | |
1185 | char *rdptr; | |
1186 | double phase; | |
1187 | ||
1188 | devc = sdi->priv; | |
1189 | if (!devc) | |
1190 | return SR_ERR_ARG; | |
1191 | ||
1192 | /* Transmit the request, receive the response. */ | |
1193 | ret = quick_send_read_then_recv(sdi, | |
1194 | INSN_READ_PARA, IDX_PHASE_CHANNELS, | |
1195 | 0, &rdptr, NULL); | |
1196 | if (ret != SR_OK) | |
1197 | return ret; | |
1198 | sr_dbg("get phase, response text: %s", rdptr); | |
1199 | ||
1200 | /* Interpret the response (single value, an angle). */ | |
1201 | ret = parse_phase_text(rdptr, &phase); | |
1202 | if (ret != SR_OK) | |
1203 | return SR_ERR_DATA; | |
1711287e | 1204 | sr_dbg("get phase, value %f", phase); |
18baeeed GS |
1205 | devc->channels_phase = phase; |
1206 | return SR_OK; | |
1207 | } | |
1208 | ||
1209 | SR_PRIV int jds6600_set_chans_enable(const struct sr_dev_inst *sdi) | |
1210 | { | |
1211 | struct dev_context *devc; | |
1212 | struct devc_chan *chans; | |
1213 | GString *en_text; | |
1214 | size_t idx; | |
1215 | int ret; | |
b1fa9aac | 1216 | |
b1fa9aac | 1217 | if (!sdi) |
18baeeed GS |
1218 | return SR_ERR_ARG; |
1219 | devc = sdi->priv; | |
1220 | if (!devc) | |
1221 | return SR_ERR_ARG; | |
1222 | ||
1223 | /* Transmit the request, receive an "ok" style response. */ | |
1224 | chans = devc->channel_config; | |
1225 | en_text = g_string_sized_new(20); | |
1226 | for (idx = 0; idx < devc->device.channel_count_gen; idx++) { | |
1227 | if (en_text->len) | |
1228 | g_string_append_c(en_text, ','); | |
1229 | g_string_append_c(en_text, chans[idx].enabled ? '1' : '0'); | |
1230 | } | |
1231 | sr_dbg("set enabled, request text: %s", en_text->str); | |
1232 | ret = quick_send_write_then_recv_ok(sdi, 0, NULL, | |
1233 | INSN_WRITE_PARA, IDX_CHANNELS_ENABLE, "%s", en_text->str); | |
1234 | g_string_free(en_text, 20); | |
1235 | if (ret != SR_OK) | |
1236 | return ret; | |
1237 | ||
1238 | return SR_OK; | |
1239 | } | |
b1fa9aac | 1240 | |
18baeeed GS |
1241 | SR_PRIV int jds6600_set_waveform(const struct sr_dev_inst *sdi, size_t ch_idx) |
1242 | { | |
1243 | struct dev_context *devc; | |
1244 | struct devc_chan *chan; | |
1245 | int ret; | |
1246 | ||
1247 | if (!sdi) | |
1248 | return SR_ERR_ARG; | |
b1fa9aac GS |
1249 | devc = sdi->priv; |
1250 | if (!devc) | |
18baeeed GS |
1251 | return SR_ERR_ARG; |
1252 | if (ch_idx >= devc->device.channel_count_gen) | |
1253 | return SR_ERR_ARG; | |
1254 | chan = &devc->channel_config[ch_idx]; | |
1255 | ||
1256 | /* Transmit the request, receive an "ok" style response. */ | |
1257 | ret = quick_send_write_then_recv_ok(sdi, 0, NULL, | |
1258 | INSN_WRITE_PARA, IDX_WAVEFORM_CH1 + ch_idx, | |
1259 | "%" PRIu32, chan->waveform_code); | |
1260 | if (ret != SR_OK) | |
1261 | return ret; | |
1262 | ||
1263 | return SR_OK; | |
1264 | } | |
1265 | ||
1266 | #if WITH_ARBWAVE_DOWNLOAD | |
1267 | /* | |
1268 | * Development HACK. Send a waveform to the device. Uncertain where | |
1269 | * to get it from though. Just generate some stupid pattern that's | |
1270 | * seen on the LCD later. | |
1271 | * | |
1272 | * Local experiments suggest that writing another waveform after having | |
1273 | * written one earlier results in the next waveform to become mangled. | |
1274 | * It appears to start with an all-bits-set pattern for a remarkable | |
1275 | * number of samples, before the actually written pattern is seen. Some | |
1276 | * delay after reception of the ":ok" response may be required to avoid | |
1277 | * this corruption. | |
1278 | */ | |
b1fa9aac | 1279 | |
18baeeed GS |
1280 | /* Stupid creation of one sample value. Gets waveform index and sample count. */ |
1281 | static uint16_t make_sample(size_t wave, size_t curr, size_t total) | |
1282 | { | |
1283 | uint16_t max_value, high_value, low_value; | |
1284 | size_t ival, high_width; | |
1285 | gboolean is_high; | |
1286 | ||
1287 | /* Get the waveform's amplitudes. */ | |
1288 | max_value = 4096; | |
1289 | high_value = max_value / (wave + 3); | |
1290 | high_value = max_value - high_value; | |
1291 | low_value = max_value - high_value; | |
1292 | ||
1293 | /* Get pulses' total interval, high and low half-periods. */ | |
1294 | ival = (total - 10) / wave; | |
1295 | high_width = ival / 2; | |
1296 | ||
1297 | /* Check location in the current period. */ | |
1298 | curr %= ival; | |
1299 | is_high = curr <= high_width; | |
1300 | return is_high ? high_value : low_value; | |
1301 | } | |
1302 | ||
1303 | /* Creation and download of the sequence of samples. */ | |
1304 | static int jds6600_set_arb_waveform(const struct sr_dev_inst *sdi, size_t idx) | |
1305 | { | |
1306 | struct dev_context *devc; | |
1307 | struct devc_wave *waves; | |
1308 | GString *wave_text; | |
1309 | size_t samples_total, samples_curr; | |
1310 | uint16_t value; | |
1311 | gboolean ok; | |
1312 | int ret; | |
1313 | ||
1314 | if (!sdi) | |
1315 | return SR_ERR_ARG; | |
1316 | devc = sdi->priv; | |
1317 | if (!devc) | |
1318 | return SR_ERR_ARG; | |
1319 | waves = &devc->waveforms; | |
1320 | ||
1321 | if (idx >= waves->arbitrary_count) | |
1322 | return SR_ERR_ARG; | |
1323 | ||
1324 | /* Construct a pattern that depends on the waveform index. */ | |
1325 | wave_text = g_string_sized_new(MAX_RSP_LENGTH); | |
1326 | samples_total = 2048; | |
1327 | samples_curr = 0; | |
1328 | for (samples_curr = 0; samples_curr < samples_total; samples_curr++) { | |
1329 | value = make_sample(idx, samples_curr, samples_total); | |
1330 | if (samples_curr) | |
1331 | g_string_append_c(wave_text, ','); | |
1332 | g_string_append_printf(wave_text, "%" PRIu16, value); | |
b1fa9aac | 1333 | } |
18baeeed GS |
1334 | sr_dbg("set arb wave, request text: %s", wave_text->str); |
1335 | ||
1336 | /* Transmit the request, receive an "ok" style response. */ | |
1337 | ret = quick_send_write_then_recv_ok(sdi, 0, &ok, | |
1338 | INSN_WRITE_WAVE, idx, "%s", wave_text->str); | |
1339 | if (ret != SR_OK) | |
1340 | return ret; | |
1341 | sr_dbg("set arb wave, response ok: %d", ok); | |
1342 | ||
1343 | if (DELAY_AFTER_FLASH) | |
1344 | g_usleep(DELAY_AFTER_FLASH * 1000); | |
1345 | ||
1346 | return SR_OK; | |
1347 | } | |
1348 | #endif | |
1349 | ||
1350 | SR_PRIV int jds6600_set_frequency(const struct sr_dev_inst *sdi, size_t ch_idx) | |
1351 | { | |
1352 | struct dev_context *devc; | |
1353 | struct devc_chan *chan; | |
1354 | double freq; | |
1355 | GString *freq_text; | |
1356 | int ret; | |
1357 | ||
1358 | if (!sdi) | |
1359 | return SR_ERR_ARG; | |
1360 | devc = sdi->priv; | |
1361 | if (!devc) | |
1362 | return SR_ERR_ARG; | |
1363 | if (ch_idx >= devc->device.channel_count_gen) | |
1364 | return SR_ERR_ARG; | |
1365 | chan = &devc->channel_config[ch_idx]; | |
1366 | ||
1367 | /* Limit input values to the range supported by the model. */ | |
1368 | freq = chan->output_frequency; | |
1369 | if (freq < 0.01) | |
1370 | freq = 0.01; | |
1371 | if (freq > devc->device.max_output_frequency) | |
1372 | freq = devc->device.max_output_frequency; | |
1373 | ||
1374 | /* Transmit the request, receive an "ok" style response. */ | |
1375 | freq_text = g_string_sized_new(32); | |
1376 | write_freq_text(freq_text, freq); | |
1377 | ret = quick_send_write_then_recv_ok(sdi, 0, NULL, | |
1378 | INSN_WRITE_PARA, IDX_FREQUENCY_CH1 + ch_idx, | |
1379 | "%s", freq_text->str); | |
1380 | g_string_free(freq_text, TRUE); | |
1381 | if (ret != SR_OK) | |
1382 | return ret; | |
1383 | ||
1384 | return SR_OK; | |
1385 | } | |
1386 | ||
1387 | SR_PRIV int jds6600_set_amplitude(const struct sr_dev_inst *sdi, size_t ch_idx) | |
1388 | { | |
1389 | struct dev_context *devc; | |
1390 | struct devc_chan *chan; | |
1391 | GString *volt_text; | |
1392 | int ret; | |
1393 | ||
1394 | if (!sdi) | |
1395 | return SR_ERR_ARG; | |
1396 | devc = sdi->priv; | |
1397 | if (!devc) | |
1398 | return SR_ERR_ARG; | |
1399 | if (ch_idx >= devc->device.channel_count_gen) | |
1400 | return SR_ERR_ARG; | |
1401 | chan = &devc->channel_config[ch_idx]; | |
1402 | ||
1403 | /* Transmit the request, receive an "ok" style response. */ | |
1404 | volt_text = g_string_sized_new(32); | |
1405 | write_volt_text(volt_text, chan->amplitude); | |
1406 | ret = quick_send_write_then_recv_ok(sdi, 0, NULL, | |
1407 | INSN_WRITE_PARA, IDX_AMPLITUDE_CH1 + ch_idx, | |
1408 | "%s", volt_text->str); | |
1409 | g_string_free(volt_text, TRUE); | |
1410 | if (ret != SR_OK) | |
1411 | return ret; | |
1412 | ||
1413 | return SR_OK; | |
1414 | } | |
1415 | ||
1416 | SR_PRIV int jds6600_set_offset(const struct sr_dev_inst *sdi, size_t ch_idx) | |
1417 | { | |
1418 | struct dev_context *devc; | |
1419 | struct devc_chan *chan; | |
1420 | GString *volt_text; | |
1421 | int ret; | |
1422 | ||
1423 | if (!sdi) | |
1424 | return SR_ERR_ARG; | |
1425 | devc = sdi->priv; | |
1426 | if (!devc) | |
1427 | return SR_ERR_ARG; | |
1428 | if (ch_idx >= devc->device.channel_count_gen) | |
1429 | return SR_ERR_ARG; | |
1430 | chan = &devc->channel_config[ch_idx]; | |
1431 | ||
1432 | /* Transmit the request, receive an "ok" style response. */ | |
1433 | volt_text = g_string_sized_new(32); | |
1434 | write_bias_text(volt_text, chan->offset); | |
1435 | ret = quick_send_write_then_recv_ok(sdi, 0, NULL, | |
1436 | INSN_WRITE_PARA, IDX_OFFSET_CH1 + ch_idx, | |
1437 | "%s", volt_text->str); | |
1438 | g_string_free(volt_text, TRUE); | |
1439 | if (ret != SR_OK) | |
1440 | return ret; | |
1441 | ||
1442 | return SR_OK; | |
1443 | } | |
1444 | ||
1445 | SR_PRIV int jds6600_set_dutycycle(const struct sr_dev_inst *sdi, size_t ch_idx) | |
1446 | { | |
1447 | struct dev_context *devc; | |
1448 | struct devc_chan *chan; | |
1449 | GString *duty_text; | |
1450 | int ret; | |
1451 | ||
1452 | if (!sdi) | |
1453 | return SR_ERR_ARG; | |
1454 | devc = sdi->priv; | |
1455 | if (!devc) | |
1456 | return SR_ERR_ARG; | |
1457 | if (ch_idx >= devc->device.channel_count_gen) | |
1458 | return SR_ERR_ARG; | |
1459 | chan = &devc->channel_config[ch_idx]; | |
1460 | ||
1461 | /* Transmit the request, receive an "ok" style response. */ | |
1462 | duty_text = g_string_sized_new(32); | |
1463 | write_duty_text(duty_text, chan->dutycycle); | |
1464 | ret = quick_send_write_then_recv_ok(sdi, 0, NULL, | |
1465 | INSN_WRITE_PARA, IDX_DUTYCYCLE_CH1 + ch_idx, | |
1466 | "%s", duty_text->str); | |
1467 | g_string_free(duty_text, TRUE); | |
1468 | if (ret != SR_OK) | |
1469 | return ret; | |
1470 | ||
1471 | return SR_OK; | |
1472 | } | |
1473 | ||
1474 | SR_PRIV int jds6600_set_phase_chans(const struct sr_dev_inst *sdi) | |
1475 | { | |
1476 | struct dev_context *devc; | |
1477 | GString *phase_text; | |
1478 | int ret; | |
1479 | ||
1480 | if (!sdi) | |
1481 | return SR_ERR_ARG; | |
1482 | devc = sdi->priv; | |
1483 | if (!devc) | |
1484 | return SR_ERR_ARG; | |
1485 | ||
1486 | /* Transmit the request, receive an "ok" style response. */ | |
1487 | phase_text = g_string_sized_new(32); | |
1488 | write_phase_text(phase_text, devc->channels_phase); | |
1489 | ret = quick_send_write_then_recv_ok(sdi, 0, NULL, | |
1490 | INSN_WRITE_PARA, IDX_PHASE_CHANNELS, | |
1491 | "%s", phase_text->str); | |
1492 | g_string_free(phase_text, TRUE); | |
1493 | if (ret != SR_OK) | |
1494 | return ret; | |
1495 | ||
1496 | return SR_OK; | |
1497 | } | |
1498 | ||
1499 | /* | |
1500 | * High level helpers for the scan/probe phase. Identify the attached | |
1501 | * device and synchronize to its current state and its capabilities. | |
1502 | */ | |
1503 | ||
1504 | SR_PRIV int jds6600_identify(struct sr_dev_inst *sdi) | |
1505 | { | |
1506 | struct dev_context *devc; | |
1507 | int ret; | |
1508 | char *rdptr, *endptr; | |
1509 | unsigned long devtype; | |
1510 | ||
1511 | (void)append_insn_write_para_dots; | |
1512 | ||
1513 | if (!sdi) | |
1514 | return SR_ERR_ARG; | |
1515 | devc = sdi->priv; | |
1516 | if (!devc) | |
1517 | return SR_ERR_ARG; | |
1518 | ||
1519 | /* Transmit "read device type" request, receive the response. */ | |
1520 | ret = quick_send_read_then_recv(sdi, | |
1521 | INSN_READ_PARA, IDX_DEVICE_TYPE, | |
1522 | TIMEOUT_IDENTIFY, &rdptr, NULL); | |
1523 | if (ret != SR_OK) | |
1524 | return ret; | |
1525 | sr_dbg("identify, device type '%s'", rdptr); | |
1526 | ||
1527 | /* Interpret the response (integer value, max freq). */ | |
1528 | endptr = NULL; | |
1529 | ret = sr_atoul_base(rdptr, &devtype, &endptr, 10); | |
1530 | if (ret != SR_OK || !endptr) | |
1531 | return SR_ERR_DATA; | |
1532 | devc->device.device_type = devtype; | |
1533 | ||
1534 | /* Transmit "read serial number" request. receive response. */ | |
1535 | ret = quick_send_read_then_recv(sdi, | |
1536 | INSN_READ_PARA, IDX_SERIAL_NUMBER, | |
1537 | 0, &rdptr, NULL); | |
1538 | if (ret != SR_OK) | |
1539 | return ret; | |
1540 | sr_dbg("identify, serial number '%s'", rdptr); | |
1541 | ||
1542 | /* Keep the response (in string format, some serial number). */ | |
1543 | devc->device.serial_number = g_strdup(rdptr); | |
1544 | ||
1545 | return SR_OK; | |
1546 | } | |
1547 | ||
1548 | SR_PRIV int jds6600_setup_devc(struct sr_dev_inst *sdi) | |
1549 | { | |
1550 | struct dev_context *devc; | |
1551 | size_t alloc_count, assign_idx, idx; | |
1552 | struct devc_dev *device; | |
1553 | struct devc_wave *waves; | |
1554 | enum waveform_index_t code; | |
1555 | char *name; | |
1556 | int ret; | |
1557 | ||
1558 | if (!sdi) | |
1559 | return SR_ERR_ARG; | |
1560 | devc = sdi->priv; | |
1561 | if (!devc) | |
1562 | return SR_ERR_ARG; | |
1563 | ||
1564 | /* | |
1565 | * Derive maximum output frequency from detected device type. | |
1566 | * Open coded generator channel count. | |
1567 | */ | |
1568 | device = &devc->device; | |
1569 | if (!device->device_type) | |
1570 | return SR_ERR_DATA; | |
1571 | device->max_output_frequency = device->device_type; | |
1572 | device->max_output_frequency *= SR_MHZ(1); | |
1573 | device->channel_count_gen = MAX_GEN_CHANNELS; | |
1574 | ||
1575 | /* Construct the list of waveform names and their codes. */ | |
1576 | waves = &devc->waveforms; | |
1577 | waves->builtin_count = WAVES_COUNT_BUILTIN; | |
1578 | waves->arbitrary_count = WAVES_COUNT_ARBITRARY; | |
1579 | alloc_count = waves->builtin_count; | |
1580 | alloc_count += waves->arbitrary_count; | |
1581 | waves->names_count = alloc_count; | |
1582 | waves->fw_codes = g_malloc0(alloc_count * sizeof(waves->fw_codes[0])); | |
1583 | alloc_count++; | |
1584 | waves->names = g_malloc0(alloc_count * sizeof(waves->names[0])); | |
1711287e GS |
1585 | if (!waves->names || !waves->fw_codes) { |
1586 | g_free(waves->names); | |
1587 | g_free(waves->fw_codes); | |
18baeeed | 1588 | return SR_ERR_MALLOC; |
1711287e | 1589 | } |
18baeeed GS |
1590 | assign_idx = 0; |
1591 | for (idx = 0; idx < waves->builtin_count; idx++) { | |
1592 | code = idx; | |
1593 | name = g_strdup(waveform_names[idx]); | |
1594 | waves->fw_codes[assign_idx] = code; | |
1595 | waves->names[assign_idx] = name; | |
1596 | assign_idx++; | |
1597 | } | |
1598 | for (idx = 0; idx < waves->arbitrary_count; idx++) { | |
1599 | code = WAVE_ARB01 + idx; | |
1600 | name = g_strdup_printf(WAVEFORM_ARB_NAME_FMT, idx + 1); | |
1601 | waves->fw_codes[assign_idx] = code; | |
1602 | waves->names[assign_idx] = name; | |
1603 | assign_idx++; | |
1604 | } | |
1605 | waves->names[assign_idx] = NULL; | |
1606 | ||
1607 | /* | |
1608 | * Populate internal channel configuration details from the | |
1609 | * device's current state. Emit a series of queries which | |
1610 | * update internal knowledge. | |
1711287e GS |
1611 | * |
1612 | * Implementation detail: Channel count is low, all parameters | |
1613 | * are simple scalars. Communication cycles are few, while we | |
1614 | * still are in the scan/probe phase and successfully verified | |
1615 | * the device to respond. Disconnects and other exceptional | |
1616 | * conditions are extremely unlikely. Not checking every getter | |
1617 | * call's return value is acceptable here. | |
18baeeed GS |
1618 | */ |
1619 | ret = SR_OK; | |
1620 | ret |= jds6600_get_chans_enable(sdi); | |
1621 | for (idx = 0; idx < device->channel_count_gen; idx++) { | |
1622 | ret |= jds6600_get_waveform(sdi, idx); | |
1623 | ret |= jds6600_get_frequency(sdi, idx); | |
1624 | ret |= jds6600_get_amplitude(sdi, idx); | |
1625 | ret |= jds6600_get_offset(sdi, idx); | |
1626 | ret |= jds6600_get_dutycycle(sdi, idx); | |
1711287e GS |
1627 | if (ret != SR_OK) |
1628 | break; | |
18baeeed GS |
1629 | } |
1630 | ret |= jds6600_get_phase_chans(sdi); | |
18baeeed GS |
1631 | if (ret != SR_OK) |
1632 | return SR_ERR_DATA; | |
1633 | ||
1634 | #if WITH_ARBWAVE_DOWNLOAD | |
1635 | /* | |
1636 | * Development HACK, to see how waveform upload works. | |
1637 | * How to forward the data to the application? Or the | |
1638 | * sigrok session actually? Provide these as acquisition | |
1639 | * results? | |
1640 | */ | |
1641 | ret |= jds6600_get_arb_waveform(sdi, 13); | |
1642 | if (ret != SR_OK) | |
1643 | return SR_ERR_DATA; | |
1644 | ret |= jds6600_set_arb_waveform(sdi, 12); | |
1645 | ret |= jds6600_set_arb_waveform(sdi, 13); | |
1646 | if (ret != SR_OK) | |
1647 | return SR_ERR_DATA; | |
1648 | #endif | |
b1fa9aac | 1649 | |
18baeeed | 1650 | return SR_OK; |
b1fa9aac | 1651 | } |