]> sigrok.org Git - libsigrok.git/blob - src/hardware/itech-it8500/api.c
itech-it8500: declaration nits
[libsigrok.git] / src / hardware / itech-it8500 / api.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2020 Timo Kokkonen <tjko@iki.fi>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <string.h>
22 #include "protocol.h"
23
24 #define MIN_SAMPLE_RATE SR_HZ(1)
25 #define MAX_SAMPLE_RATE SR_HZ(60)
26 #define DEFAULT_SAMPLE_RATE SR_HZ(10)
27
28 static const uint32_t scanopts[] = {
29         SR_CONF_CONN,
30         SR_CONF_SERIALCOMM,
31 };
32
33 static const uint32_t drvopts[] = {
34         SR_CONF_ELECTRONIC_LOAD,
35 };
36
37 static const uint32_t devopts[] = {
38         SR_CONF_CONTINUOUS,
39         SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
40         SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
41         SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
42 };
43
44 static const uint32_t devopts_cg[] = {
45         SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
46         SR_CONF_REGULATION | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
47         SR_CONF_VOLTAGE | SR_CONF_GET,
48         SR_CONF_VOLTAGE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
49         SR_CONF_CURRENT | SR_CONF_GET,
50         SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
51         SR_CONF_POWER | SR_CONF_GET,
52         SR_CONF_POWER_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
53         SR_CONF_RESISTANCE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
54         SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED | SR_CONF_GET,
55         SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE | SR_CONF_GET,
56         SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD | SR_CONF_GET | SR_CONF_SET,
57         SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_GET,
58         SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE | SR_CONF_GET,
59         SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD | SR_CONF_GET | SR_CONF_SET,
60         SR_CONF_UNDER_VOLTAGE_CONDITION | SR_CONF_GET,
61         SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE | SR_CONF_GET,
62         SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD | SR_CONF_GET | SR_CONF_SET,
63         SR_CONF_OVER_TEMPERATURE_PROTECTION | SR_CONF_GET,
64         SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE | SR_CONF_GET,
65 };
66
67 static const uint64_t samplerates[] = {
68         SR_HZ(1),
69         SR_HZ(2),
70         SR_HZ(5),
71         SR_HZ(10),
72         SR_HZ(15),
73         SR_HZ(20),
74         SR_HZ(30),
75         SR_HZ(40),
76         SR_HZ(50),
77         SR_HZ(60),
78 };
79
80 static const char *default_serial_parameters[] = {
81         "9600/8n1", /* Factory default. */
82         "38400/8n1",
83         "19200/8n1",
84         "4800/8n1",
85         NULL,
86 };
87
88 static struct sr_dev_driver itech_it8500_driver_info;
89
90 static GSList *scan(struct sr_dev_driver *di, GSList *options)
91 {
92         struct sr_dev_inst *sdi;
93         struct sr_config *conf;
94         struct sr_serial_dev_inst *serial;
95         struct sr_channel_group *cg;
96         struct sr_channel *ch;
97         struct dev_context *devc;
98         const char *custom_serial_parameters[2];
99         const char **serial_parameters;
100         const char *conn, *serialcomm;
101         GSList *l;
102         struct itech_it8500_cmd_packet *cmd, *response;
103         uint8_t fw_major, fw_minor;
104         const uint8_t *p;
105         char *unit_model, *unit_serial, *unit_barcode;
106         double max_i, max_v, min_v, max_p, max_r, min_r;
107         uint64_t max_samplerate;
108
109         size_t u, i;
110         int ret;
111
112         cmd = g_malloc0(sizeof(*cmd));
113         devc = g_malloc0(sizeof(*devc));
114         sdi = g_malloc0(sizeof(*sdi));
115         if (!cmd || !devc || !sdi)
116                 return NULL;
117
118         serial = NULL;
119         response = NULL;
120         unit_model = NULL;
121         unit_serial = NULL;
122
123         /*
124          * Use a list of typical parameters for serial communication by
125          * default. Prefer user specified parameters when available.
126          * Lack of a user specified serial port is fatal.
127          */
128         conn = NULL;
129         serialcomm = NULL;
130         serial_parameters = default_serial_parameters;
131         for (l = options; l; l = l->next) {
132                 conf = l->data;
133                 switch (conf->key) {
134                 case SR_CONF_CONN:
135                         conn = g_variant_get_string(conf->data, NULL);
136                         break;
137                 case SR_CONF_SERIALCOMM:
138                         serialcomm = g_variant_get_string(conf->data, NULL);
139                         custom_serial_parameters[0] = serialcomm;
140                         custom_serial_parameters[1] = NULL;
141                         serial_parameters = custom_serial_parameters;
142                         break;
143                 }
144         }
145         if (!conn)
146                 goto error;
147
148         /*
149          * Try different serial parameters in the list
150          * until we get a response (or none at all).
151          */
152         sr_info("Probing serial port: %s", conn);
153         for (i = 0; (serialcomm = serial_parameters[i]); i++) {
154                 serial = sr_serial_dev_inst_new(conn, serialcomm);
155                 if (serial_open(serial, SERIAL_RDWR) != SR_OK)
156                         goto error;
157                 serial_flush(serial);
158
159                 cmd->address = 0xff; /* Use "broadcast" address. */
160                 cmd->command = CMD_GET_MODEL_INFO;
161                 if (itech_it8500_send_cmd(serial, cmd, &response) == SR_OK)
162                         break;
163
164                 serial_close(serial);
165                 sr_serial_dev_inst_free(serial);
166                 serial = NULL;
167         }
168         if (!serialcomm)
169                 goto error;
170
171         /*
172          * The "dense" response string consists of several fields. Grab
173          * integer data before putting terminators in their place to
174          * grab text strings afterwards. Order is important here.
175          */
176         devc->address = response->address;
177         fw_major = response->data[6];
178         fw_minor = response->data[5];
179         response->data[5] = 0;
180         unit_model = g_strdup((const char *)&response->data[0]);
181         response->data[17] = 0;
182         unit_serial = g_strdup((const char *)&response->data[7]);
183         sr_info("Model name: %s (v%x.%02x)", unit_model, fw_major, fw_minor);
184         sr_info("Address: %d", devc->address);
185         sr_info("Serial number: %s", unit_serial);
186
187         sdi->status = SR_ST_INACTIVE;
188         sdi->conn = serial;
189         sdi->inst_type = SR_INST_SERIAL;
190         sdi->driver = &itech_it8500_driver_info;
191         sdi->priv = devc;
192         g_mutex_init(&devc->mutex);
193
194         /*
195          * Calculate maxium "safe" sample rate based on serial connection
196          * speed / bitrate.
197          */
198         max_samplerate = serial->comm_params.bit_rate * 15 / 9600;
199         if (max_samplerate < 15)
200                 max_samplerate = 10;
201         if (max_samplerate > MAX_SAMPLE_RATE)
202                 max_samplerate = MAX_SAMPLE_RATE;
203         devc->max_sample_rate_idx = 0;
204         for (u = 0; u < ARRAY_SIZE(samplerates); u++) {
205                 if (samplerates[u] > max_samplerate)
206                         break;
207                 devc->max_sample_rate_idx = u;
208         }
209         devc->sample_rate = DEFAULT_SAMPLE_RATE;
210
211         /*
212          * Get full serial number (barcode).
213          */
214         cmd->address = devc->address;
215         cmd->command = CMD_GET_BARCODE_INFO;
216         if (itech_it8500_send_cmd(serial, cmd, &response) == SR_OK) {
217                 unit_barcode = g_malloc0(IT8500_DATA_LEN + 1);
218                 memcpy(unit_barcode, response->data, IT8500_DATA_LEN);
219                 sr_info("Barcode: %s", response->data);
220                 g_free(unit_barcode);
221         }
222
223         /*
224          * Query unit capabilities.
225          */
226         cmd->command = CMD_GET_LOAD_LIMITS;
227         if (itech_it8500_send_cmd(serial, cmd, &response) != SR_OK)
228                 goto error;
229         p = response->data;
230         max_i = read_u32le_inc(&p) / 10000.0;
231         max_v = read_u32le_inc(&p) / 1000.0;
232         min_v = read_u32le_inc(&p) / 1000.0;
233         max_p = read_u32le_inc(&p) / 1000.0;
234         max_r = read_u32le_inc(&p) / 1000.0;
235         min_r = read_u16le_inc(&p) / 1000.0;
236         sr_info("Max current: %.0f A", max_i);
237         sr_info("Max power: %.0f W", max_p);
238         sr_info("Voltage range: %.1f - %.1f V", min_v, max_v);
239         sr_info("Resistance range: %.2f - %.2f Ohm", min_r, max_r);
240
241         /*
242          * Get current status of the unit.
243          */
244         if ((ret = itech_it8500_get_status(sdi)) != SR_OK) {
245                 sr_err("Failed to get unit status: %d", ret);
246                 goto error;
247         }
248         sr_info("Mode: %s", itech_it8500_mode_to_string(devc->mode));
249         sr_info("State: %s", devc->load_on ? "ON" : "OFF");
250         sr_info("Default sample rate: %" PRIu64 " Hz", devc->sample_rate);
251         sr_info("Maximum sample rate: %" PRIu64 " Hz",
252                 samplerates[devc->max_sample_rate_idx]);
253
254         /*
255          * Populate data structures.
256          */
257
258         devc->fw_ver_major = fw_major;
259         devc->fw_ver_minor = fw_minor;
260         snprintf(devc->model, sizeof(devc->model), "%s", unit_model);
261         devc->max_current = max_i;
262         devc->min_voltage = min_v;
263         devc->max_voltage = max_v;
264         devc->max_power = max_p;
265         devc->min_resistance = min_r;
266         devc->max_resistance = max_r;
267
268         sdi->vendor = g_strdup("ITECH");
269         sdi->model = unit_model;
270         sdi->version = g_strdup_printf("%x.%02x", fw_major, fw_minor);
271         sdi->serial_num = unit_serial;
272
273         cg = g_malloc0(sizeof(*cg));
274         cg->name = g_strdup("1");
275         sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
276         ch = sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "V1");
277         cg->channels = g_slist_append(cg->channels, ch);
278         ch = sr_channel_new(sdi, 1, SR_CHANNEL_ANALOG, TRUE, "I1");
279         cg->channels = g_slist_append(cg->channels, ch);
280         ch = sr_channel_new(sdi, 2, SR_CHANNEL_ANALOG, TRUE, "P1");
281         cg->channels = g_slist_append(cg->channels, ch);
282
283         g_free(cmd);
284         g_free(response);
285         serial_close(serial);
286
287         return std_scan_complete(di, g_slist_append(NULL, sdi));
288
289 error:
290         g_free(cmd);
291         g_free(devc);
292         g_free(sdi);
293         g_free(response);
294         g_free(unit_model);
295         g_free(unit_serial);
296         if (serial) {
297                 serial_close(serial);
298                 sr_serial_dev_inst_free(serial);
299         }
300
301         return NULL;
302 }
303
304 static int config_get(uint32_t key, GVariant **data,
305                 const struct sr_dev_inst *sdi,
306                 const struct sr_channel_group *cg)
307 {
308         struct dev_context *devc;
309         const struct sr_key_info *kinfo;
310         const char *mode;
311         int ret, ival;
312         gboolean bval;
313
314         (void)cg;
315
316         if (!data || !sdi)
317                 return SR_ERR_ARG;
318
319         devc = sdi->priv;
320         kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
321         ret = SR_OK;
322
323         switch (key) {
324         case SR_CONF_LIMIT_SAMPLES:
325         case SR_CONF_LIMIT_MSEC:
326                 ret = sr_sw_limits_config_get(&devc->limits, key, data);
327                 break;
328         case SR_CONF_SAMPLERATE:
329                 *data = g_variant_new_uint64(devc->sample_rate);
330                 break;
331         case SR_CONF_ENABLED:
332                 ret = itech_it8500_get_status(sdi);
333                 if (ret != SR_OK)
334                         break;
335                 *data = g_variant_new_boolean(devc->load_on);
336                 break;
337         case SR_CONF_REGULATION:
338                 ret = itech_it8500_get_status(sdi);
339                 if (ret != SR_OK)
340                         break;
341                 mode = itech_it8500_mode_to_string(devc->mode);
342                 *data = g_variant_new_string(mode);
343                 break;
344         case SR_CONF_VOLTAGE:
345                 ret = itech_it8500_get_status(sdi);
346                 if (ret != SR_OK)
347                         break;
348                 *data = g_variant_new_double(devc->voltage);
349                 break;
350         case SR_CONF_VOLTAGE_TARGET:
351                 ret = itech_it8500_get_int(sdi, CMD_GET_CV_VOLTAGE, &ival);
352                 if (ret != SR_OK)
353                         break;
354                 *data = g_variant_new_double((double)ival / 1000.0);
355                 break;
356         case SR_CONF_CURRENT:
357                 ret = itech_it8500_get_status(sdi);
358                 if (ret != SR_OK)
359                         break;
360                 *data = g_variant_new_double(devc->current);
361                 break;
362         case SR_CONF_CURRENT_LIMIT:
363                 ret = itech_it8500_get_int(sdi, CMD_GET_CC_CURRENT, &ival);
364                 if (ret != SR_OK)
365                         break;
366                 *data = g_variant_new_double((double)ival / 10000.0);
367                 break;
368         case SR_CONF_POWER:
369                 ret = itech_it8500_get_status(sdi);
370                 if (ret != SR_OK)
371                         break;
372                 *data = g_variant_new_double(devc->power);
373                 break;
374         case SR_CONF_POWER_TARGET:
375                 ret = itech_it8500_get_int(sdi, CMD_GET_CW_POWER, &ival);
376                 if (ret != SR_OK)
377                         break;
378                 *data = g_variant_new_double((double)ival / 1000.0);
379                 break;
380         case SR_CONF_RESISTANCE_TARGET:
381                 ret = itech_it8500_get_int(sdi, CMD_GET_CR_RESISTANCE, &ival);
382                 if (ret != SR_OK)
383                         break;
384                 *data = g_variant_new_double((double)ival / 1000.0);
385                 break;
386         case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
387                 *data = g_variant_new_boolean(TRUE);
388                 break;
389         case SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE:
390                 ret = itech_it8500_get_status(sdi);
391                 if (ret != SR_OK)
392                         break;
393                 bval = devc->demand_state & DS_OV_FLAG;
394                 *data = g_variant_new_boolean(bval);
395                 break;
396         case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
397                 ret = itech_it8500_get_int(sdi, CMD_GET_MAX_VOLTAGE, &ival);
398                 if (ret != SR_OK)
399                         break;
400                 *data = g_variant_new_double((double)ival / 1000.0);
401                 break;
402         case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
403                 *data = g_variant_new_boolean(TRUE);
404                 break;
405         case SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE:
406                 ret = itech_it8500_get_status(sdi);
407                 if (ret != SR_OK)
408                         break;
409                 bval = devc->demand_state & DS_OC_FLAG;
410                 *data = g_variant_new_boolean(bval);
411                 break;
412         case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
413                 ret = itech_it8500_get_int(sdi, CMD_GET_MAX_CURRENT, &ival);
414                 if (ret != SR_OK)
415                         break;
416                 *data = g_variant_new_double((double)ival / 10000.0);
417                 break;
418         case SR_CONF_OVER_TEMPERATURE_PROTECTION:
419                 *data = g_variant_new_boolean(TRUE);
420                 break;
421         case SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE:
422                 ret = itech_it8500_get_status(sdi);
423                 if (ret != SR_OK)
424                         break;
425                 bval = devc->demand_state & DS_OT_FLAG;
426                 *data = g_variant_new_boolean(bval);
427                 break;
428         /* Hardware doesn't support under voltage reporting. */
429         case SR_CONF_UNDER_VOLTAGE_CONDITION:
430         case SR_CONF_UNDER_VOLTAGE_CONDITION_ACTIVE:
431                 *data = g_variant_new_boolean(FALSE);
432                 break;
433         case SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD:
434                 *data = g_variant_new_double(0.0);
435                 break;
436         default:
437                 sr_dbg("%s: Unsupported key: %u (%s)", __func__, key,
438                         kinfo ? kinfo->name : "unknown");
439                 ret = SR_ERR_NA;
440                 break;
441         }
442
443         return ret;
444 }
445
446 static int config_set(uint32_t key, GVariant *data,
447                 const struct sr_dev_inst *sdi,
448                 const struct sr_channel_group *cg)
449 {
450         struct dev_context *devc;
451         struct itech_it8500_cmd_packet *cmd, *response;
452         const struct sr_key_info *kinfo;
453         enum itech_it8500_modes mode;
454         int ret, ivalue;
455         uint64_t new_sr;
456         const char *s;
457
458         (void)cg;
459
460         if (!data || !sdi)
461                 return SR_ERR_ARG;
462
463         cmd = g_malloc0(sizeof(*cmd));
464         if (!cmd)
465                 return SR_ERR_MALLOC;
466
467         devc = sdi->priv;
468         response = NULL;
469         ret = SR_OK;
470
471         kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
472
473         switch (key) {
474         case SR_CONF_LIMIT_MSEC:
475         case SR_CONF_LIMIT_SAMPLES:
476                 ret = sr_sw_limits_config_set(&devc->limits, key, data);
477                 break;
478         case SR_CONF_SAMPLERATE:
479                 new_sr = g_variant_get_uint64(data);
480                 if (new_sr < MIN_SAMPLE_RATE) {
481                         ret = SR_ERR_SAMPLERATE;
482                         break;
483                 }
484                 if (new_sr > samplerates[devc->max_sample_rate_idx]) {
485                         ret = SR_ERR_SAMPLERATE;
486                         break;
487                 }
488                 devc->sample_rate = new_sr;
489                 break;
490         case SR_CONF_ENABLED:
491                 cmd->command = CMD_LOAD_ON_OFF;
492                 cmd->data[0] = g_variant_get_boolean(data);
493                 break;
494         case SR_CONF_REGULATION:
495                 s = g_variant_get_string(data, NULL);
496                 if (itech_it8500_string_to_mode(s, &mode) != SR_OK) {
497                         ret = SR_ERR_ARG;
498                         break;
499                 }
500                 cmd->command = CMD_SET_MODE;
501                 cmd->data[0] = mode;
502                 break;
503         case SR_CONF_VOLTAGE_TARGET:
504                 cmd->command = CMD_SET_CV_VOLTAGE;
505                 ivalue = g_variant_get_double(data) * 1000.0;
506                 WL32(&cmd->data[0], ivalue);
507                 break;
508         case SR_CONF_CURRENT_LIMIT:
509                 cmd->command = CMD_SET_CC_CURRENT;
510                 ivalue = g_variant_get_double(data) * 10000.0;
511                 WL32(&cmd->data[0], ivalue);
512                 break;
513         case SR_CONF_POWER_TARGET:
514                 cmd->command = CMD_SET_CW_POWER;
515                 ivalue = g_variant_get_double(data) * 1000.0;
516                 WL32(&cmd->data[0], ivalue);
517                 break;
518         case SR_CONF_RESISTANCE_TARGET:
519                 cmd->command = CMD_SET_CR_RESISTANCE;
520                 ivalue = g_variant_get_double(data) * 1000.0;
521                 WL32(&cmd->data[0], ivalue);
522                 break;
523         case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
524                 cmd->command = CMD_SET_MAX_VOLTAGE;
525                 ivalue = g_variant_get_double(data) * 1000.0;
526                 WL32(&cmd->data[0], ivalue);
527                 break;
528         case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
529                 cmd->command = CMD_SET_MAX_CURRENT;
530                 ivalue = g_variant_get_double(data) * 10000.0;
531                 WL32(&cmd->data[0], ivalue);
532                 break;
533         default:
534                 sr_dbg("%s: Unsupported key: %u (%s)", __func__, key,
535                         kinfo ? kinfo->name : "unknown");
536                 ret = SR_ERR_NA;
537                 break;
538         }
539
540         if (ret == SR_OK && cmd->command) {
541                 cmd->address = devc->address;
542                 ret = itech_it8500_cmd(sdi, cmd, &response);
543         }
544
545         g_free(cmd);
546         g_free(response);
547
548         return ret;
549 }
550
551 static int config_list(uint32_t key, GVariant **data,
552                 const struct sr_dev_inst *sdi,
553                 const struct sr_channel_group *cg)
554 {
555         const struct dev_context *devc;
556         const struct sr_key_info *kinfo;
557         GVariantBuilder *b;
558
559         devc = sdi ? sdi->priv : NULL;
560         if (!data)
561                 return SR_ERR_ARG;
562
563         if (!cg)
564                 return STD_CONFIG_LIST(key, data, sdi, cg,
565                         scanopts, drvopts, devopts);
566
567         kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
568
569         switch (key) {
570         case SR_CONF_DEVICE_OPTIONS:
571                 *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg));
572                 break;
573         case SR_CONF_SAMPLERATE:
574                 *data = std_gvar_samplerates_steps(samplerates,
575                                 1 + devc->max_sample_rate_idx);
576                 break;
577         case SR_CONF_REGULATION:
578                 b = g_variant_builder_new(G_VARIANT_TYPE("as"));
579                 g_variant_builder_add(b, "s", itech_it8500_mode_to_string(CC));
580                 g_variant_builder_add(b, "s", itech_it8500_mode_to_string(CV));
581                 g_variant_builder_add(b, "s", itech_it8500_mode_to_string(CW));
582                 g_variant_builder_add(b, "s", itech_it8500_mode_to_string(CR));
583                 *data = g_variant_new("as", b);
584                 g_variant_builder_unref(b);
585                 break;
586         case SR_CONF_VOLTAGE_TARGET:
587                 if (!devc)
588                         return SR_ERR_ARG;
589                 *data = std_gvar_min_max_step(devc->min_voltage,
590                                 devc->max_voltage, 0.01);
591                 break;
592         case SR_CONF_CURRENT_LIMIT:
593                 if (!devc)
594                         return SR_ERR_ARG;
595                 *data = std_gvar_min_max_step(0.0, devc->max_current, 0.001);
596                 break;
597         case SR_CONF_POWER_TARGET:
598                 if (!devc)
599                         return SR_ERR_ARG;
600                 *data = std_gvar_min_max_step(0.0, devc->max_power, 0.01);
601                 break;
602         case SR_CONF_RESISTANCE_TARGET:
603                 if (!devc)
604                         return SR_ERR_ARG;
605                 *data = std_gvar_min_max_step(devc->min_resistance,
606                                 devc->max_resistance, 0.01);
607                 break;
608
609         default:
610                 sr_dbg("%s: Unsupported key: %u (%s)", __func__, key,
611                         kinfo ? kinfo->name : "unknown");
612                 return SR_ERR_NA;
613         }
614
615         return SR_OK;
616 }
617
618 static int dev_acquisition_start(const struct sr_dev_inst *sdi)
619 {
620         struct dev_context *devc;
621         struct sr_serial_dev_inst *serial;
622         int ret;
623
624         if (!sdi)
625                 return SR_ERR_ARG;
626
627         devc = sdi->priv;
628         serial = sdi->conn;
629
630         ret = serial_source_add(sdi->session, serial,
631                         G_IO_IN, (1000.0 / devc->sample_rate),
632                         itech_it8500_receive_data, (void *)sdi);
633         if (ret == SR_OK) {
634                 sr_sw_limits_acquisition_start(&devc->limits);
635                 std_session_send_df_header(sdi);
636         }
637
638         return ret;
639 }
640
641 static int dev_acquisition_stop(struct sr_dev_inst *sdi)
642 {
643         struct sr_serial_dev_inst *serial;
644
645         if (!sdi)
646                 return SR_ERR_ARG;
647
648         serial = sdi->conn;
649
650         std_session_send_df_end(sdi);
651         serial_source_remove(sdi->session, serial);
652
653         return SR_OK;
654 }
655
656 static int dev_open(struct sr_dev_inst *sdi)
657 {
658         struct dev_context *devc;
659         struct itech_it8500_cmd_packet *cmd, *response;
660         int ret, res;
661
662         if (!sdi)
663                 return SR_ERR_ARG;
664
665         devc = sdi->priv;
666         ret = std_serial_dev_open(sdi);
667         if (ret == SR_OK) {
668                 /* Request the unit to enter remote control mode. */
669                 response = NULL;
670                 cmd = g_malloc0(sizeof(*cmd));
671                 if (cmd) {
672                         cmd->address = devc->address;
673                         cmd->command = CMD_SET_REMOTE_MODE;
674                         cmd->data[0] = 1;
675                         res = itech_it8500_cmd(sdi, cmd, &response);
676                         if (res != SR_OK)
677                                 sr_dbg("Failed to set unit to remote mode");
678                         g_free(cmd);
679                         g_free(response);
680                 }
681         }
682
683         return ret;
684 }
685
686 static int dev_close(struct sr_dev_inst *sdi)
687 {
688         struct dev_context *devc;
689         struct itech_it8500_cmd_packet *cmd, *response;
690         int ret;
691
692         if (!sdi)
693                 return SR_ERR_ARG;
694
695         devc = sdi->priv;
696         response = NULL;
697         cmd = g_malloc0(sizeof(*cmd));
698         if (cmd) {
699                 /* Request the unit to enter local control mode. */
700                 cmd->address = devc->address;
701                 cmd->command = CMD_SET_REMOTE_MODE;
702                 cmd->data[0] = 0;
703                 ret = itech_it8500_cmd(sdi, cmd, &response);
704                 if (ret != SR_OK)
705                         sr_dbg("Failed to set unit back to local mode: %d",
706                                 ret);
707         }
708
709         g_free(cmd);
710         g_free(response);
711
712         return std_serial_dev_close(sdi);
713 }
714
715 static void dev_clear_callback(void *priv)
716 {
717         struct dev_context *devc;
718
719         if (!priv)
720                 return;
721
722         devc = priv;
723         g_mutex_clear(&devc->mutex);
724 }
725
726 static int dev_clear(const struct sr_dev_driver *di)
727 {
728         return std_dev_clear_with_callback(di, dev_clear_callback);
729 }
730
731 static struct sr_dev_driver itech_it8500_driver_info = {
732         .name = "itech-it8500",
733         .longname = "ITECH IT8500 series",
734         .api_version = 1,
735         .init = std_init,
736         .cleanup = std_cleanup,
737         .scan = scan,
738         .dev_list = std_dev_list,
739         .dev_clear = dev_clear,
740         .config_get = config_get,
741         .config_set = config_set,
742         .config_list = config_list,
743         .dev_open = dev_open,
744         .dev_close = dev_close,
745         .dev_acquisition_start = dev_acquisition_start,
746         .dev_acquisition_stop = dev_acquisition_stop,
747         .context = NULL,
748 };
749 SR_REGISTER_DEV_DRIVER(itech_it8500_driver_info);