]> sigrok.org Git - libsigrok.git/blob - src/serial_libsp.c
scpi-pps: Support for the EEZ PSU series
[libsigrok.git] / src / serial_libsp.c
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 #define LOG_PREFIX "serial-libsp"
35
36 /**
37  * @file
38  *
39  * Serial port handling, wraps the external libserialport dependency.
40  */
41
42 #ifdef HAVE_LIBSERIALPORT
43
44 /**
45  * @defgroup grp_serial_libsp Serial port handling, libserialport group
46  *
47  * Serial port handling functions, based on libserialport.
48  *
49  * @{
50  */
51
52 static int sr_ser_libsp_open(struct sr_serial_dev_inst *serial, int flags)
53 {
54         int ret;
55         char *error;
56         int sp_flags;
57
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         }
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
90 static int sr_ser_libsp_close(struct sr_serial_dev_inst *serial)
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
120 static int sr_ser_libsp_flush(struct sr_serial_dev_inst *serial)
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
147 static int sr_ser_libsp_drain(struct sr_serial_dev_inst *serial)
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
170 static int sr_ser_libsp_write(struct sr_serial_dev_inst *serial,
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
201 static int sr_ser_libsp_read(struct sr_serial_dev_inst *serial,
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
232 static int sr_ser_libsp_set_params(struct sr_serial_dev_inst *serial,
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
290 static 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
314 #ifdef G_OS_WIN32
315 typedef HANDLE event_handle;
316 #else
317 typedef int event_handle;
318 #endif
319
320 static 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
386 static int sr_ser_libsp_source_add(struct sr_session *session,
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
405 static int sr_ser_libsp_source_remove(struct sr_session *session,
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
414 static GSList *sr_ser_libsp_list(GSList *list, sr_ser_list_append_t append)
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
435 static GSList *sr_ser_libsp_find_usb(GSList *list, sr_ser_find_append_t append,
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
461 static int sr_ser_libsp_get_frame_format(struct sr_serial_dev_inst *serial,
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 }
505
506 static size_t sr_ser_libsp_get_rx_avail(struct sr_serial_dev_inst *serial)
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 }
519
520 static 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,
528         .set_handshake = sr_ser_libsp_set_handshake,
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 };
536 SR_PRIV struct ser_lib_functions *ser_lib_funcs_libsp = &serlib_sp;
537
538 #else
539
540 SR_PRIV struct ser_lib_functions *ser_lib_funcs_libsp = NULL;
541
542 #endif