2 * This file is part of the libsigrok project.
4 * Copyright (C) 2020 Timo Kokkonen <tjko@iki.fi>
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.
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.
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/>.
24 #define MIN_SAMPLE_RATE SR_HZ(1)
25 #define MAX_SAMPLE_RATE SR_HZ(60)
26 #define DEFAULT_SAMPLE_RATE SR_HZ(10)
28 static const uint32_t scanopts[] = {
33 static const uint32_t drvopts[] = {
34 SR_CONF_ELECTRONIC_LOAD,
37 static const uint32_t devopts[] = {
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,
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,
67 static const uint64_t samplerates[] = {
80 static const char *default_serial_parameters[] = {
81 "9600/8n1", /* Factory default. */
88 static struct sr_dev_driver itech_it8500_driver_info;
90 static GSList *scan(struct sr_dev_driver *di, GSList *options)
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;
102 struct itech_it8500_cmd_packet *cmd, *response;
103 uint8_t fw_major, fw_minor;
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;
112 cmd = g_malloc0(sizeof(*cmd));
113 devc = g_malloc0(sizeof(*devc));
114 sdi = g_malloc0(sizeof(*sdi));
115 if (!cmd || !devc || !sdi)
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.
130 serial_parameters = default_serial_parameters;
131 for (l = options; l; l = l->next) {
135 conn = g_variant_get_string(conf->data, NULL);
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;
149 * Try different serial parameters in the list
150 * until we get a response (or none at all).
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)
157 serial_flush(serial);
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)
164 serial_close(serial);
165 sr_serial_dev_inst_free(serial);
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.
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);
187 sdi->status = SR_ST_INACTIVE;
189 sdi->inst_type = SR_INST_SERIAL;
190 sdi->driver = &itech_it8500_driver_info;
192 g_mutex_init(&devc->mutex);
195 * Calculate maxium "safe" sample rate based on serial connection
198 max_samplerate = serial->comm_params.bit_rate * 15 / 9600;
199 if (max_samplerate < 15)
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)
207 devc->max_sample_rate_idx = u;
209 devc->sample_rate = DEFAULT_SAMPLE_RATE;
212 * Get full serial number (barcode).
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);
224 * Query unit capabilities.
226 cmd->command = CMD_GET_LOAD_LIMITS;
227 if (itech_it8500_send_cmd(serial, cmd, &response) != SR_OK)
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);
242 * Get current status of the unit.
244 if ((ret = itech_it8500_get_status(sdi)) != SR_OK) {
245 sr_err("Failed to get unit status: %d", ret);
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]);
255 * Populate data structures.
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;
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;
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);
285 serial_close(serial);
287 return std_scan_complete(di, g_slist_append(NULL, sdi));
297 serial_close(serial);
298 sr_serial_dev_inst_free(serial);
304 static int config_get(uint32_t key, GVariant **data,
305 const struct sr_dev_inst *sdi,
306 const struct sr_channel_group *cg)
308 struct dev_context *devc;
309 const struct sr_key_info *kinfo;
320 kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
324 case SR_CONF_LIMIT_SAMPLES:
325 case SR_CONF_LIMIT_MSEC:
326 ret = sr_sw_limits_config_get(&devc->limits, key, data);
328 case SR_CONF_SAMPLERATE:
329 *data = g_variant_new_uint64(devc->sample_rate);
331 case SR_CONF_ENABLED:
332 ret = itech_it8500_get_status(sdi);
335 *data = g_variant_new_boolean(devc->load_on);
337 case SR_CONF_REGULATION:
338 ret = itech_it8500_get_status(sdi);
341 mode = itech_it8500_mode_to_string(devc->mode);
342 *data = g_variant_new_string(mode);
344 case SR_CONF_VOLTAGE:
345 ret = itech_it8500_get_status(sdi);
348 *data = g_variant_new_double(devc->voltage);
350 case SR_CONF_VOLTAGE_TARGET:
351 ret = itech_it8500_get_int(sdi, CMD_GET_CV_VOLTAGE, &ival);
354 *data = g_variant_new_double((double)ival / 1000.0);
356 case SR_CONF_CURRENT:
357 ret = itech_it8500_get_status(sdi);
360 *data = g_variant_new_double(devc->current);
362 case SR_CONF_CURRENT_LIMIT:
363 ret = itech_it8500_get_int(sdi, CMD_GET_CC_CURRENT, &ival);
366 *data = g_variant_new_double((double)ival / 10000.0);
369 ret = itech_it8500_get_status(sdi);
372 *data = g_variant_new_double(devc->power);
374 case SR_CONF_POWER_TARGET:
375 ret = itech_it8500_get_int(sdi, CMD_GET_CW_POWER, &ival);
378 *data = g_variant_new_double((double)ival / 1000.0);
380 case SR_CONF_RESISTANCE_TARGET:
381 ret = itech_it8500_get_int(sdi, CMD_GET_CR_RESISTANCE, &ival);
384 *data = g_variant_new_double((double)ival / 1000.0);
386 case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED:
387 *data = g_variant_new_boolean(TRUE);
389 case SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE:
390 ret = itech_it8500_get_status(sdi);
393 bval = devc->demand_state & DS_OV_FLAG;
394 *data = g_variant_new_boolean(bval);
396 case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD:
397 ret = itech_it8500_get_int(sdi, CMD_GET_MAX_VOLTAGE, &ival);
400 *data = g_variant_new_double((double)ival / 1000.0);
402 case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
403 *data = g_variant_new_boolean(TRUE);
405 case SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE:
406 ret = itech_it8500_get_status(sdi);
409 bval = devc->demand_state & DS_OC_FLAG;
410 *data = g_variant_new_boolean(bval);
412 case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD:
413 ret = itech_it8500_get_int(sdi, CMD_GET_MAX_CURRENT, &ival);
416 *data = g_variant_new_double((double)ival / 10000.0);
418 case SR_CONF_OVER_TEMPERATURE_PROTECTION:
419 *data = g_variant_new_boolean(TRUE);
421 case SR_CONF_OVER_TEMPERATURE_PROTECTION_ACTIVE:
422 ret = itech_it8500_get_status(sdi);
425 bval = devc->demand_state & DS_OT_FLAG;
426 *data = g_variant_new_boolean(bval);
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);
433 case SR_CONF_UNDER_VOLTAGE_CONDITION_THRESHOLD:
434 *data = g_variant_new_double(0.0);
437 sr_dbg("%s: Unsupported key: %u (%s)", __func__, key,
438 kinfo ? kinfo->name : "unknown");
446 static int config_set(uint32_t key, GVariant *data,
447 const struct sr_dev_inst *sdi,
448 const struct sr_channel_group *cg)
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;
463 cmd = g_malloc0(sizeof(*cmd));
465 return SR_ERR_MALLOC;
471 kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
474 case SR_CONF_LIMIT_MSEC:
475 case SR_CONF_LIMIT_SAMPLES:
476 ret = sr_sw_limits_config_set(&devc->limits, key, data);
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;
484 if (new_sr > samplerates[devc->max_sample_rate_idx]) {
485 ret = SR_ERR_SAMPLERATE;
488 devc->sample_rate = new_sr;
490 case SR_CONF_ENABLED:
491 cmd->command = CMD_LOAD_ON_OFF;
492 cmd->data[0] = g_variant_get_boolean(data);
494 case SR_CONF_REGULATION:
495 s = g_variant_get_string(data, NULL);
496 if (itech_it8500_string_to_mode(s, &mode) != SR_OK) {
500 cmd->command = CMD_SET_MODE;
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);
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);
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);
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);
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);
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);
534 sr_dbg("%s: Unsupported key: %u (%s)", __func__, key,
535 kinfo ? kinfo->name : "unknown");
540 if (ret == SR_OK && cmd->command) {
541 cmd->address = devc->address;
542 ret = itech_it8500_cmd(sdi, cmd, &response);
551 static int config_list(uint32_t key, GVariant **data,
552 const struct sr_dev_inst *sdi,
553 const struct sr_channel_group *cg)
555 const struct dev_context *devc;
556 const struct sr_key_info *kinfo;
559 devc = sdi ? sdi->priv : NULL;
564 return STD_CONFIG_LIST(key, data, sdi, cg,
565 scanopts, drvopts, devopts);
567 kinfo = sr_key_info_get(SR_KEY_CONFIG, key);
570 case SR_CONF_DEVICE_OPTIONS:
571 *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg));
573 case SR_CONF_SAMPLERATE:
574 *data = std_gvar_samplerates_steps(samplerates,
575 1 + devc->max_sample_rate_idx);
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);
586 case SR_CONF_VOLTAGE_TARGET:
589 *data = std_gvar_min_max_step(devc->min_voltage,
590 devc->max_voltage, 0.01);
592 case SR_CONF_CURRENT_LIMIT:
595 *data = std_gvar_min_max_step(0.0, devc->max_current, 0.001);
597 case SR_CONF_POWER_TARGET:
600 *data = std_gvar_min_max_step(0.0, devc->max_power, 0.01);
602 case SR_CONF_RESISTANCE_TARGET:
605 *data = std_gvar_min_max_step(devc->min_resistance,
606 devc->max_resistance, 0.01);
610 sr_dbg("%s: Unsupported key: %u (%s)", __func__, key,
611 kinfo ? kinfo->name : "unknown");
618 static int dev_acquisition_start(const struct sr_dev_inst *sdi)
620 struct dev_context *devc;
621 struct sr_serial_dev_inst *serial;
630 ret = serial_source_add(sdi->session, serial,
631 G_IO_IN, (1000.0 / devc->sample_rate),
632 itech_it8500_receive_data, (void *)sdi);
634 sr_sw_limits_acquisition_start(&devc->limits);
635 std_session_send_df_header(sdi);
641 static int dev_acquisition_stop(struct sr_dev_inst *sdi)
643 struct sr_serial_dev_inst *serial;
650 std_session_send_df_end(sdi);
651 serial_source_remove(sdi->session, serial);
656 static int dev_open(struct sr_dev_inst *sdi)
658 struct dev_context *devc;
659 struct itech_it8500_cmd_packet *cmd, *response;
666 ret = std_serial_dev_open(sdi);
668 /* Request the unit to enter remote control mode. */
670 cmd = g_malloc0(sizeof(*cmd));
672 cmd->address = devc->address;
673 cmd->command = CMD_SET_REMOTE_MODE;
675 res = itech_it8500_cmd(sdi, cmd, &response);
677 sr_dbg("Failed to set unit to remote mode");
686 static int dev_close(struct sr_dev_inst *sdi)
688 struct dev_context *devc;
689 struct itech_it8500_cmd_packet *cmd, *response;
697 cmd = g_malloc0(sizeof(*cmd));
699 /* Request the unit to enter local control mode. */
700 cmd->address = devc->address;
701 cmd->command = CMD_SET_REMOTE_MODE;
703 ret = itech_it8500_cmd(sdi, cmd, &response);
705 sr_dbg("Failed to set unit back to local mode: %d",
712 return std_serial_dev_close(sdi);
715 static void dev_clear_callback(void *priv)
717 struct dev_context *devc;
723 g_mutex_clear(&devc->mutex);
726 static int dev_clear(const struct sr_dev_driver *di)
728 return std_dev_clear_with_callback(di, dev_clear_callback);
731 static struct sr_dev_driver itech_it8500_driver_info = {
732 .name = "itech-it8500",
733 .longname = "ITECH IT8500 series",
736 .cleanup = std_cleanup,
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,
749 SR_REGISTER_DEV_DRIVER(itech_it8500_driver_info);