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