]> sigrok.org Git - libsigrok.git/blob - src/hardware/korad-kaxxxxp/protocol.c
korad-kaxxxxp: rephrase how config setter transmits commands to device
[libsigrok.git] / src / hardware / korad-kaxxxxp / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2015 Hannu Vuolasaho <vuokkosetae@gmail.com>
5  * Copyright (C) 2018-2019 Frank Stettner <frank-stettner@gmx.net>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include "protocol.h"
23
24 #define DEVICE_PROCESSING_TIME_MS 80
25
26 SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
27                                 const char *cmd)
28 {
29         int ret;
30
31         sr_dbg("Sending '%s'.", cmd);
32         if ((ret = serial_write_blocking(serial, cmd, strlen(cmd), 0)) < 0) {
33                 sr_err("Error sending command: %d.", ret);
34                 return ret;
35         }
36
37         return ret;
38 }
39
40 /**
41  * Read a variable length non-terminated string (caller specified maximum size).
42  *
43  * @param[in] serial The serial port to read from.
44  * @param[in] count The maximum amount of data to read.
45  * @param[out] buf The buffer to read data into. Must be larger than @a count.
46  *
47  * @return The amount of received data, or negative in case of error.
48  *     See @ref SR_ERR and other error codes.
49  *
50  * @internal
51  *
52  * The protocol has no concept of request/response termination. The only
53  * terminating conditions are either the caller's expected maxmimum byte
54  * count, or a period of time without receive data. It's essential to
55  * accept a longer initial period of time before the first receive data
56  * is seen. The supported devices can be very slow to respond.
57  *
58  * The protocol is text based. That's why the 'count' parameter specifies
59  * the expected number of text characters, and does not include the NUL
60  * termination which is not part of the wire protocol but gets added by
61  * the receive routine. The caller provided buffer is expected to have
62  * enough space for the text data and the NUL termination.
63  *
64  * Implementation detail: It's assumed that once receive data was seen,
65  * remaining response data will follow at wire speed. No further delays
66  * are expected beyond bitrate expectations. All normal commands in the
67  * acquisition phase are of fixed length which is known to the caller.
68  * Identification during device scan needs to deal with variable length
69  * data. Quick termination after reception is important there, as is the
70  * larger initial timeout period before receive data is seen.
71  */
72 SR_PRIV int korad_kaxxxxp_read_chars(struct sr_serial_dev_inst *serial,
73         size_t count, char *buf)
74 {
75         int timeout_first, timeout_later, timeout;
76         size_t retries_first, retries_later, retries;
77         size_t received;
78         int ret;
79
80         /* Clear the buffer early, to simplify the receive code path. */
81         memset(buf, 0, count + 1);
82
83         /*
84          * This calculation is aiming for backwards compatibility with
85          * an earlier implementation. An initial timeout is used which
86          * depends on the expected response byte count, and a maximum
87          * iteration count is used for read attempts.
88          *
89          * TODO Consider an absolute initial timeout instead, to reduce
90          * accumulated rounding errors for serial timeout results. The
91          * iteration with a short period is still required for variable
92          * length responses, because otherwise the serial communication
93          * layer would spend the total amount of time waiting for the
94          * remaining bytes, while the device probe code path by design
95          * passes a larger acceptable count than the typical and legal
96          * response would occupy.
97          *
98          * After initial receive data was seen, a shorter timeout is
99          * used which corresponds to a few bytes at wire speed. Idle
100          * periods without receive data longer than this threshold are
101          * taken as the end of the response. This is not compatible to
102          * the previous implementation, but was found to work as well.
103          * And severely reduces the time spent scanning for devices.
104          */
105         timeout_first = serial_timeout(serial, count);
106         retries_first = 100;
107         timeout_later = serial_timeout(serial, 3);
108         retries_later = 1;
109
110         sr_spew("want %zu bytes, timeout/retry: init %d/%zu, later %d/%zu.",
111                 count, timeout_first, retries_first,
112                 timeout_later, retries_later);
113
114         /*
115          * Run a sequence of read attempts. Try with the larger timeout
116          * and a high retry count until the first receive data became
117          * available. Then continue with a short timeout and small retry
118          * count.
119          *
120          * Failed read is fatal, immediately terminates the read sequence.
121          * A timeout in the initial phase just keeps repeating. A timeout
122          * after receive data was seen regularly terminates the sequence.
123          * Successful reads of non-empty responses keep extending the
124          * read sequence until no more receive data is available.
125          */
126         received = 0;
127         timeout = timeout_first;
128         retries = retries_first;
129         while (received < count && retries--) {
130                 ret = serial_read_blocking(serial,
131                         &buf[received], count - received, timeout);
132                 if (ret < 0) {
133                         sr_err("Error %d reading %zu bytes from device.",
134                                ret, count);
135                         return ret;
136                 }
137                 if (ret == 0 && !received)
138                         continue;
139                 if (ret == 0 && received) {
140                         sr_spew("receive timed out, want %zu, received %zu.",
141                                 count, received);
142                         break;
143                 }
144                 received += ret;
145                 timeout = timeout_later;
146                 retries = retries_later;
147         }
148         /* TODO Escape non-printables? Seen those with status queries. */
149         sr_dbg("got %zu bytes, received: '%s'.", received, buf);
150
151         return received;
152 }
153
154 static void give_device_time_to_process(struct dev_context *devc)
155 {
156         int64_t sleeping_time;
157
158         sleeping_time = devc->req_sent_at + (DEVICE_PROCESSING_TIME_MS * 1000);
159         sleeping_time -= g_get_monotonic_time();
160
161         if (sleeping_time > 0) {
162                 g_usleep(sleeping_time);
163                 sr_spew("Sleeping for processing %" PRIi64 " usec", sleeping_time);
164         }
165 }
166
167 SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
168                                 int target, struct dev_context *devc)
169 {
170         char msg[20];
171         int ret;
172
173         g_mutex_lock(&devc->rw_mutex);
174         give_device_time_to_process(devc);
175
176         msg[0] = '\0';
177         ret = SR_OK;
178         switch (target) {
179         case KAXXXXP_CURRENT:
180         case KAXXXXP_VOLTAGE:
181         case KAXXXXP_STATUS:
182                 sr_err("Can't set measured value %d.", target);
183                 ret = SR_ERR;
184                 break;
185         case KAXXXXP_CURRENT_LIMIT:
186                 sr_snprintf_ascii(msg, sizeof(msg),
187                         "ISET1:%05.3f", devc->set_current_limit);
188                 break;
189         case KAXXXXP_VOLTAGE_TARGET:
190                 sr_snprintf_ascii(msg, sizeof(msg),
191                         "VSET1:%05.2f", devc->set_voltage_target);
192                 break;
193         case KAXXXXP_OUTPUT:
194                 sr_snprintf_ascii(msg, sizeof(msg),
195                         "OUT%1d", (devc->set_output_enabled) ? 1 : 0);
196                 /* Set value back to recognize changes */
197                 devc->output_enabled = devc->set_output_enabled;
198                 break;
199         case KAXXXXP_BEEP:
200                 sr_snprintf_ascii(msg, sizeof(msg),
201                         "BEEP%1d", (devc->set_beep_enabled) ? 1 : 0);
202                 break;
203         case KAXXXXP_OCP:
204                 sr_snprintf_ascii(msg, sizeof(msg),
205                         "OCP%1d", (devc->set_ocp_enabled) ? 1 : 0);
206                 /* Set value back to recognize changes */
207                 devc->ocp_enabled = devc->set_ocp_enabled;
208                 break;
209         case KAXXXXP_OVP:
210                 sr_snprintf_ascii(msg, sizeof(msg),
211                         "OVP%1d", (devc->set_ovp_enabled) ? 1 : 0);
212                 /* Set value back to recognize changes */
213                 devc->ovp_enabled = devc->set_ovp_enabled;
214                 break;
215         case KAXXXXP_SAVE:
216                 if (devc->program < 1 || devc->program > 5) {
217                         sr_err("Program %d is not in the supported 1-5 range.",
218                                devc->program);
219                         ret = SR_ERR;
220                         break;
221                 }
222                 sr_snprintf_ascii(msg, sizeof(msg),
223                         "SAV%1d", devc->program);
224                 break;
225         case KAXXXXP_RECALL:
226                 if (devc->program < 1 || devc->program > 5) {
227                         sr_err("Program %d is not in the supported 1-5 range.",
228                                devc->program);
229                         ret = SR_ERR;
230                         break;
231                 }
232                 sr_snprintf_ascii(msg, sizeof(msg),
233                         "RCL%1d", devc->program);
234                 break;
235         default:
236                 sr_err("Don't know how to set target %d.", target);
237                 ret = SR_ERR;
238                 break;
239         }
240
241         if (ret == SR_OK && msg[0]) {
242                 ret = korad_kaxxxxp_send_cmd(serial, msg);
243                 devc->req_sent_at = g_get_monotonic_time();
244         }
245
246         g_mutex_unlock(&devc->rw_mutex);
247
248         return ret;
249 }
250
251 SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial,
252                                 int target, struct dev_context *devc)
253 {
254         int ret, count;
255         char reply[6];
256         float *value;
257         char status_byte;
258         gboolean needs_ovp_quirk;
259         gboolean prev_status;
260
261         g_mutex_lock(&devc->rw_mutex);
262         give_device_time_to_process(devc);
263
264         value = NULL;
265         count = 5;
266
267         switch (target) {
268         case KAXXXXP_CURRENT:
269                 /* Read current from device. */
270                 ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?");
271                 value = &(devc->current);
272                 break;
273         case KAXXXXP_CURRENT_LIMIT:
274                 /* Read set current from device. */
275                 ret = korad_kaxxxxp_send_cmd(serial, "ISET1?");
276                 value = &(devc->current_limit);
277                 break;
278         case KAXXXXP_VOLTAGE:
279                 /* Read voltage from device. */
280                 ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?");
281                 value = &(devc->voltage);
282                 break;
283         case KAXXXXP_VOLTAGE_TARGET:
284                 /* Read set voltage from device. */
285                 ret = korad_kaxxxxp_send_cmd(serial, "VSET1?");
286                 value = &(devc->voltage_target);
287                 break;
288         case KAXXXXP_STATUS:
289         case KAXXXXP_OUTPUT:
290         case KAXXXXP_OCP:
291         case KAXXXXP_OVP:
292                 /* Read status from device. */
293                 ret = korad_kaxxxxp_send_cmd(serial, "STATUS?");
294                 count = 1;
295                 break;
296         default:
297                 sr_err("Don't know how to query %d.", target);
298                 ret = SR_ERR;
299         }
300         if (ret < 0) {
301                 g_mutex_unlock(&devc->rw_mutex);
302                 return ret;
303         }
304
305         devc->req_sent_at = g_get_monotonic_time();
306
307         if ((ret = korad_kaxxxxp_read_chars(serial, count, reply)) < 0) {
308                 g_mutex_unlock(&devc->rw_mutex);
309                 return ret;
310         }
311
312         if (value) {
313                 sr_atof_ascii((const char *)&reply, value);
314                 sr_dbg("value: %f", *value);
315         } else {
316                 /* We have status reply. */
317                 status_byte = reply[0];
318
319                 /* Constant current channel one. */
320                 prev_status = devc->cc_mode[0];
321                 devc->cc_mode[0] = !(status_byte & (1 << 0));
322                 devc->cc_mode_1_changed = devc->cc_mode[0] != prev_status;
323                 /* Constant current channel two. */
324                 prev_status = devc->cc_mode[1];
325                 devc->cc_mode[1] = !(status_byte & (1 << 1));
326                 devc->cc_mode_2_changed = devc->cc_mode[1] != prev_status;
327
328                 /*
329                  * Tracking:
330                  * status_byte & ((1 << 2) | (1 << 3))
331                  * 00 independent 01 series 11 parallel
332                  */
333                 devc->beep_enabled = status_byte & (1 << 4);
334
335                 /* OCP enabled. */
336                 prev_status = devc->ocp_enabled;
337                 devc->ocp_enabled = status_byte & (1 << 5);
338                 devc->ocp_enabled_changed = devc->ocp_enabled != prev_status;
339
340                 /* Output status. */
341                 prev_status = devc->output_enabled;
342                 devc->output_enabled = status_byte & (1 << 6);
343                 devc->output_enabled_changed = devc->output_enabled != prev_status;
344
345                 /* OVP enabled, special handling for Velleman LABPS3005 quirk. */
346                 needs_ovp_quirk = devc->model->quirks & KORAD_QUIRK_LABPS_OVP_EN;
347                 if (!needs_ovp_quirk || devc->output_enabled) {
348                         prev_status = devc->ovp_enabled;
349                         devc->ovp_enabled = status_byte & (1 << 7);
350                         devc->ovp_enabled_changed = devc->ovp_enabled != prev_status;
351                 }
352
353                 sr_dbg("Status: 0x%02x", status_byte);
354                 sr_spew("Status: CH1: constant %s CH2: constant %s. "
355                         "Tracking would be %s and %s. Output is %s. "
356                         "OCP is %s, OVP is %s. Device is %s.",
357                         (status_byte & (1 << 0)) ? "voltage" : "current",
358                         (status_byte & (1 << 1)) ? "voltage" : "current",
359                         (status_byte & (1 << 2)) ? "parallel" : "series",
360                         (status_byte & (1 << 3)) ? "tracking" : "independent",
361                         (status_byte & (1 << 6)) ? "enabled" : "disabled",
362                         (status_byte & (1 << 5)) ? "enabled" : "disabled",
363                         (status_byte & (1 << 7)) ? "enabled" : "disabled",
364                         (status_byte & (1 << 4)) ? "beeping" : "silent");
365         }
366
367         /* Read the sixth byte from ISET? BUG workaround. */
368         if (target == KAXXXXP_CURRENT_LIMIT)
369                 serial_read_blocking(serial, &status_byte, 1, 10);
370
371         g_mutex_unlock(&devc->rw_mutex);
372
373         return ret;
374 }
375
376 SR_PRIV int korad_kaxxxxp_get_all_values(struct sr_serial_dev_inst *serial,
377                                 struct dev_context *devc)
378 {
379         int ret, target;
380
381         for (target = KAXXXXP_CURRENT;
382                         target <= KAXXXXP_STATUS; target++) {
383                 if ((ret = korad_kaxxxxp_get_value(serial, target, devc)) < 0)
384                         return ret;
385         }
386
387         return ret;
388 }
389
390 static void next_measurement(struct dev_context *devc)
391 {
392         switch (devc->acquisition_target) {
393         case KAXXXXP_CURRENT:
394                 devc->acquisition_target = KAXXXXP_VOLTAGE;
395                 break;
396         case KAXXXXP_VOLTAGE:
397                 devc->acquisition_target = KAXXXXP_STATUS;
398                 break;
399         case KAXXXXP_STATUS:
400                 devc->acquisition_target = KAXXXXP_CURRENT;
401                 break;
402         default:
403                 devc->acquisition_target = KAXXXXP_CURRENT;
404                 sr_err("Invalid target for next acquisition.");
405         }
406 }
407
408 SR_PRIV int korad_kaxxxxp_receive_data(int fd, int revents, void *cb_data)
409 {
410         struct sr_dev_inst *sdi;
411         struct dev_context *devc;
412         struct sr_serial_dev_inst *serial;
413         struct sr_datafeed_packet packet;
414         struct sr_datafeed_analog analog;
415         struct sr_analog_encoding encoding;
416         struct sr_analog_meaning meaning;
417         struct sr_analog_spec spec;
418         GSList *l;
419
420         (void)fd;
421         (void)revents;
422
423         if (!(sdi = cb_data))
424                 return TRUE;
425
426         if (!(devc = sdi->priv))
427                 return TRUE;
428
429         serial = sdi->conn;
430
431         /* Get the value. */
432         korad_kaxxxxp_get_value(serial, devc->acquisition_target, devc);
433
434         /* Note: digits/spec_digits will be overridden later. */
435         sr_analog_init(&analog, &encoding, &meaning, &spec, 0);
436
437         /* Send the value forward. */
438         packet.type = SR_DF_ANALOG;
439         packet.payload = &analog;
440         analog.num_samples = 1;
441         l = g_slist_copy(sdi->channels);
442         if (devc->acquisition_target == KAXXXXP_CURRENT) {
443                 l = g_slist_remove_link(l, g_slist_nth(l, 0));
444                 analog.meaning->channels = l;
445                 analog.meaning->mq = SR_MQ_CURRENT;
446                 analog.meaning->unit = SR_UNIT_AMPERE;
447                 analog.meaning->mqflags = SR_MQFLAG_DC;
448                 analog.encoding->digits = 3;
449                 analog.spec->spec_digits = 3;
450                 analog.data = &devc->current;
451                 sr_session_send(sdi, &packet);
452         } else if (devc->acquisition_target == KAXXXXP_VOLTAGE) {
453                 l = g_slist_remove_link(l, g_slist_nth(l, 1));
454                 analog.meaning->channels = l;
455                 analog.meaning->mq = SR_MQ_VOLTAGE;
456                 analog.meaning->unit = SR_UNIT_VOLT;
457                 analog.meaning->mqflags = SR_MQFLAG_DC;
458                 analog.encoding->digits = 2;
459                 analog.spec->spec_digits = 2;
460                 analog.data = &devc->voltage;
461                 sr_session_send(sdi, &packet);
462                 sr_sw_limits_update_samples_read(&devc->limits, 1);
463         } else if (devc->acquisition_target == KAXXXXP_STATUS) {
464                 if (devc->cc_mode_1_changed) {
465                         sr_session_send_meta(sdi, SR_CONF_REGULATION,
466                                 g_variant_new_string((devc->cc_mode[0]) ? "CC" : "CV"));
467                         devc->cc_mode_1_changed = FALSE;
468                 }
469                 if (devc->cc_mode_2_changed) {
470                         sr_session_send_meta(sdi, SR_CONF_REGULATION,
471                                 g_variant_new_string((devc->cc_mode[1]) ? "CC" : "CV"));
472                         devc->cc_mode_2_changed = FALSE;
473                 }
474                 if (devc->output_enabled_changed) {
475                         sr_session_send_meta(sdi, SR_CONF_ENABLED,
476                                 g_variant_new_boolean(devc->output_enabled));
477                         devc->output_enabled_changed = FALSE;
478                 }
479                 if (devc->ocp_enabled_changed) {
480                         sr_session_send_meta(sdi, SR_CONF_OVER_CURRENT_PROTECTION_ENABLED,
481                                 g_variant_new_boolean(devc->ocp_enabled));
482                         devc->ocp_enabled_changed = FALSE;
483                 }
484                 if (devc->ovp_enabled_changed) {
485                         sr_session_send_meta(sdi, SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED,
486                                 g_variant_new_boolean(devc->ovp_enabled));
487                         devc->ovp_enabled_changed = FALSE;
488                 }
489         }
490         next_measurement(devc);
491
492         if (sr_sw_limits_check(&devc->limits))
493                 sr_dev_acquisition_stop(sdi);
494
495         return TRUE;
496 }