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