]> sigrok.org Git - libsigrok.git/blob - src/hardware/korad-kaxxxxp/protocol.c
korad-kaxxxxp: use ID text prefix with optional version for RND models
[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;
171         const char *cmd;
172         float value;
173         int ret;
174
175         g_mutex_lock(&devc->rw_mutex);
176         give_device_time_to_process(devc);
177
178         switch (target) {
179         case KAXXXXP_CURRENT:
180         case KAXXXXP_VOLTAGE:
181         case KAXXXXP_STATUS:
182                 sr_err("Can't set measurable parameter %d.", target);
183                 g_mutex_unlock(&devc->rw_mutex);
184                 return SR_ERR;
185         case KAXXXXP_CURRENT_LIMIT:
186                 cmd = "ISET1:%05.3f";
187                 value = devc->set_current_limit;
188                 break;
189         case KAXXXXP_VOLTAGE_TARGET:
190                 cmd = "VSET1:%05.2f";
191                 value = devc->set_voltage_target;
192                 break;
193         case KAXXXXP_OUTPUT:
194                 cmd = "OUT%01.0f";
195                 value = (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                 cmd = "BEEP%01.0f";
201                 value = (devc->set_beep_enabled) ? 1 : 0;
202                 break;
203         case KAXXXXP_OCP:
204                 cmd = "OCP%01.0f";
205                 value = (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                 cmd = "OVP%01.0f";
211                 value = (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                 cmd = "SAV%01.0f";
217                 if (devc->program < 1 || devc->program > 5) {
218                         sr_err("Only programs 1-5 supported and %d isn't "
219                                "between them.", devc->program);
220                         g_mutex_unlock(&devc->rw_mutex);
221                         return SR_ERR;
222                 }
223                 value = devc->program;
224                 break;
225         case KAXXXXP_RECALL:
226                 cmd = "RCL%01.0f";
227                 if (devc->program < 1 || devc->program > 5) {
228                         sr_err("Only programs 1-5 supported and %d isn't "
229                                "between them.", devc->program);
230                         g_mutex_unlock(&devc->rw_mutex);
231                         return SR_ERR;
232                 }
233                 value = devc->program;
234                 break;
235         default:
236                 sr_err("Don't know how to set %d.", target);
237                 g_mutex_unlock(&devc->rw_mutex);
238                 return SR_ERR;
239         }
240
241         msg = g_malloc0(20 + 1);
242         if (cmd)
243                 sr_snprintf_ascii(msg, 20, cmd, value);
244
245         ret = korad_kaxxxxp_send_cmd(serial, msg);
246         devc->req_sent_at = g_get_monotonic_time();
247         g_free(msg);
248
249         g_mutex_unlock(&devc->rw_mutex);
250
251         return ret;
252 }
253
254 SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial,
255                                 int target, struct dev_context *devc)
256 {
257         int ret, count;
258         char reply[6];
259         float *value;
260         char status_byte;
261         gboolean needs_ovp_quirk;
262         gboolean prev_status;
263
264         g_mutex_lock(&devc->rw_mutex);
265         give_device_time_to_process(devc);
266
267         value = NULL;
268         count = 5;
269
270         switch (target) {
271         case KAXXXXP_CURRENT:
272                 /* Read current from device. */
273                 ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?");
274                 value = &(devc->current);
275                 break;
276         case KAXXXXP_CURRENT_LIMIT:
277                 /* Read set current from device. */
278                 ret = korad_kaxxxxp_send_cmd(serial, "ISET1?");
279                 value = &(devc->current_limit);
280                 break;
281         case KAXXXXP_VOLTAGE:
282                 /* Read voltage from device. */
283                 ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?");
284                 value = &(devc->voltage);
285                 break;
286         case KAXXXXP_VOLTAGE_TARGET:
287                 /* Read set voltage from device. */
288                 ret = korad_kaxxxxp_send_cmd(serial, "VSET1?");
289                 value = &(devc->voltage_target);
290                 break;
291         case KAXXXXP_STATUS:
292         case KAXXXXP_OUTPUT:
293         case KAXXXXP_OCP:
294         case KAXXXXP_OVP:
295                 /* Read status from device. */
296                 ret = korad_kaxxxxp_send_cmd(serial, "STATUS?");
297                 count = 1;
298                 break;
299         default:
300                 sr_err("Don't know how to query %d.", target);
301                 ret = SR_ERR;
302         }
303         if (ret < 0) {
304                 g_mutex_unlock(&devc->rw_mutex);
305                 return ret;
306         }
307
308         devc->req_sent_at = g_get_monotonic_time();
309
310         if ((ret = korad_kaxxxxp_read_chars(serial, count, reply)) < 0) {
311                 g_mutex_unlock(&devc->rw_mutex);
312                 return ret;
313         }
314
315         if (value) {
316                 sr_atof_ascii((const char *)&reply, value);
317                 sr_dbg("value: %f", *value);
318         } else {
319                 /* We have status reply. */
320                 status_byte = reply[0];
321
322                 /* Constant current channel one. */
323                 prev_status = devc->cc_mode[0];
324                 devc->cc_mode[0] = !(status_byte & (1 << 0));
325                 devc->cc_mode_1_changed = devc->cc_mode[0] != prev_status;
326                 /* Constant current channel two. */
327                 prev_status = devc->cc_mode[1];
328                 devc->cc_mode[1] = !(status_byte & (1 << 1));
329                 devc->cc_mode_2_changed = devc->cc_mode[1] != prev_status;
330
331                 /*
332                  * Tracking:
333                  * status_byte & ((1 << 2) | (1 << 3))
334                  * 00 independent 01 series 11 parallel
335                  */
336                 devc->beep_enabled = status_byte & (1 << 4);
337
338                 /* OCP enabled. */
339                 prev_status = devc->ocp_enabled;
340                 devc->ocp_enabled = status_byte & (1 << 5);
341                 devc->ocp_enabled_changed = devc->ocp_enabled != prev_status;
342
343                 /* Output status. */
344                 prev_status = devc->output_enabled;
345                 devc->output_enabled = status_byte & (1 << 6);
346                 devc->output_enabled_changed = devc->output_enabled != prev_status;
347
348                 /* OVP enabled, special handling for Velleman LABPS3005 quirk. */
349                 needs_ovp_quirk = devc->model->quirks & KORAD_QUIRK_LABPS_OVP_EN;
350                 if (!needs_ovp_quirk || devc->output_enabled) {
351                         prev_status = devc->ovp_enabled;
352                         devc->ovp_enabled = status_byte & (1 << 7);
353                         devc->ovp_enabled_changed = devc->ovp_enabled != prev_status;
354                 }
355
356                 sr_dbg("Status: 0x%02x", status_byte);
357                 sr_spew("Status: CH1: constant %s CH2: constant %s. "
358                         "Tracking would be %s and %s. Output is %s. "
359                         "OCP is %s, OVP is %s. Device is %s.",
360                         (status_byte & (1 << 0)) ? "voltage" : "current",
361                         (status_byte & (1 << 1)) ? "voltage" : "current",
362                         (status_byte & (1 << 2)) ? "parallel" : "series",
363                         (status_byte & (1 << 3)) ? "tracking" : "independent",
364                         (status_byte & (1 << 6)) ? "enabled" : "disabled",
365                         (status_byte & (1 << 5)) ? "enabled" : "disabled",
366                         (status_byte & (1 << 7)) ? "enabled" : "disabled",
367                         (status_byte & (1 << 4)) ? "beeping" : "silent");
368         }
369
370         /* Read the sixth byte from ISET? BUG workaround. */
371         if (target == KAXXXXP_CURRENT_LIMIT)
372                 serial_read_blocking(serial, &status_byte, 1, 10);
373
374         g_mutex_unlock(&devc->rw_mutex);
375
376         return ret;
377 }
378
379 SR_PRIV int korad_kaxxxxp_get_all_values(struct sr_serial_dev_inst *serial,
380                                 struct dev_context *devc)
381 {
382         int ret, target;
383
384         for (target = KAXXXXP_CURRENT;
385                         target <= KAXXXXP_STATUS; target++) {
386                 if ((ret = korad_kaxxxxp_get_value(serial, target, devc)) < 0)
387                         return ret;
388         }
389
390         return ret;
391 }
392
393 static void next_measurement(struct dev_context *devc)
394 {
395         switch (devc->acquisition_target) {
396         case KAXXXXP_CURRENT:
397                 devc->acquisition_target = KAXXXXP_VOLTAGE;
398                 break;
399         case KAXXXXP_VOLTAGE:
400                 devc->acquisition_target = KAXXXXP_STATUS;
401                 break;
402         case KAXXXXP_STATUS:
403                 devc->acquisition_target = KAXXXXP_CURRENT;
404                 break;
405         default:
406                 devc->acquisition_target = KAXXXXP_CURRENT;
407                 sr_err("Invalid target for next acquisition.");
408         }
409 }
410
411 SR_PRIV int korad_kaxxxxp_receive_data(int fd, int revents, void *cb_data)
412 {
413         struct sr_dev_inst *sdi;
414         struct dev_context *devc;
415         struct sr_serial_dev_inst *serial;
416         struct sr_datafeed_packet packet;
417         struct sr_datafeed_analog analog;
418         struct sr_analog_encoding encoding;
419         struct sr_analog_meaning meaning;
420         struct sr_analog_spec spec;
421         GSList *l;
422
423         (void)fd;
424         (void)revents;
425
426         if (!(sdi = cb_data))
427                 return TRUE;
428
429         if (!(devc = sdi->priv))
430                 return TRUE;
431
432         serial = sdi->conn;
433
434         /* Get the value. */
435         korad_kaxxxxp_get_value(serial, devc->acquisition_target, devc);
436
437         /* Note: digits/spec_digits will be overridden later. */
438         sr_analog_init(&analog, &encoding, &meaning, &spec, 0);
439
440         /* Send the value forward. */
441         packet.type = SR_DF_ANALOG;
442         packet.payload = &analog;
443         analog.num_samples = 1;
444         l = g_slist_copy(sdi->channels);
445         if (devc->acquisition_target == KAXXXXP_CURRENT) {
446                 l = g_slist_remove_link(l, g_slist_nth(l, 0));
447                 analog.meaning->channels = l;
448                 analog.meaning->mq = SR_MQ_CURRENT;
449                 analog.meaning->unit = SR_UNIT_AMPERE;
450                 analog.meaning->mqflags = SR_MQFLAG_DC;
451                 analog.encoding->digits = 3;
452                 analog.spec->spec_digits = 3;
453                 analog.data = &devc->current;
454                 sr_session_send(sdi, &packet);
455         } else if (devc->acquisition_target == KAXXXXP_VOLTAGE) {
456                 l = g_slist_remove_link(l, g_slist_nth(l, 1));
457                 analog.meaning->channels = l;
458                 analog.meaning->mq = SR_MQ_VOLTAGE;
459                 analog.meaning->unit = SR_UNIT_VOLT;
460                 analog.meaning->mqflags = SR_MQFLAG_DC;
461                 analog.encoding->digits = 2;
462                 analog.spec->spec_digits = 2;
463                 analog.data = &devc->voltage;
464                 sr_session_send(sdi, &packet);
465                 sr_sw_limits_update_samples_read(&devc->limits, 1);
466         } else if (devc->acquisition_target == KAXXXXP_STATUS) {
467                 if (devc->cc_mode_1_changed) {
468                         sr_session_send_meta(sdi, SR_CONF_REGULATION,
469                                 g_variant_new_string((devc->cc_mode[0]) ? "CC" : "CV"));
470                         devc->cc_mode_1_changed = FALSE;
471                 }
472                 if (devc->cc_mode_2_changed) {
473                         sr_session_send_meta(sdi, SR_CONF_REGULATION,
474                                 g_variant_new_string((devc->cc_mode[1]) ? "CC" : "CV"));
475                         devc->cc_mode_2_changed = FALSE;
476                 }
477                 if (devc->output_enabled_changed) {
478                         sr_session_send_meta(sdi, SR_CONF_ENABLED,
479                                 g_variant_new_boolean(devc->output_enabled));
480                         devc->output_enabled_changed = FALSE;
481                 }
482                 if (devc->ocp_enabled_changed) {
483                         sr_session_send_meta(sdi, SR_CONF_OVER_CURRENT_PROTECTION_ENABLED,
484                                 g_variant_new_boolean(devc->ocp_enabled));
485                         devc->ocp_enabled_changed = FALSE;
486                 }
487                 if (devc->ovp_enabled_changed) {
488                         sr_session_send_meta(sdi, SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED,
489                                 g_variant_new_boolean(devc->ovp_enabled));
490                         devc->ovp_enabled_changed = FALSE;
491                 }
492         }
493         next_measurement(devc);
494
495         if (sr_sw_limits_check(&devc->limits))
496                 sr_dev_acquisition_stop(sdi);
497
498         return TRUE;
499 }