1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
5  * Portions of the code are adapted from scpi_tcp.c and scpi.c, their
6  * copyright notices are listed below:
7  *
8  * Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
9  * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho@gmail.com>
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 #include <config.h>
26 #ifdef _WIN32
27 #define _WIN32_WINNT 0x0501
28 #include <winsock2.h>
29 #include <ws2tcpip.h>
30 #endif
31 #include <glib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #ifndef _WIN32
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <netdb.h>
39 #endif
40 #include <errno.h>
41 
42 #include "protocol.h"
43 #include "beaglelogic.h"
44 
beaglelogic_tcp_open(struct dev_context * devc)45 static int beaglelogic_tcp_open(struct dev_context *devc)
46 {
47 	struct addrinfo hints;
48 	struct addrinfo *results, *res;
49 	int err;
50 
51 	memset(&hints, 0, sizeof(hints));
52 	hints.ai_family = AF_UNSPEC;
53 	hints.ai_socktype = SOCK_STREAM;
54 	hints.ai_protocol = IPPROTO_TCP;
55 
56 	err = getaddrinfo(devc->address, devc->port, &hints, &results);
57 
58 	if (err) {
59 		sr_err("Address lookup failed: %s:%s: %s", devc->address,
60 			devc->port, gai_strerror(err));
61 		return SR_ERR;
62 	}
63 
64 	for (res = results; res; res = res->ai_next) {
65 		if ((devc->socket = socket(res->ai_family, res->ai_socktype,
66 						res->ai_protocol)) < 0)
67 			continue;
68 		if (connect(devc->socket, res->ai_addr, res->ai_addrlen) != 0) {
69 			close(devc->socket);
70 			devc->socket = -1;
71 			continue;
72 		}
73 		break;
74 	}
75 
76 	freeaddrinfo(results);
77 
78 	if (devc->socket < 0) {
79 		sr_err("Failed to connect to %s:%s: %s", devc->address,
80 			devc->port, g_strerror(errno));
81 		return SR_ERR;
82 	}
83 
84 	return SR_OK;
85 }
86 
beaglelogic_tcp_send_cmd(struct dev_context * devc,const char * format,...)87 static int beaglelogic_tcp_send_cmd(struct dev_context *devc,
88 				    const char *format, ...)
89 {
90 	int len, out;
91 	va_list args, args_copy;
92 	char *buf;
93 
94 	va_start(args, format);
95 	va_copy(args_copy, args);
96 	len = vsnprintf(NULL, 0, format, args_copy);
97 	va_end(args_copy);
98 
99 	buf = g_malloc0(len + 2);
100 	vsprintf(buf, format, args);
101 	va_end(args);
102 
103 	if (buf[len - 1] != '\n')
104 		buf[len] = '\n';
105 
106 	out = send(devc->socket, buf, strlen(buf), 0);
107 
108 	if (out < 0) {
109 		sr_err("Send error: %s", g_strerror(errno));
110 		g_free(buf);
111 		return SR_ERR;
112 	}
113 
114 	if (out < (int)strlen(buf)) {
115 		sr_dbg("Only sent %d/%zu bytes of command: '%s'.", out,
116 		       strlen(buf), buf);
117 	}
118 
119 	sr_spew("Sent command: '%s'.", buf);
120 
121 	g_free(buf);
122 
123 	return SR_OK;
124 }
125 
beaglelogic_tcp_read_data(struct dev_context * devc,char * buf,int maxlen)126 static int beaglelogic_tcp_read_data(struct dev_context *devc, char *buf,
127 				     int maxlen)
128 {
129 	int len;
130 
131 	len = recv(devc->socket, buf, maxlen, 0);
132 
133 	if (len < 0) {
134 		sr_err("Receive error: %s", g_strerror(errno));
135 		return SR_ERR;
136 	}
137 
138 	return len;
139 }
140 
beaglelogic_tcp_drain(struct dev_context * devc)141 SR_PRIV int beaglelogic_tcp_drain(struct dev_context *devc)
142 {
143 	char *buf = g_malloc(1024);
144 	fd_set rset;
145 	int ret, len = 0;
146 	struct timeval tv;
147 
148 	FD_ZERO(&rset);
149 	FD_SET(devc->socket, &rset);
150 
151 	/* 25ms timeout */
152 	tv.tv_sec = 0;
153 	tv.tv_usec = 25 * 1000;
154 
155 	do {
156 		ret = select(devc->socket + 1, &rset, NULL, NULL, &tv);
157 		if (ret > 0)
158 			len += beaglelogic_tcp_read_data(devc, buf, 1024);
159 	} while (ret > 0);
160 
161 	sr_spew("Drained %d bytes of data.", len);
162 
163 	g_free(buf);
164 
165 	return SR_OK;
166 }
167 
beaglelogic_tcp_get_string(struct dev_context * devc,const char * cmd,char ** tcp_resp)168 static int beaglelogic_tcp_get_string(struct dev_context *devc, const char *cmd,
169 				      char **tcp_resp)
170 {
171 	GString *response = g_string_sized_new(1024);
172 	int len;
173 	gint64 timeout;
174 
175 	*tcp_resp = NULL;
176 	if (cmd) {
177 		if (beaglelogic_tcp_send_cmd(devc, cmd) != SR_OK)
178 			return SR_ERR;
179 	}
180 
181 	timeout = g_get_monotonic_time() + devc->read_timeout;
182 	len = beaglelogic_tcp_read_data(devc, response->str,
183 					response->allocated_len);
184 
185 	if (len < 0) {
186 		g_string_free(response, TRUE);
187 		return SR_ERR;
188 	}
189 
190 	if (len > 0)
191 		g_string_set_size(response, len);
192 
193 	if (g_get_monotonic_time() > timeout) {
194 		sr_err("Timed out waiting for response.");
195 		g_string_free(response, TRUE);
196 		return SR_ERR_TIMEOUT;
197 	}
198 
199 	/* Remove trailing newline if present */
200 	if (response->len >= 1 && response->str[response->len - 1] == '\n')
201 		g_string_truncate(response, response->len - 1);
202 
203 	/* Remove trailing carriage return if present */
204 	if (response->len >= 1 && response->str[response->len - 1] == '\r')
205 		g_string_truncate(response, response->len - 1);
206 
207 	sr_spew("Got response: '%.70s', length %" G_GSIZE_FORMAT ".",
208 		response->str, response->len);
209 
210 	*tcp_resp = g_string_free(response, FALSE);
211 
212 	return SR_OK;
213 }
214 
beaglelogic_tcp_get_int(struct dev_context * devc,const char * cmd,int * response)215 static int beaglelogic_tcp_get_int(struct dev_context *devc,
216 				   const char *cmd, int *response)
217 {
218 	int ret;
219 	char *resp = NULL;
220 
221 	ret = beaglelogic_tcp_get_string(devc, cmd, &resp);
222 	if (!resp && ret != SR_OK)
223 		return ret;
224 
225 	if (sr_atoi(resp, response) == SR_OK)
226 		ret = SR_OK;
227 	else
228 		ret = SR_ERR_DATA;
229 
230 	g_free(resp);
231 
232 	return ret;
233 }
234 
beaglelogic_tcp_detect(struct dev_context * devc)235 SR_PRIV int beaglelogic_tcp_detect(struct dev_context *devc)
236 {
237 	char *resp = NULL;
238 	int ret;
239 
240 	ret = beaglelogic_tcp_get_string(devc, "version", &resp);
241 	if (ret == SR_OK && !g_ascii_strncasecmp(resp, "BeagleLogic", 11))
242 		ret = SR_OK;
243 	else
244 		ret = SR_ERR;
245 
246 	g_free(resp);
247 
248 	return ret;
249 }
250 
beaglelogic_open(struct dev_context * devc)251 static int beaglelogic_open(struct dev_context *devc)
252 {
253 	return beaglelogic_tcp_open(devc);
254 }
255 
beaglelogic_close(struct dev_context * devc)256 static int beaglelogic_close(struct dev_context *devc)
257 {
258 	if (close(devc->socket) < 0)
259 		return SR_ERR;
260 
261 	return SR_OK;
262 }
263 
beaglelogic_get_buffersize(struct dev_context * devc)264 static int beaglelogic_get_buffersize(struct dev_context *devc)
265 {
266 	return beaglelogic_tcp_get_int(devc, "memalloc",
267 		(int *)&devc->buffersize);
268 }
269 
beaglelogic_set_buffersize(struct dev_context * devc)270 static int beaglelogic_set_buffersize(struct dev_context *devc)
271 {
272 	int ret;
273 	char *resp;
274 
275 	beaglelogic_tcp_send_cmd(devc, "memalloc %" PRIu32, devc->buffersize);
276 	ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
277 	if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
278 		ret = SR_OK;
279 	else
280 		ret = SR_ERR;
281 
282 	g_free(resp);
283 
284 	return ret;
285 }
286 
beaglelogic_get_samplerate(struct dev_context * devc)287 static int beaglelogic_get_samplerate(struct dev_context *devc)
288 {
289 	int arg, err;
290 
291 	err = beaglelogic_tcp_get_int(devc, "samplerate", &arg);
292 	if (err)
293 		return err;
294 
295 	devc->cur_samplerate = arg;
296 	return SR_OK;
297 }
298 
beaglelogic_set_samplerate(struct dev_context * devc)299 static int beaglelogic_set_samplerate(struct dev_context *devc)
300 {
301 	int ret;
302 	char *resp;
303 
304 	beaglelogic_tcp_send_cmd(devc, "samplerate %" PRIu32,
305 		(uint32_t)devc->cur_samplerate);
306 	ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
307 	if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
308 		ret = SR_OK;
309 	else
310 		ret = SR_ERR;
311 
312 	g_free(resp);
313 
314 	return ret;
315 }
316 
beaglelogic_get_sampleunit(struct dev_context * devc)317 static int beaglelogic_get_sampleunit(struct dev_context *devc)
318 {
319 	return beaglelogic_tcp_get_int(devc, "sampleunit",
320 		(int *)&devc->sampleunit);
321 }
322 
beaglelogic_set_sampleunit(struct dev_context * devc)323 static int beaglelogic_set_sampleunit(struct dev_context *devc)
324 {
325 	int ret;
326 	char *resp;
327 
328 	beaglelogic_tcp_send_cmd(devc, "sampleunit %" PRIu32, devc->sampleunit);
329 	ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
330 	if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
331 		ret = SR_OK;
332 	else
333 		ret = SR_ERR;
334 
335 	g_free(resp);
336 
337 	return ret;
338 }
339 
beaglelogic_get_triggerflags(struct dev_context * devc)340 static int beaglelogic_get_triggerflags(struct dev_context *devc)
341 {
342 	return beaglelogic_tcp_get_int(devc, "triggerflags",
343 		(int *)&devc->triggerflags);
344 }
345 
beaglelogic_set_triggerflags(struct dev_context * devc)346 static int beaglelogic_set_triggerflags(struct dev_context *devc)
347 {
348 	int ret;
349 	char *resp;
350 
351 	beaglelogic_tcp_send_cmd(devc, "triggerflags %" PRIu32, devc->triggerflags);
352 	ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
353 	if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
354 		ret = SR_OK;
355 	else
356 		ret = SR_ERR;
357 
358 	g_free(resp);
359 
360 	return ret;
361 }
362 
beaglelogic_get_lasterror(struct dev_context * devc)363 static int beaglelogic_get_lasterror(struct dev_context *devc)
364 {
365 	devc->last_error = 0;
366 
367 	return SR_OK;
368 }
369 
beaglelogic_start(struct dev_context * devc)370 static int beaglelogic_start(struct dev_context *devc)
371 {
372 	beaglelogic_tcp_drain(devc);
373 
374 	return beaglelogic_tcp_send_cmd(devc, "get");
375 }
376 
beaglelogic_stop(struct dev_context * devc)377 static int beaglelogic_stop(struct dev_context *devc)
378 {
379 	return beaglelogic_tcp_send_cmd(devc, "close");
380 }
381 
beaglelogic_get_bufunitsize(struct dev_context * devc)382 static int beaglelogic_get_bufunitsize(struct dev_context *devc)
383 {
384 	return beaglelogic_tcp_get_int(devc, "bufunitsize",
385 		(int *)&devc->bufunitsize);
386 }
387 
beaglelogic_set_bufunitsize(struct dev_context * devc)388 static int beaglelogic_set_bufunitsize(struct dev_context *devc)
389 {
390 	int ret;
391 	char *resp;
392 
393 	beaglelogic_tcp_send_cmd(devc, "bufunitsize %" PRIu32, devc->bufunitsize);
394 	ret = beaglelogic_tcp_get_string(devc, NULL, &resp);
395 	if (ret == SR_OK && !g_ascii_strncasecmp(resp, "ok", 2))
396 		ret = SR_OK;
397 	else
398 		ret = SR_ERR;
399 
400 	g_free(resp);
401 
402 	return ret;
403 }
404 
dummy(struct dev_context * devc)405 static int dummy(struct dev_context *devc)
406 {
407 	(void)devc;
408 
409 	return SR_ERR_NA;
410 }
411 
412 SR_PRIV const struct beaglelogic_ops beaglelogic_tcp_ops = {
413 	.open = beaglelogic_open,
414 	.close = beaglelogic_close,
415 	.get_buffersize = beaglelogic_get_buffersize,
416 	.set_buffersize = beaglelogic_set_buffersize,
417 	.get_samplerate = beaglelogic_get_samplerate,
418 	.set_samplerate = beaglelogic_set_samplerate,
419 	.get_sampleunit = beaglelogic_get_sampleunit,
420 	.set_sampleunit = beaglelogic_set_sampleunit,
421 	.get_triggerflags = beaglelogic_get_triggerflags,
422 	.set_triggerflags = beaglelogic_set_triggerflags,
423 	.start = beaglelogic_start,
424 	.stop = beaglelogic_stop,
425 	.get_lasterror = beaglelogic_get_lasterror,
426 	.get_bufunitsize = beaglelogic_get_bufunitsize,
427 	.set_bufunitsize = beaglelogic_set_bufunitsize,
428 	.mmap = dummy,
429 	.munmap = dummy,
430 };
431