1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Uwe Hermann <uwe@hermann-uwe.de>
5  * Copyright (C) 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
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 2 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 static const uint32_t scanopts[] = {
25 	SR_CONF_CONN,
26 	SR_CONF_SERIALCOMM,
27 };
28 
29 static const uint32_t drvopts[] = {
30 	SR_CONF_POWER_SUPPLY,
31 };
32 
33 static const uint32_t devopts[] = {
34 	SR_CONF_CONTINUOUS,
35 	SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
36 	SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
37 	SR_CONF_VOLTAGE | SR_CONF_GET,
38 	SR_CONF_VOLTAGE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
39 	SR_CONF_CURRENT | SR_CONF_GET,
40 	SR_CONF_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
41 	SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
42 };
43 
44 /* Note: All models have one power supply output only. */
45 static const struct hcs_model models[] = {
46 	{ MANSON_HCS_3100, "HCS-3100",     "3100",     { 1, 18, 0.1 }, { 0, 10,   0.10 } },
47 	{ MANSON_HCS_3102, "HCS-3102",     "3102",     { 1, 36, 0.1 }, { 0,  5,   0.01 } },
48 	{ MANSON_HCS_3104, "HCS-3104",     "3104",     { 1, 60, 0.1 }, { 0,  2.5, 0.01 } },
49 	{ MANSON_HCS_3150, "HCS-3150",     "3150",     { 1, 18, 0.1 }, { 0, 15,   0.10 } },
50 	{ MANSON_HCS_3200, "HCS-3200",     "3200",     { 1, 18, 0.1 }, { 0, 20,   0.10 } },
51 	{ MANSON_HCS_3200, "HCS-3200",     "HCS-3200", { 1, 18, 0.1 }, { 0, 20,   0.10 } },
52 	{ MANSON_HCS_3202, "HCS-3202",     "3202",     { 1, 36, 0.1 }, { 0, 10,   0.10 } },
53 	{ MANSON_HCS_3202, "HCS-3202",     "HCS-3202", { 1, 36, 0.1 }, { 0, 10,   0.10 } },
54 	{ MANSON_HCS_3204, "HCS-3204",     "3204",     { 1, 60, 0.1 }, { 0,  5,   0.01 } },
55 	{ MANSON_HCS_3300, "HCS-3300-USB", "3300",     { 1, 16, 0.1 }, { 0, 30,   0.10 } },
56 	{ MANSON_HCS_3300, "HCS-3300-USB", "HCS-3300", { 1, 16, 0.1 }, { 0, 30,   0.10 } },
57 	{ MANSON_HCS_3302, "HCS-3302-USB", "3302",     { 1, 32, 0.1 }, { 0, 15,   0.10 } },
58 	{ MANSON_HCS_3302, "HCS-3302-USB", "HCS-3302", { 1, 32, 0.1 }, { 0, 15,   0.10 } },
59 	{ MANSON_HCS_3304, "HCS-3304-USB", "3304",     { 1, 60, 0.1 }, { 0,  8,   0.10 } },
60 	{ MANSON_HCS_3304, "HCS-3304-USB", "HCS-3304", { 1, 60, 0.1 }, { 0,  8,   0.10 } },
61 	{ MANSON_HCS_3400, "HCS-3400-USB", "3400",     { 1, 16, 0.1 }, { 0, 40,   0.10 } },
62 	{ MANSON_HCS_3402, "HCS-3402-USB", "3402",     { 1, 32, 0.1 }, { 0, 20,   0.10 } },
63 	{ MANSON_HCS_3404, "HCS-3404-USB", "3404",     { 1, 60, 0.1 }, { 0, 10,   0.10 } },
64 	{ MANSON_HCS_3600, "HCS-3600-USB", "3600",     { 1, 16, 0.1 }, { 0, 60,   0.10 } },
65 	{ MANSON_HCS_3602, "HCS-3602-USB", "3602",     { 1, 32, 0.1 }, { 0, 30,   0.10 } },
66 	{ MANSON_HCS_3604, "HCS-3604-USB", "3604",     { 1, 60, 0.1 }, { 0, 15,   0.10 } },
67 	ALL_ZERO
68 };
69 
scan(struct sr_dev_driver * di,GSList * options)70 static GSList *scan(struct sr_dev_driver *di, GSList *options)
71 {
72 	int i, model_id;
73 	struct dev_context *devc;
74 	struct sr_dev_inst *sdi;
75 	struct sr_config *src;
76 	GSList *l;
77 	const char *conn, *serialcomm;
78 	struct sr_serial_dev_inst *serial;
79 	char reply[50], **tokens, *dummy;
80 
81 	conn = NULL;
82 	serialcomm = NULL;
83 	devc = NULL;
84 
85 	for (l = options; l; l = l->next) {
86 		src = l->data;
87 		switch (src->key) {
88 		case SR_CONF_CONN:
89 			conn = g_variant_get_string(src->data, NULL);
90 			break;
91 		case SR_CONF_SERIALCOMM:
92 			serialcomm = g_variant_get_string(src->data, NULL);
93 			break;
94 		default:
95 			sr_err("Unknown option %d, skipping.", src->key);
96 			break;
97 		}
98 	}
99 
100 	if (!conn)
101 		return NULL;
102 	if (!serialcomm)
103 		serialcomm = "9600/8n1";
104 
105 	serial = sr_serial_dev_inst_new(conn, serialcomm);
106 
107 	if (serial_open(serial, SERIAL_RDWR) != SR_OK)
108 		return NULL;
109 
110 	serial_flush(serial);
111 
112 	sr_info("Probing serial port %s.", conn);
113 
114 	/* Get the device model. */
115 	memset(&reply, 0, sizeof(reply));
116 	if ((hcs_send_cmd(serial, "GMOD\r") < 0) ||
117 	    (hcs_read_reply(serial, 2, reply, sizeof(reply)) < 0))
118 		return NULL;
119 	tokens = g_strsplit((const gchar *)&reply, "\r", 2);
120 
121 	model_id = -1;
122 	for (i = 0; models[i].id != NULL; i++) {
123 		if (!strcmp(models[i].id, tokens[0]))
124 			model_id = i;
125 	}
126 	if (model_id < 0) {
127 		sr_err("Unknown model ID '%s' detected, aborting.", tokens[0]);
128 		g_strfreev(tokens);
129 		return NULL;
130 	}
131 	g_strfreev(tokens);
132 
133 	sdi = g_malloc0(sizeof(struct sr_dev_inst));
134 	sdi->status = SR_ST_INACTIVE;
135 	sdi->vendor = g_strdup("Manson");
136 	sdi->model = g_strdup(models[model_id].name);
137 	sdi->inst_type = SR_INST_SERIAL;
138 	sdi->conn = serial;
139 
140 	sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "CH1");
141 
142 	devc = g_malloc0(sizeof(struct dev_context));
143 	sr_sw_limits_init(&devc->limits);
144 	devc->model = &models[model_id];
145 
146 	sdi->priv = devc;
147 
148 	/* Get current voltage, current, status. */
149 	if ((hcs_send_cmd(serial, "GETD\r") < 0) ||
150 	    (hcs_read_reply(serial, 2, reply, sizeof(reply)) < 0))
151 		goto exit_err;
152 	tokens = g_strsplit((const gchar *)&reply, "\r", 2);
153 	if (hcs_parse_volt_curr_mode(sdi, tokens) < 0) {
154 		g_strfreev(tokens);
155 		goto exit_err;
156 	}
157 	g_strfreev(tokens);
158 
159 	/* Get max. voltage and current. */
160 	if ((hcs_send_cmd(serial, "GMAX\r") < 0) ||
161 	    (hcs_read_reply(serial, 2, reply, sizeof(reply)) < 0))
162 		goto exit_err;
163 	tokens = g_strsplit((const gchar *)&reply, "\r", 2);
164 	devc->current_max_device = g_strtod(&tokens[0][3], &dummy) * devc->model->current[2];
165 	tokens[0][3] = '\0';
166 	devc->voltage_max_device = g_strtod(tokens[0], &dummy) * devc->model->voltage[2];
167 	g_strfreev(tokens);
168 
169 	serial_close(serial);
170 
171 	return std_scan_complete(di, g_slist_append(NULL, sdi));
172 
173 exit_err:
174 	sr_dev_inst_free(sdi);
175 	g_free(devc);
176 
177 	return NULL;
178 }
179 
config_get(uint32_t key,GVariant ** data,const struct sr_dev_inst * sdi,const struct sr_channel_group * cg)180 static int config_get(uint32_t key, GVariant **data,
181 	const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
182 {
183 	struct dev_context *devc;
184 
185 	(void)cg;
186 
187 	if (!sdi)
188 		return SR_ERR_ARG;
189 
190 	devc = sdi->priv;
191 
192 	switch (key) {
193 	case SR_CONF_LIMIT_SAMPLES:
194 	case SR_CONF_LIMIT_MSEC:
195 		return sr_sw_limits_config_get(&devc->limits, key, data);
196 	case SR_CONF_VOLTAGE:
197 		*data = g_variant_new_double(devc->voltage);
198 		break;
199 	case SR_CONF_VOLTAGE_TARGET:
200 		*data = g_variant_new_double(devc->voltage_max);
201 		break;
202 	case SR_CONF_CURRENT:
203 		*data = g_variant_new_double(devc->current);
204 		break;
205 	case SR_CONF_CURRENT_LIMIT:
206 		*data = g_variant_new_double(devc->current_max);
207 		break;
208 	case SR_CONF_ENABLED:
209 		*data = g_variant_new_boolean(devc->output_enabled);
210 		break;
211 	default:
212 		return SR_ERR_NA;
213 	}
214 
215 	return SR_OK;
216 }
217 
config_set(uint32_t key,GVariant * data,const struct sr_dev_inst * sdi,const struct sr_channel_group * cg)218 static int config_set(uint32_t key, GVariant *data,
219 	const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
220 {
221 	struct dev_context *devc;
222 	gboolean bval;
223 	gdouble dval;
224 
225 	(void)cg;
226 
227 	devc = sdi->priv;
228 
229 	switch (key) {
230 	case SR_CONF_LIMIT_MSEC:
231 	case SR_CONF_LIMIT_SAMPLES:
232 		return sr_sw_limits_config_set(&devc->limits, key, data);
233 	case SR_CONF_VOLTAGE_TARGET:
234 		dval = g_variant_get_double(data);
235 		if (dval < devc->model->voltage[0] || dval > devc->voltage_max_device)
236 			return SR_ERR_ARG;
237 
238 		if ((hcs_send_cmd(sdi->conn, "VOLT%03.0f\r",
239 			(dval / devc->model->voltage[2])) < 0) ||
240 		    (hcs_read_reply(sdi->conn, 1, devc->buf, sizeof(devc->buf)) < 0))
241 			return SR_ERR;
242 		devc->voltage_max = dval;
243 		break;
244 	case SR_CONF_CURRENT_LIMIT:
245 		dval = g_variant_get_double(data);
246 		if (dval < devc->model->current[0] || dval > devc->current_max_device)
247 			return SR_ERR_ARG;
248 
249 		if ((hcs_send_cmd(sdi->conn, "CURR%03.0f\r",
250 			(dval / devc->model->current[2])) < 0) ||
251 		    (hcs_read_reply(sdi->conn, 1, devc->buf, sizeof(devc->buf)) < 0))
252 			return SR_ERR;
253 		devc->current_max = dval;
254 		break;
255 	case SR_CONF_ENABLED:
256 		bval = g_variant_get_boolean(data);
257 
258 		if (hcs_send_cmd(sdi->conn, "SOUT%1d\r", !bval) < 0) {
259 			sr_err("Could not send SR_CONF_ENABLED command.");
260 			return SR_ERR;
261 		}
262 		if (hcs_read_reply(sdi->conn, 1, devc->buf, sizeof(devc->buf)) < 0) {
263 			sr_err("Could not read SR_CONF_ENABLED reply.");
264 			return SR_ERR;
265 		}
266 		devc->output_enabled = bval;
267 		break;
268 	default:
269 		return SR_ERR_NA;
270 	}
271 
272 	return SR_OK;
273 }
274 
config_list(uint32_t key,GVariant ** data,const struct sr_dev_inst * sdi,const struct sr_channel_group * cg)275 static int config_list(uint32_t key, GVariant **data,
276 	const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
277 {
278 	const double *a;
279 	struct dev_context *devc;
280 
281 	devc = (sdi) ? sdi->priv : NULL;
282 
283 	switch (key) {
284 	case SR_CONF_SCAN_OPTIONS:
285 	case SR_CONF_DEVICE_OPTIONS:
286 		return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts);
287 	case SR_CONF_VOLTAGE_TARGET:
288 		if (!devc || !devc->model)
289 			return SR_ERR_ARG;
290 		a = devc->model->voltage;
291 		*data = std_gvar_min_max_step(a[0], devc->voltage_max_device, a[2]);
292 		break;
293 	case SR_CONF_CURRENT_LIMIT:
294 		if (!devc || !devc->model)
295 			return SR_ERR_ARG;
296 		a = devc->model->current;
297 		*data = std_gvar_min_max_step(a[0], devc->current_max_device, a[2]);
298 		break;
299 	default:
300 		return SR_ERR_NA;
301 	}
302 
303 	return SR_OK;
304 }
305 
dev_acquisition_start(const struct sr_dev_inst * sdi)306 static int dev_acquisition_start(const struct sr_dev_inst *sdi)
307 {
308 	struct dev_context *devc;
309 	struct sr_serial_dev_inst *serial;
310 
311 	devc = sdi->priv;
312 
313 	sr_sw_limits_acquisition_start(&devc->limits);
314 	std_session_send_df_header(sdi);
315 
316 	devc->reply_pending = FALSE;
317 	devc->req_sent_at = 0;
318 
319 	serial = sdi->conn;
320 	serial_source_add(sdi->session, serial, G_IO_IN, 10,
321 			hcs_receive_data, (void *)sdi);
322 
323 	return SR_OK;
324 }
325 
326 static struct sr_dev_driver manson_hcs_3xxx_driver_info = {
327 	.name = "manson-hcs-3xxx",
328 	.longname = "Manson HCS-3xxx",
329 	.api_version = 1,
330 	.init = std_init,
331 	.cleanup = std_cleanup,
332 	.scan = scan,
333 	.dev_list = std_dev_list,
334 	.dev_clear = std_dev_clear,
335 	.config_get = config_get,
336 	.config_set = config_set,
337 	.config_list = config_list,
338 	.dev_open = std_serial_dev_open,
339 	.dev_close = std_serial_dev_close,
340 	.dev_acquisition_start = dev_acquisition_start,
341 	.dev_acquisition_stop = std_serial_dev_acquisition_stop,
342 	.context = NULL,
343 };
344 SR_REGISTER_DEV_DRIVER(manson_hcs_3xxx_driver_info);
345