]> sigrok.org Git - libsigrok.git/blob - src/hardware/korad-kaxxxxp/protocol.c
input/stf: introduce support for Asix' Sigma Test File format
[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 prev_status;
262
263         g_mutex_lock(&devc->rw_mutex);
264         give_device_time_to_process(devc);
265
266         value = NULL;
267         count = 5;
268
269         switch (target) {
270         case KAXXXXP_CURRENT:
271                 /* Read current from device. */
272                 ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?");
273                 value = &(devc->current);
274                 break;
275         case KAXXXXP_CURRENT_LIMIT:
276                 /* Read set current from device. */
277                 ret = korad_kaxxxxp_send_cmd(serial, "ISET1?");
278                 value = &(devc->current_limit);
279                 break;
280         case KAXXXXP_VOLTAGE:
281                 /* Read voltage from device. */
282                 ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?");
283                 value = &(devc->voltage);
284                 break;
285         case KAXXXXP_VOLTAGE_TARGET:
286                 /* Read set voltage from device. */
287                 ret = korad_kaxxxxp_send_cmd(serial, "VSET1?");
288                 value = &(devc->voltage_target);
289                 break;
290         case KAXXXXP_STATUS:
291         case KAXXXXP_OUTPUT:
292         case KAXXXXP_OCP:
293         case KAXXXXP_OVP:
294                 /* Read status from device. */
295                 ret = korad_kaxxxxp_send_cmd(serial, "STATUS?");
296                 count = 1;
297                 break;
298         default:
299                 sr_err("Don't know how to query %d.", target);
300                 g_mutex_unlock(&devc->rw_mutex);
301                 return SR_ERR;
302         }
303
304         devc->req_sent_at = g_get_monotonic_time();
305
306         if ((ret = korad_kaxxxxp_read_chars(serial, count, reply)) < 0) {
307                 g_mutex_unlock(&devc->rw_mutex);
308                 return ret;
309         }
310
311         if (value) {
312                 sr_atof_ascii((const char *)&reply, value);
313                 sr_dbg("value: %f", *value);
314         } else {
315                 /* We have status reply. */
316                 status_byte = reply[0];
317
318                 /* Constant current channel one. */
319                 prev_status = devc->cc_mode[0];
320                 devc->cc_mode[0] = !(status_byte & (1 << 0));
321                 devc->cc_mode_1_changed = devc->cc_mode[0] != prev_status;
322                 /* Constant current channel two. */
323                 prev_status = devc->cc_mode[1];
324                 devc->cc_mode[1] = !(status_byte & (1 << 1));
325                 devc->cc_mode_2_changed = devc->cc_mode[1] != prev_status;
326
327                 /*
328                  * Tracking:
329                  * status_byte & ((1 << 2) | (1 << 3))
330                  * 00 independent 01 series 11 parallel
331                  */
332                 devc->beep_enabled = status_byte & (1 << 4);
333
334                 /* OCP enabled. */
335                 prev_status = devc->ocp_enabled;
336                 devc->ocp_enabled = status_byte & (1 << 5);
337                 devc->ocp_enabled_changed = devc->ocp_enabled != prev_status;
338
339                 /* Output status. */
340                 prev_status = devc->output_enabled;
341                 devc->output_enabled = status_byte & (1 << 6);
342                 devc->output_enabled_changed = devc->output_enabled != prev_status;
343
344                 /* OVP enabled, special handling for Velleman LABPS3005 quirk. */
345                 if ((devc->model->model_id == VELLEMAN_LABPS3005D && devc->output_enabled) ||
346                         devc->model->model_id != VELLEMAN_LABPS3005D) {
347
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 }