]> sigrok.org Git - libsigrok.git/blame - src/serial_libsp.c
scpi-dmm: add support to get/set range on Agilent protocol using meters
[libsigrok.git] / src / serial_libsp.c
CommitLineData
ae4c1fb6
GS
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
5 * Copyright (C) 2010-2012 Uwe Hermann <uwe@hermann-uwe.de>
6 * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
7 * Copyright (C) 2014 Uffe Jakobsen <uffe@uffe.org>
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <config.h>
24#include <glib.h>
25#include <libsigrok/libsigrok.h>
26#include "libsigrok-internal.h"
27#ifdef HAVE_LIBSERIALPORT
28#include <libserialport.h>
29#endif
30#ifdef G_OS_WIN32
31#include <windows.h> /* for HANDLE */
32#endif
33
ae4c1fb6 34#define LOG_PREFIX "serial-libsp"
ae4c1fb6
GS
35
36/**
37 * @file
38 *
39 * Serial port handling, wraps the external libserialport dependency.
40 */
41
a7b8692e
GS
42#ifdef HAVE_LIBSERIALPORT
43
ae4c1fb6
GS
44/**
45 * @defgroup grp_serial_libsp Serial port handling, libserialport group
46 *
47 * Serial port handling functions, based on libserialport.
48 *
49 * @{
50 */
51
a7b8692e 52static int sr_ser_libsp_open(struct sr_serial_dev_inst *serial, int flags)
ae4c1fb6
GS
53{
54 int ret;
55 char *error;
56 int sp_flags;
57
ac1866b9
GS
58 ret = sp_get_port_by_name(serial->port, &serial->sp_data);
59 if (ret != SP_OK) {
60 error = sp_last_error_message();
61 sr_err("Error getting port from name %s: (%d) %s.",
62 serial->port, sp_last_error_code(), error);
63 sp_free_error_message(error);
64 return SR_ERR;
65 }
ae4c1fb6
GS
66
67 sp_flags = 0;
68 if (flags & SERIAL_RDWR)
69 sp_flags = (SP_MODE_READ | SP_MODE_WRITE);
70 else if (flags & SERIAL_RDONLY)
71 sp_flags = SP_MODE_READ;
72
73 ret = sp_open(serial->sp_data, sp_flags);
74
75 switch (ret) {
76 case SP_ERR_ARG:
77 sr_err("Attempt to open serial port with invalid parameters.");
78 return SR_ERR_ARG;
79 case SP_ERR_FAIL:
80 error = sp_last_error_message();
81 sr_err("Error opening port (%d): %s.",
82 sp_last_error_code(), error);
83 sp_free_error_message(error);
84 return SR_ERR;
85 }
86
87 return SR_OK;
88}
89
a7b8692e 90static int sr_ser_libsp_close(struct sr_serial_dev_inst *serial)
ae4c1fb6
GS
91{
92 int ret;
93 char *error;
94
95 if (!serial->sp_data) {
96 sr_dbg("Cannot close unopened serial port %s.", serial->port);
97 return SR_ERR;
98 }
99
100 ret = sp_close(serial->sp_data);
101
102 switch (ret) {
103 case SP_ERR_ARG:
104 sr_err("Attempt to close an invalid serial port.");
105 return SR_ERR_ARG;
106 case SP_ERR_FAIL:
107 error = sp_last_error_message();
108 sr_err("Error closing port (%d): %s.",
109 sp_last_error_code(), error);
110 sp_free_error_message(error);
111 return SR_ERR;
112 }
113
114 sp_free_port(serial->sp_data);
115 serial->sp_data = NULL;
116
117 return SR_OK;
118}
119
a7b8692e 120static int sr_ser_libsp_flush(struct sr_serial_dev_inst *serial)
ae4c1fb6
GS
121{
122 int ret;
123 char *error;
124
125 if (!serial->sp_data) {
126 sr_dbg("Cannot flush unopened serial port %s.", serial->port);
127 return SR_ERR;
128 }
129
130 ret = sp_flush(serial->sp_data, SP_BUF_BOTH);
131
132 switch (ret) {
133 case SP_ERR_ARG:
134 sr_err("Attempt to flush an invalid serial port.");
135 return SR_ERR_ARG;
136 case SP_ERR_FAIL:
137 error = sp_last_error_message();
138 sr_err("Error flushing port (%d): %s.",
139 sp_last_error_code(), error);
140 sp_free_error_message(error);
141 return SR_ERR;
142 }
143
144 return SR_OK;
145}
146
a7b8692e 147static int sr_ser_libsp_drain(struct sr_serial_dev_inst *serial)
ae4c1fb6
GS
148{
149 int ret;
150 char *error;
151
152 if (!serial->sp_data) {
153 sr_dbg("Cannot drain unopened serial port %s.", serial->port);
154 return SR_ERR;
155 }
156
157 ret = sp_drain(serial->sp_data);
158
159 if (ret == SP_ERR_FAIL) {
160 error = sp_last_error_message();
161 sr_err("Error draining port (%d): %s.",
162 sp_last_error_code(), error);
163 sp_free_error_message(error);
164 return SR_ERR;
165 }
166
167 return SR_OK;
168}
169
a7b8692e 170static int sr_ser_libsp_write(struct sr_serial_dev_inst *serial,
ae4c1fb6
GS
171 const void *buf, size_t count,
172 int nonblocking, unsigned int timeout_ms)
173{
174 ssize_t ret;
175 char *error;
176
177 if (!serial->sp_data) {
178 sr_dbg("Cannot use unopened serial port %s.", serial->port);
179 return SR_ERR;
180 }
181
182 if (nonblocking)
183 ret = sp_nonblocking_write(serial->sp_data, buf, count);
184 else
185 ret = sp_blocking_write(serial->sp_data, buf, count, timeout_ms);
186
187 switch (ret) {
188 case SP_ERR_ARG:
189 sr_err("Attempted serial port write with invalid arguments.");
190 return SR_ERR_ARG;
191 case SP_ERR_FAIL:
192 error = sp_last_error_message();
193 sr_err("Write error (%d): %s.", sp_last_error_code(), error);
194 sp_free_error_message(error);
195 return SR_ERR;
196 }
197
198 return ret;
199}
200
a7b8692e 201static int sr_ser_libsp_read(struct sr_serial_dev_inst *serial,
ae4c1fb6
GS
202 void *buf, size_t count,
203 int nonblocking, unsigned int timeout_ms)
204{
205 ssize_t ret;
206 char *error;
207
208 if (!serial->sp_data) {
209 sr_dbg("Cannot use unopened serial port %s.", serial->port);
210 return SR_ERR;
211 }
212
213 if (nonblocking)
214 ret = sp_nonblocking_read(serial->sp_data, buf, count);
215 else
216 ret = sp_blocking_read(serial->sp_data, buf, count, timeout_ms);
217
218 switch (ret) {
219 case SP_ERR_ARG:
220 sr_err("Attempted serial port read with invalid arguments.");
221 return SR_ERR_ARG;
222 case SP_ERR_FAIL:
223 error = sp_last_error_message();
224 sr_err("Read error (%d): %s.", sp_last_error_code(), error);
225 sp_free_error_message(error);
226 return SR_ERR;
227 }
228
229 return ret;
230}
231
a7b8692e 232static int sr_ser_libsp_set_params(struct sr_serial_dev_inst *serial,
ae4c1fb6
GS
233 int baudrate, int bits, int parity, int stopbits,
234 int flowcontrol, int rts, int dtr)
235{
236 int ret;
237 char *error;
238 struct sp_port_config *config;
239 int cts, xonoff;
240
241 if (!serial->sp_data) {
242 sr_dbg("Cannot configure unopened serial port %s.", serial->port);
243 return SR_ERR;
244 }
245
246 sp_new_config(&config);
247 sp_set_config_baudrate(config, baudrate);
248 sp_set_config_bits(config, bits);
249 switch (parity) {
250 case 0:
251 sp_set_config_parity(config, SP_PARITY_NONE);
252 break;
253 case 1:
254 sp_set_config_parity(config, SP_PARITY_EVEN);
255 break;
256 case 2:
257 sp_set_config_parity(config, SP_PARITY_ODD);
258 break;
259 default:
260 return SR_ERR_ARG;
261 }
262 sp_set_config_stopbits(config, stopbits);
263 rts = flowcontrol == 1 ? SP_RTS_FLOW_CONTROL : rts;
264 sp_set_config_rts(config, rts);
265 cts = flowcontrol == 1 ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
266 sp_set_config_cts(config, cts);
267 sp_set_config_dtr(config, dtr);
268 sp_set_config_dsr(config, SP_DSR_IGNORE);
269 xonoff = flowcontrol == 2 ? SP_XONXOFF_INOUT : SP_XONXOFF_DISABLED;
270 sp_set_config_xon_xoff(config, xonoff);
271
272 ret = sp_set_config(serial->sp_data, config);
273 sp_free_config(config);
274
275 switch (ret) {
276 case SP_ERR_ARG:
277 sr_err("Invalid arguments for setting serial port parameters.");
278 return SR_ERR_ARG;
279 case SP_ERR_FAIL:
280 error = sp_last_error_message();
281 sr_err("Error setting serial port parameters (%d): %s.",
282 sp_last_error_code(), error);
283 sp_free_error_message(error);
284 return SR_ERR;
285 }
286
287 return SR_OK;
288}
289
3ad30b4e
GS
290static int sr_ser_libsp_set_handshake(struct sr_serial_dev_inst *serial,
291 int rts, int dtr)
292{
293 int ret;
294
295 if (!serial->sp_data) {
296 sr_dbg("Cannot configure unopened serial port %s.", serial->port);
297 return SR_ERR;
298 }
299
300 if (rts >= 0) {
301 ret = sp_set_rts(serial->sp_data, rts ? SP_RTS_ON : SP_RTS_OFF);
302 if (ret != SP_OK)
303 return SR_ERR;
304 }
305 if (dtr >= 0) {
306 ret = sp_set_dtr(serial->sp_data, dtr ? SP_DTR_ON : SP_DTR_OFF);
307 if (ret != SP_OK)
308 return SR_ERR;
309 }
310
311 return SR_OK;
312}
313
ae4c1fb6
GS
314#ifdef G_OS_WIN32
315typedef HANDLE event_handle;
316#else
317typedef int event_handle;
318#endif
ae4c1fb6
GS
319
320static int sr_ser_libsp_source_add_int(struct sr_serial_dev_inst *serial,
321 int events,
322 void **keyptr, gintptr *fdptr, unsigned int *pollevtptr)
323{
324 struct sp_event_set *event_set;
325 gintptr poll_fd;
326 unsigned int poll_events;
327 enum sp_event mask;
328
329 if ((events & (G_IO_IN | G_IO_ERR)) && (events & G_IO_OUT)) {
330 sr_err("Cannot poll input/error and output simultaneously.");
331 return SR_ERR_ARG;
332 }
333 if (!serial->sp_data) {
334 sr_err("Invalid serial port.");
335 return SR_ERR_ARG;
336 }
337
338 if (sp_new_event_set(&event_set) != SP_OK)
339 return SR_ERR;
340
341 mask = 0;
342 if (events & G_IO_IN)
343 mask |= SP_EVENT_RX_READY;
344 if (events & G_IO_OUT)
345 mask |= SP_EVENT_TX_READY;
346 if (events & G_IO_ERR)
347 mask |= SP_EVENT_ERROR;
348
349 if (sp_add_port_events(event_set, serial->sp_data, mask) != SP_OK) {
350 sp_free_event_set(event_set);
351 return SR_ERR;
352 }
353 if (event_set->count != 1) {
354 sr_err("Unexpected number (%u) of event handles to poll.",
355 event_set->count);
356 sp_free_event_set(event_set);
357 return SR_ERR;
358 }
359
360 poll_fd = (gintptr) ((event_handle *)event_set->handles)[0];
361 mask = event_set->masks[0];
362
363 sp_free_event_set(event_set);
364
365 poll_events = 0;
366 if (mask & SP_EVENT_RX_READY)
367 poll_events |= G_IO_IN;
368 if (mask & SP_EVENT_TX_READY)
369 poll_events |= G_IO_OUT;
370 if (mask & SP_EVENT_ERROR)
371 poll_events |= G_IO_ERR;
372
373 /*
374 * Using serial->sp_data as the key for the event source is not quite
375 * proper, as it makes it impossible to create another event source
376 * for the same serial port. However, these fixed keys will soon be
377 * removed from the API anyway, so this is OK for now.
378 */
379 *keyptr = serial->sp_data;
380 *fdptr = poll_fd;
381 *pollevtptr = poll_events;
382
383 return SR_OK;
384}
385
a7b8692e 386static int sr_ser_libsp_source_add(struct sr_session *session,
ae4c1fb6
GS
387 struct sr_serial_dev_inst *serial, int events, int timeout,
388 sr_receive_data_callback cb, void *cb_data)
389{
390 int ret;
391 void *key;
392 gintptr poll_fd;
393 unsigned int poll_events;
394
395 ret = sr_ser_libsp_source_add_int(serial, events,
396 &key, &poll_fd, &poll_events);
397 if (ret != SR_OK)
398 return ret;
399
400 return sr_session_fd_source_add(session,
401 key, poll_fd, poll_events,
402 timeout, cb, cb_data);
403}
404
a7b8692e 405static int sr_ser_libsp_source_remove(struct sr_session *session,
ae4c1fb6
GS
406 struct sr_serial_dev_inst *serial)
407{
408 void *key;
409
410 key = serial->sp_data;
411 return sr_session_source_remove_internal(session, key);
412}
413
a7b8692e 414static GSList *sr_ser_libsp_list(GSList *list, sr_ser_list_append_t append)
ae4c1fb6
GS
415{
416 struct sp_port **ports;
417 size_t i;
418 const char *name;
419 const char *desc;
420
421 if (sp_list_ports(&ports) != SP_OK)
422 return list;
423
424 for (i = 0; ports[i]; i++) {
425 name = sp_get_port_name(ports[i]);
426 desc = sp_get_port_description(ports[i]);
427 list = append(list, name, desc);
428 }
429
430 sp_free_port_list(ports);
431
432 return list;
433}
434
a7b8692e 435static GSList *sr_ser_libsp_find_usb(GSList *list, sr_ser_find_append_t append,
ae4c1fb6
GS
436 uint16_t vendor_id, uint16_t product_id)
437{
438 struct sp_port **ports;
439 int i, vid, pid;
440
441 if (sp_list_ports(&ports) != SP_OK)
442 return list;
443
444 for (i = 0; ports[i]; i++) {
445 if (sp_get_port_transport(ports[i]) != SP_TRANSPORT_USB)
446 continue;
447 if (sp_get_port_usb_vid_pid(ports[i], &vid, &pid) != SP_OK)
448 continue;
449 if (vendor_id && vid != vendor_id)
450 continue;
451 if (product_id && pid != product_id)
452 continue;
453 list = append(list, sp_get_port_name(ports[i]));
454 }
455
456 sp_free_port_list(ports);
457
458 return list;
459}
460
a7b8692e 461static int sr_ser_libsp_get_frame_format(struct sr_serial_dev_inst *serial,
ae4c1fb6
GS
462 int *baud, int *bits)
463{
464 struct sp_port_config *config;
465 int ret, tmp;
466 enum sp_parity parity;
467
468 if (sp_new_config(&config) < 0)
469 return SR_ERR_MALLOC;
470 *baud = *bits = 0;
471 ret = SR_OK;
472 do {
473 if (sp_get_config(serial->sp_data, config) < 0) {
474 ret = SR_ERR_NA;
475 break;
476 }
477
478 if (sp_get_config_baudrate(config, &tmp) < 0) {
479 ret = SR_ERR_NA;
480 break;
481 }
482 *baud = tmp;
483
484 *bits += 1; /* Start bit. */
485 if (sp_get_config_bits(config, &tmp) < 0) {
486 ret = SR_ERR_NA;
487 break;
488 }
489 *bits += tmp;
490 if (sp_get_config_parity(config, &parity) < 0) {
491 ret = SR_ERR_NA;
492 break;
493 }
494 *bits += (parity != SP_PARITY_NONE) ? 1 : 0;
495 if (sp_get_config_stopbits(config, &tmp) < 0) {
496 ret = SR_ERR_NA;
497 break;
498 }
499 *bits += tmp;
500 } while (FALSE);
501 sp_free_config(config);
502
503 return ret;
504}
8c3df6e5 505
a7b8692e 506static size_t sr_ser_libsp_get_rx_avail(struct sr_serial_dev_inst *serial)
8c3df6e5
GS
507{
508 int rc;
509
510 if (!serial)
511 return 0;
512
513 rc = sp_input_waiting(serial->sp_data);
514 if (rc < 0)
515 return 0;
516
517 return rc;
518}
a7b8692e
GS
519
520static struct ser_lib_functions serlib_sp = {
521 .open = sr_ser_libsp_open,
522 .close = sr_ser_libsp_close,
523 .flush = sr_ser_libsp_flush,
524 .drain = sr_ser_libsp_drain,
525 .write = sr_ser_libsp_write,
526 .read = sr_ser_libsp_read,
527 .set_params = sr_ser_libsp_set_params,
3ad30b4e 528 .set_handshake = sr_ser_libsp_set_handshake,
a7b8692e
GS
529 .setup_source_add = sr_ser_libsp_source_add,
530 .setup_source_remove = sr_ser_libsp_source_remove,
531 .list = sr_ser_libsp_list,
532 .find_usb = sr_ser_libsp_find_usb,
533 .get_frame_format = sr_ser_libsp_get_frame_format,
534 .get_rx_avail = sr_ser_libsp_get_rx_avail,
535};
536SR_PRIV struct ser_lib_functions *ser_lib_funcs_libsp = &serlib_sp;
537
538#else
539
540SR_PRIV struct ser_lib_functions *ser_lib_funcs_libsp = NULL;
541
542#endif