├── README.md ├── libserialport.h ├── libserialport_internal.h ├── linux.c ├── linux_termios.c ├── linux_termios.h ├── listports └── listports.go ├── macosx.c ├── serial.go ├── serialport.c └── windows.c /README.md: -------------------------------------------------------------------------------- 1 | # Go Serial 2 | 3 | [![GoDoc](https://godoc.org/github.com/mikepb/go-serial?status.svg)](https://godoc.org/github.com/mikepb/go-serial) 4 | 5 | Package serial provides a binding to libserialport for serial port 6 | functionality. Serial ports are commonly used with embedded systems, 7 | such as the Arduino platform. 8 | 9 | ## Usage 10 | 11 | ```go 12 | package main 13 | 14 | import ( 15 | "github.com/mikepb/go-serial" 16 | "log" 17 | ) 18 | 19 | func main() { 20 | options := serial.RawOptions 21 | options.BitRate = 115200 22 | p, err := options.Open("/dev/tty") 23 | if err != nil { 24 | log.Panic(err) 25 | } 26 | 27 | defer p.Close() 28 | 29 | buf := make([]byte, 1) 30 | if _, err := p.Read(buf); err != nil { 31 | log.Panic(err) 32 | } else { 33 | log.Println(buf) 34 | } 35 | } 36 | ``` 37 | 38 | ## Documentation 39 | 40 | https://godoc.org/github.com/mikepb/go-serial 41 | 42 | 43 | ## License 44 | 45 | Copyright 2014 Michael Phan-Ba 46 | 47 | Licensed under the Apache License, Version 2.0 (the "License"); 48 | you may not use this file except in compliance with the License. 49 | You may obtain a copy of the License at 50 | 51 | http://www.apache.org/licenses/LICENSE-2.0 52 | 53 | Unless required by applicable law or agreed to in writing, software 54 | distributed under the License is distributed on an "AS IS" BASIS, 55 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 56 | See the License for the specific language governing permissions and 57 | limitations under the License. 58 | 59 | Files from the libserialport library are licensed under the GNU Lesser General 60 | Public License. These files include in the header the notice that follows. 61 | 62 | This file is part of the libserialport project. 63 | 64 | Copyright (C) 2010-2012 Bert Vermeulen 65 | Copyright (C) 2010-2012 Uwe Hermann 66 | Copyright (C) 2013-2014 Martin Ling 67 | Copyright (C) 2013 Matthias Heidbrink 68 | Copyright (C) 2014 Aurelien Jacobs 69 | 70 | This program is free software: you can redistribute it and/or modify 71 | it under the terms of the GNU Lesser General Public License as 72 | published by the Free Software Foundation, either version 3 of the 73 | License, or (at your option) any later version. 74 | 75 | This program is distributed in the hope that it will be useful, 76 | but WITHOUT ANY WARRANTY; without even the implied warranty of 77 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 78 | GNU General Public License for more details. 79 | 80 | You should have received a copy of the GNU Lesser General Public License 81 | along with this program. If not, see . 82 | -------------------------------------------------------------------------------- /libserialport.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libserialport project. 3 | * 4 | * Copyright (C) 2013 Martin Ling 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * @mainpage libserialport API 22 | * 23 | * Introduction 24 | * ============ 25 | * 26 | * libserialport is a minimal library written in C that is intended to take 27 | * care of the OS-specific details when writing software that uses serial ports. 28 | * 29 | * By writing your serial code to use libserialport, you enable it to work 30 | * transparently on any platform supported by the library. 31 | * 32 | * The operations that are supported are: 33 | * 34 | * - @ref Enumeration (obtaining a list of serial ports on the system) 35 | * - @ref Ports 36 | * - @ref Configuration (baud rate, parity, etc.) 37 | * - @ref Signals (modem control lines, breaks, etc.) 38 | * - @ref Data 39 | * - @ref Waiting 40 | * - @ref Errors 41 | * 42 | * libserialport is an open source project released under the LGPL3+ license. 43 | * 44 | * API principles 45 | * ============== 46 | * 47 | * The API is simple, and designed to be a minimal wrapper around the serial 48 | * port support in each OS. 49 | * 50 | * Most functions take a pointer to a struct sp_port, which represents a serial 51 | * port. These structures are always allocated and freed by the library, using 52 | * the functions in the @ref Enumeration "Enumeration" section. 53 | * 54 | * Most functions have return type @ref sp_return and can return only four 55 | * possible error values: 56 | * 57 | * - @ref SP_ERR_ARG means that a function was called with invalid 58 | * arguments. This implies a bug in the caller. The arguments passed would 59 | * be invalid regardless of the underlying OS or serial device involved. 60 | * 61 | * - @ref SP_ERR_FAIL means that the OS reported a failure. The error code or 62 | * message provided by the OS can be obtained by calling sp_last_error_code() 63 | * or sp_last_error_message(). 64 | * 65 | * - @ref SP_ERR_SUPP indicates that there is no support for the requested 66 | * operation in the current OS, driver or device. No error message is 67 | * available from the OS in this case. There is either no way to request 68 | * the operation in the first place, or libserialport does not know how to 69 | * do so in the current version. 70 | * 71 | * - @ref SP_ERR_MEM indicates that a memory allocation failed. 72 | * 73 | * All of these error values are negative. 74 | * 75 | * Calls that succeed return @ref SP_OK, which is equal to zero. Some functions 76 | * declared @ref sp_return can also return a positive value for a successful 77 | * numeric result, e.g. sp_blocking_read() or sp_blocking_write(). 78 | */ 79 | 80 | #ifndef LIBSERIALPORT_LIBSERIALPORT_H 81 | #define LIBSERIALPORT_LIBSERIALPORT_H 82 | 83 | #ifdef __cplusplus 84 | extern "C" { 85 | #endif 86 | 87 | #include 88 | #ifdef _WIN32 89 | #include 90 | #endif 91 | 92 | /** Return values. */ 93 | enum sp_return { 94 | /** Operation completed successfully. */ 95 | SP_OK = 0, 96 | /** Invalid arguments were passed to the function. */ 97 | SP_ERR_ARG = -1, 98 | /** A system error occured while executing the operation. */ 99 | SP_ERR_FAIL = -2, 100 | /** A memory allocation failed while executing the operation. */ 101 | SP_ERR_MEM = -3, 102 | /** The requested operation is not supported by this system or device. */ 103 | SP_ERR_SUPP = -4 104 | }; 105 | 106 | /** Port access modes. */ 107 | enum sp_mode { 108 | /** Open port for read access. */ 109 | SP_MODE_READ = 1, 110 | /** Open port for write access. */ 111 | SP_MODE_WRITE = 2, 112 | /** Open port for read and write access. */ 113 | SP_MODE_READ_WRITE = 3 114 | }; 115 | 116 | /** Port events. */ 117 | enum sp_event { 118 | /* Data received and ready to read. */ 119 | SP_EVENT_RX_READY = 1, 120 | /* Ready to transmit new data. */ 121 | SP_EVENT_TX_READY = 2, 122 | /* Error occured. */ 123 | SP_EVENT_ERROR = 4 124 | }; 125 | 126 | /** Buffer selection. */ 127 | enum sp_buffer { 128 | /** Input buffer. */ 129 | SP_BUF_INPUT = 1, 130 | /** Output buffer. */ 131 | SP_BUF_OUTPUT = 2, 132 | /** Both buffers. */ 133 | SP_BUF_BOTH = 3 134 | }; 135 | 136 | /** Parity settings. */ 137 | enum sp_parity { 138 | /** Special value to indicate setting should be left alone. */ 139 | SP_PARITY_INVALID = -1, 140 | /** No parity. */ 141 | SP_PARITY_NONE = 0, 142 | /** Odd parity. */ 143 | SP_PARITY_ODD = 1, 144 | /** Even parity. */ 145 | SP_PARITY_EVEN = 2, 146 | /** Mark parity. */ 147 | SP_PARITY_MARK = 3, 148 | /** Space parity. */ 149 | SP_PARITY_SPACE = 4 150 | }; 151 | 152 | /** RTS pin behaviour. */ 153 | enum sp_rts { 154 | /** Special value to indicate setting should be left alone. */ 155 | SP_RTS_INVALID = -1, 156 | /** RTS off. */ 157 | SP_RTS_OFF = 0, 158 | /** RTS on. */ 159 | SP_RTS_ON = 1, 160 | /** RTS used for flow control. */ 161 | SP_RTS_FLOW_CONTROL = 2 162 | }; 163 | 164 | /** CTS pin behaviour. */ 165 | enum sp_cts { 166 | /** Special value to indicate setting should be left alone. */ 167 | SP_CTS_INVALID = -1, 168 | /** CTS ignored. */ 169 | SP_CTS_IGNORE = 0, 170 | /** CTS used for flow control. */ 171 | SP_CTS_FLOW_CONTROL = 1 172 | }; 173 | 174 | /** DTR pin behaviour. */ 175 | enum sp_dtr { 176 | /** Special value to indicate setting should be left alone. */ 177 | SP_DTR_INVALID = -1, 178 | /** DTR off. */ 179 | SP_DTR_OFF = 0, 180 | /** DTR on. */ 181 | SP_DTR_ON = 1, 182 | /** DTR used for flow control. */ 183 | SP_DTR_FLOW_CONTROL = 2 184 | }; 185 | 186 | /** DSR pin behaviour. */ 187 | enum sp_dsr { 188 | /** Special value to indicate setting should be left alone. */ 189 | SP_DSR_INVALID = -1, 190 | /** DSR ignored. */ 191 | SP_DSR_IGNORE = 0, 192 | /** DSR used for flow control. */ 193 | SP_DSR_FLOW_CONTROL = 1 194 | }; 195 | 196 | /** XON/XOFF flow control behaviour. */ 197 | enum sp_xonxoff { 198 | /** Special value to indicate setting should be left alone. */ 199 | SP_XONXOFF_INVALID = -1, 200 | /** XON/XOFF disabled. */ 201 | SP_XONXOFF_DISABLED = 0, 202 | /** XON/XOFF enabled for input only. */ 203 | SP_XONXOFF_IN = 1, 204 | /** XON/XOFF enabled for output only. */ 205 | SP_XONXOFF_OUT = 2, 206 | /** XON/XOFF enabled for input and output. */ 207 | SP_XONXOFF_INOUT = 3 208 | }; 209 | 210 | /** Standard flow control combinations. */ 211 | enum sp_flowcontrol { 212 | /** No flow control. */ 213 | SP_FLOWCONTROL_NONE = 0, 214 | /** Software flow control using XON/XOFF characters. */ 215 | SP_FLOWCONTROL_XONXOFF = 1, 216 | /** Hardware flow control using RTS/CTS signals. */ 217 | SP_FLOWCONTROL_RTSCTS = 2, 218 | /** Hardware flow control using DTR/DSR signals. */ 219 | SP_FLOWCONTROL_DTRDSR = 3 220 | }; 221 | 222 | /** Input signals. */ 223 | enum sp_signal { 224 | /** Clear to send. */ 225 | SP_SIG_CTS = 1, 226 | /** Data set ready. */ 227 | SP_SIG_DSR = 2, 228 | /** Data carrier detect. */ 229 | SP_SIG_DCD = 4, 230 | /** Ring indicator. */ 231 | SP_SIG_RI = 8 232 | }; 233 | 234 | /** Transport types. */ 235 | enum sp_transport { 236 | /** Native platform serial port. */ 237 | SP_TRANSPORT_NATIVE, 238 | /** USB serial port adapter. */ 239 | SP_TRANSPORT_USB, 240 | /** Bluetooth serial port adapter. */ 241 | SP_TRANSPORT_BLUETOOTH 242 | }; 243 | 244 | /** 245 | * @struct sp_port 246 | * An opaque structure representing a serial port. 247 | */ 248 | struct sp_port; 249 | 250 | /** 251 | * @struct sp_port_config 252 | * An opaque structure representing the configuration for a serial port. 253 | */ 254 | struct sp_port_config; 255 | 256 | /** 257 | * @struct sp_event_set 258 | * A set of handles to wait on for events. 259 | */ 260 | struct sp_event_set { 261 | /** Array of OS-specific handles. */ 262 | void *handles; 263 | /** Array of bitmasks indicating which events apply for each handle. */ 264 | enum sp_event *masks; 265 | /** Number of handles. */ 266 | unsigned int count; 267 | }; 268 | 269 | /** 270 | @defgroup Enumeration Port enumeration 271 | @{ 272 | */ 273 | 274 | /** 275 | * Obtain a pointer to a new sp_port structure representing the named port. 276 | * 277 | * The user should allocate a variable of type "struct sp_port *" and pass a 278 | * pointer to this to receive the result. 279 | * 280 | * The result should be freed after use by calling sp_free_port(). 281 | * 282 | * If any error is returned, the variable pointed to by port_ptr will be set 283 | * to NULL. Otherwise, it will be set to point to the newly allocated port. 284 | * 285 | * @return SP_OK upon success, a negative error code otherwise. 286 | * 287 | * @since 0.1.0 288 | */ 289 | enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr); 290 | 291 | /** 292 | * Free a port structure obtained from sp_get_port_by_name() or sp_copy_port(). 293 | * 294 | * @since 0.1.0 295 | */ 296 | void sp_free_port(struct sp_port *port); 297 | 298 | /** 299 | * List the serial ports available on the system. 300 | * 301 | * The result obtained is an array of pointers to sp_port structures, 302 | * terminated by a NULL. The user should allocate a variable of type 303 | * "struct sp_port **" and pass a pointer to this to receive the result. 304 | * 305 | * The result should be freed after use by calling sp_free_port_list(). 306 | * If a port from the list is to be used after freeing the list, it must be 307 | * copied first using sp_copy_port(). 308 | * 309 | * If any error is returned, the variable pointed to by list_ptr will be set 310 | * to NULL. Otherwise, it will be set to point to the newly allocated array. 311 | * 312 | * @return SP_OK upon success, a negative error code otherwise. 313 | * 314 | * @since 0.1.0 315 | */ 316 | enum sp_return sp_list_ports(struct sp_port ***list_ptr); 317 | 318 | /** 319 | * Make a new copy of a sp_port structure. 320 | * 321 | * The user should allocate a variable of type "struct sp_port *" and pass a 322 | * pointer to this to receive the result. 323 | * 324 | * The copy should be freed after use by calling sp_free_port(). 325 | * 326 | * If any error is returned, the variable pointed to by copy_ptr will be set 327 | * to NULL. Otherwise, it will be set to point to the newly allocated copy. 328 | * 329 | * @return SP_OK upon success, a negative error code otherwise. 330 | * 331 | * @since 0.1.0 332 | */ 333 | enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr); 334 | 335 | /** 336 | * Free a port list obtained from sp_list_ports(). 337 | * 338 | * This will also free all the sp_port structures referred to from the list; 339 | * any that are to be retained must be copied first using sp_copy_port(). 340 | * 341 | * @since 0.1.0 342 | */ 343 | void sp_free_port_list(struct sp_port **ports); 344 | 345 | /** 346 | * @} 347 | * @defgroup Ports Opening, closing and querying ports 348 | * @{ 349 | */ 350 | 351 | /** 352 | * Open the specified serial port. 353 | * 354 | * @param port Pointer to port structure. 355 | * @param flags Flags to use when opening the serial port. 356 | * 357 | * @return SP_OK upon success, a negative error code otherwise. 358 | * 359 | * @since 0.1.0 360 | */ 361 | enum sp_return sp_open(struct sp_port *port, enum sp_mode flags); 362 | 363 | /** 364 | * Close the specified serial port. 365 | * 366 | * @return SP_OK upon success, a negative error code otherwise. 367 | * 368 | * @since 0.1.0 369 | */ 370 | enum sp_return sp_close(struct sp_port *port); 371 | 372 | /** 373 | * Get the name of a port. 374 | * 375 | * The name returned is whatever is normally used to refer to a port on the 376 | * current operating system; e.g. for Windows it will usually be a "COMn" 377 | * device name, and for Unix it will be a device path beginning with "/dev/". 378 | * 379 | * @param port Pointer to port structure. 380 | * 381 | * @return The port name, or NULL if an invalid port is passed. The name 382 | * string is part of the port structure and may not be used after the 383 | * port structure has been freed. 384 | * 385 | * @since 0.1.0 386 | */ 387 | char *sp_get_port_name(const struct sp_port *port); 388 | 389 | /** 390 | * Get a description for a port, to present to end user. 391 | * 392 | * @param port Pointer to port structure. 393 | * 394 | * @return The port description, or NULL if an invalid port is passed. 395 | * The description string is part of the port structure and may not be used 396 | * after the port structure has been freed. 397 | * 398 | * @since 0.2.0 399 | */ 400 | char *sp_get_port_description(struct sp_port *port); 401 | 402 | /** 403 | * Get the transport type used by a port. 404 | * 405 | * @param port Pointer to port structure. 406 | * 407 | * @return The port transport type. 408 | * 409 | * @since 0.2.0 410 | */ 411 | enum sp_transport sp_get_port_transport(struct sp_port *port); 412 | 413 | /** 414 | * Get the USB bus number and address on bus of a USB serial adapter port. 415 | * 416 | * @param port Pointer to port structure. 417 | * @param usb_bus Pointer to variable to store USB bus. 418 | * @param usb_address Pointer to variable to store USB address 419 | * 420 | * @return SP_OK upon success, a negative error code otherwise. 421 | * 422 | * @since 0.2.0 423 | */ 424 | enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port, 425 | int *usb_bus, int *usb_address); 426 | 427 | /** 428 | * Get the USB Vendor ID and Product ID of a USB serial adapter port. 429 | * 430 | * @param port Pointer to port structure. 431 | * @param usb_vid Pointer to variable to store USB VID. 432 | * @param usb_pid Pointer to variable to store USB PID 433 | * 434 | * @return SP_OK upon success, a negative error code otherwise. 435 | * 436 | * @since 0.2.0 437 | */ 438 | enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, int *usb_vid, int *usb_pid); 439 | 440 | /** 441 | * Get the USB manufacturer string of a USB serial adapter port. 442 | * 443 | * @param port Pointer to port structure. 444 | * 445 | * @return The port manufacturer string, or NULL if an invalid port is passed. 446 | * The manufacturer string is part of the port structure and may not be used 447 | * after the port structure has been freed. 448 | * 449 | * @since 0.2.0 450 | */ 451 | char *sp_get_port_usb_manufacturer(const struct sp_port *port); 452 | 453 | /** 454 | * Get the USB product string of a USB serial adapter port. 455 | * 456 | * @param port Pointer to port structure. 457 | * 458 | * @return The port product string, or NULL if an invalid port is passed. 459 | * The product string is part of the port structure and may not be used 460 | * after the port structure has been freed. 461 | * 462 | * @since 0.2.0 463 | */ 464 | char *sp_get_port_usb_product(const struct sp_port *port); 465 | 466 | /** 467 | * Get the USB serial number string of a USB serial adapter port. 468 | * 469 | * @param port Pointer to port structure. 470 | * 471 | * @return The port serial number, or NULL if an invalid port is passed. 472 | * The serial number string is part of the port structure and may not be used 473 | * after the port structure has been freed. 474 | * 475 | * @since 0.2.0 476 | */ 477 | char *sp_get_port_usb_serial(const struct sp_port *port); 478 | 479 | /** 480 | * Get the MAC address of a Bluetooth serial adapter port. 481 | * 482 | * @param port Pointer to port structure. 483 | * 484 | * @return The port MAC address, or NULL if an invalid port is passed. 485 | * The MAC address string is part of the port structure and may not be used 486 | * after the port structure has been freed. 487 | * 488 | * @since 0.2.0 489 | */ 490 | char *sp_get_port_bluetooth_address(const struct sp_port *port); 491 | 492 | /** 493 | * Get the operating system handle for a port. 494 | * 495 | * The type of the handle depends on the operating system. On Unix based 496 | * systems, the handle is a file descriptor of type "int". On Windows, the 497 | * handle is of type "HANDLE". The user should allocate a variable of the 498 | * appropriate type and pass a pointer to this to receive the result. 499 | * 500 | * To obtain a valid handle, the port must first be opened by calling 501 | * sp_open() using the same port structure. 502 | * 503 | * After the port is closed or the port structure freed, the handle may 504 | * no longer be valid. 505 | * 506 | * @warning This feature is provided so that programs may make use of 507 | * OS-specific functionality where desired. Doing so obviously 508 | * comes at a cost in portability. It also cannot be guaranteed 509 | * that direct usage of the OS handle will not conflict with the 510 | * library's own usage of the port. Be careful. 511 | * 512 | * @return SP_OK upon success, a negative error code otherwise. 513 | * 514 | * @since 0.1.0 515 | */ 516 | enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr); 517 | 518 | /** 519 | * @} 520 | * @defgroup Configuration Setting port parameters 521 | * @{ 522 | */ 523 | 524 | /** 525 | * Allocate a port configuration structure. 526 | * 527 | * The user should allocate a variable of type "struct sp_config *" and pass a 528 | * pointer to this to receive the result. The variable will be updated to 529 | * point to the new configuration structure. The structure is opaque and must 530 | * be accessed via the functions provided. 531 | * 532 | * All parameters in the structure will be initialised to special values which 533 | * are ignored by sp_set_config(). 534 | * 535 | * The structure should be freed after use by calling sp_free_config(). 536 | * 537 | * @param config_ptr Pointer to variable to receive result. 538 | * 539 | * @return SP_OK upon success, a negative error code otherwise. 540 | * 541 | * @since 0.1.0 542 | */ 543 | enum sp_return sp_new_config(struct sp_port_config **config_ptr); 544 | 545 | /** 546 | * Free a port configuration structure. 547 | * 548 | * @param config Pointer to configuration structure. 549 | * 550 | * @since 0.1.0 551 | */ 552 | void sp_free_config(struct sp_port_config *config); 553 | 554 | /** 555 | * Get the current configuration of the specified serial port. 556 | * 557 | * The user should allocate a configuration structure using sp_new_config() 558 | * and pass this as the config parameter. The configuration structure will 559 | * be updated with the port configuration. 560 | * 561 | * Any parameters that are configured with settings not recognised or 562 | * supported by libserialport, will be set to special values that are 563 | * ignored by sp_set_config(). 564 | * 565 | * @return SP_OK upon success, a negative error code otherwise. 566 | * 567 | * @since 0.1.0 568 | */ 569 | enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config); 570 | 571 | /** 572 | * Set the configuration for the specified serial port. 573 | * 574 | * For each parameter in the configuration, there is a special value (usually 575 | * -1, but see the documentation for each field). These values will be ignored 576 | * and the corresponding setting left unchanged on the port. 577 | * 578 | * @return SP_OK upon success, a negative error code otherwise. 579 | * 580 | * @since 0.1.0 581 | */ 582 | enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config); 583 | 584 | /** 585 | * Set the baud rate for the specified serial port. 586 | * 587 | * @param port Pointer to port structure. 588 | * @param baudrate Baud rate in bits per second. 589 | * 590 | * @return SP_OK upon success, a negative error code otherwise. 591 | * 592 | * @since 0.1.0 593 | */ 594 | enum sp_return sp_set_baudrate(struct sp_port *port, int baudrate); 595 | 596 | /** 597 | * Get the baud rate from a port configuration. 598 | * 599 | * The user should allocate a variable of type int and pass a pointer to this 600 | * to receive the result. 601 | * 602 | * @param config Pointer to configuration structure. 603 | * @param baudrate_ptr Pointer to variable to store result. 604 | * 605 | * @return SP_OK upon success, a negative error code otherwise. 606 | * 607 | * @since 0.1.0 608 | */ 609 | enum sp_return sp_get_config_baudrate(const struct sp_port_config *config, int *baudrate_ptr); 610 | 611 | /** 612 | * Set the baud rate in a port configuration. 613 | * 614 | * @param config Pointer to configuration structure. 615 | * @param baudrate Baud rate in bits per second, or -1 to retain current setting. 616 | * 617 | * @return SP_OK upon success, a negative error code otherwise. 618 | * 619 | * @since 0.1.0 620 | */ 621 | enum sp_return sp_set_config_baudrate(struct sp_port_config *config, int baudrate); 622 | 623 | /** 624 | * Set the data bits for the specified serial port. 625 | * 626 | * @param port Pointer to port structure. 627 | * @param bits Number of data bits. 628 | * 629 | * @return SP_OK upon success, a negative error code otherwise. 630 | * 631 | * @since 0.1.0 632 | */ 633 | enum sp_return sp_set_bits(struct sp_port *port, int bits); 634 | 635 | /** 636 | * Get the data bits from a port configuration. 637 | * 638 | * The user should allocate a variable of type int and pass a pointer to this 639 | * to receive the result. 640 | * 641 | * @param config Pointer to configuration structure. 642 | * @param bits_ptr Pointer to variable to store result. 643 | * 644 | * @return SP_OK upon success, a negative error code otherwise. 645 | * 646 | * @since 0.1.0 647 | */ 648 | enum sp_return sp_get_config_bits(const struct sp_port_config *config, int *bits_ptr); 649 | 650 | /** 651 | * Set the data bits in a port configuration. 652 | * 653 | * @param config Pointer to configuration structure. 654 | * @param bits Number of data bits, or -1 to retain current setting. 655 | * 656 | * @return SP_OK upon success, a negative error code otherwise. 657 | * 658 | * @since 0.1.0 659 | */ 660 | enum sp_return sp_set_config_bits(struct sp_port_config *config, int bits); 661 | 662 | /** 663 | * Set the parity setting for the specified serial port. 664 | * 665 | * @param port Pointer to port structure. 666 | * @param parity Parity setting. 667 | * 668 | * @return SP_OK upon success, a negative error code otherwise. 669 | * 670 | * @since 0.1.0 671 | */ 672 | enum sp_return sp_set_parity(struct sp_port *port, enum sp_parity parity); 673 | 674 | /** 675 | * Get the parity setting from a port configuration. 676 | * 677 | * The user should allocate a variable of type enum sp_parity and pass a pointer to this 678 | * to receive the result. 679 | * 680 | * @param config Pointer to configuration structure. 681 | * @param parity_ptr Pointer to variable to store result. 682 | * 683 | * @return SP_OK upon success, a negative error code otherwise. 684 | * 685 | * @since 0.1.0 686 | */ 687 | enum sp_return sp_get_config_parity(const struct sp_port_config *config, enum sp_parity *parity_ptr); 688 | 689 | /** 690 | * Set the parity setting in a port configuration. 691 | * 692 | * @param config Pointer to configuration structure. 693 | * @param parity Parity setting, or -1 to retain current setting. 694 | * 695 | * @return SP_OK upon success, a negative error code otherwise. 696 | * 697 | * @since 0.1.0 698 | */ 699 | enum sp_return sp_set_config_parity(struct sp_port_config *config, enum sp_parity parity); 700 | 701 | /** 702 | * Set the stop bits for the specified serial port. 703 | * 704 | * @param port Pointer to port structure. 705 | * @param stopbits Number of stop bits. 706 | * 707 | * @return SP_OK upon success, a negative error code otherwise. 708 | * 709 | * @since 0.1.0 710 | */ 711 | enum sp_return sp_set_stopbits(struct sp_port *port, int stopbits); 712 | 713 | /** 714 | * Get the stop bits from a port configuration. 715 | * 716 | * The user should allocate a variable of type int and pass a pointer to this 717 | * to receive the result. 718 | * 719 | * @param config Pointer to configuration structure. 720 | * @param stopbits_ptr Pointer to variable to store result. 721 | * 722 | * @return SP_OK upon success, a negative error code otherwise. 723 | * 724 | * @since 0.1.0 725 | */ 726 | enum sp_return sp_get_config_stopbits(const struct sp_port_config *config, int *stopbits_ptr); 727 | 728 | /** 729 | * Set the stop bits in a port configuration. 730 | * 731 | * @param config Pointer to configuration structure. 732 | * @param stopbits Number of stop bits, or -1 to retain current setting. 733 | * 734 | * @return SP_OK upon success, a negative error code otherwise. 735 | * 736 | * @since 0.1.0 737 | */ 738 | enum sp_return sp_set_config_stopbits(struct sp_port_config *config, int stopbits); 739 | 740 | /** 741 | * Set the RTS pin behaviour for the specified serial port. 742 | * 743 | * @param port Pointer to port structure. 744 | * @param rts RTS pin mode. 745 | * 746 | * @return SP_OK upon success, a negative error code otherwise. 747 | * 748 | * @since 0.1.0 749 | */ 750 | enum sp_return sp_set_rts(struct sp_port *port, enum sp_rts rts); 751 | 752 | /** 753 | * Get the RTS pin behaviour from a port configuration. 754 | * 755 | * The user should allocate a variable of type enum sp_rts and pass a pointer to this 756 | * to receive the result. 757 | * 758 | * @param config Pointer to configuration structure. 759 | * @param rts_ptr Pointer to variable to store result. 760 | * 761 | * @return SP_OK upon success, a negative error code otherwise. 762 | * 763 | * @since 0.1.0 764 | */ 765 | enum sp_return sp_get_config_rts(const struct sp_port_config *config, enum sp_rts *rts_ptr); 766 | 767 | /** 768 | * Set the RTS pin behaviour in a port configuration. 769 | * 770 | * @param config Pointer to configuration structure. 771 | * @param rts RTS pin mode, or -1 to retain current setting. 772 | * 773 | * @return SP_OK upon success, a negative error code otherwise. 774 | * 775 | * @since 0.1.0 776 | */ 777 | enum sp_return sp_set_config_rts(struct sp_port_config *config, enum sp_rts rts); 778 | 779 | /** 780 | * Set the CTS pin behaviour for the specified serial port. 781 | * 782 | * @param port Pointer to port structure. 783 | * @param cts CTS pin mode. 784 | * 785 | * @return SP_OK upon success, a negative error code otherwise. 786 | * 787 | * @since 0.1.0 788 | */ 789 | enum sp_return sp_set_cts(struct sp_port *port, enum sp_cts cts); 790 | 791 | /** 792 | * Get the CTS pin behaviour from a port configuration. 793 | * 794 | * The user should allocate a variable of type enum sp_cts and pass a pointer to this 795 | * to receive the result. 796 | * 797 | * @param config Pointer to configuration structure. 798 | * @param cts_ptr Pointer to variable to store result. 799 | * 800 | * @return SP_OK upon success, a negative error code otherwise. 801 | * 802 | * @since 0.1.0 803 | */ 804 | enum sp_return sp_get_config_cts(const struct sp_port_config *config, enum sp_cts *cts_ptr); 805 | 806 | /** 807 | * Set the CTS pin behaviour in a port configuration. 808 | * 809 | * @param config Pointer to configuration structure. 810 | * @param cts CTS pin mode, or -1 to retain current setting. 811 | * 812 | * @return SP_OK upon success, a negative error code otherwise. 813 | * 814 | * @since 0.1.0 815 | */ 816 | enum sp_return sp_set_config_cts(struct sp_port_config *config, enum sp_cts cts); 817 | 818 | /** 819 | * Set the DTR pin behaviour for the specified serial port. 820 | * 821 | * @param port Pointer to port structure. 822 | * @param dtr DTR pin mode. 823 | * 824 | * @return SP_OK upon success, a negative error code otherwise. 825 | * 826 | * @since 0.1.0 827 | */ 828 | enum sp_return sp_set_dtr(struct sp_port *port, enum sp_dtr dtr); 829 | 830 | /** 831 | * Get the DTR pin behaviour from a port configuration. 832 | * 833 | * The user should allocate a variable of type enum sp_dtr and pass a pointer to this 834 | * to receive the result. 835 | * 836 | * @param config Pointer to configuration structure. 837 | * @param dtr_ptr Pointer to variable to store result. 838 | * 839 | * @return SP_OK upon success, a negative error code otherwise. 840 | * 841 | * @since 0.1.0 842 | */ 843 | enum sp_return sp_get_config_dtr(const struct sp_port_config *config, enum sp_dtr *dtr_ptr); 844 | 845 | /** 846 | * Set the DTR pin behaviour in a port configuration. 847 | * 848 | * @param config Pointer to configuration structure. 849 | * @param dtr DTR pin mode, or -1 to retain current setting. 850 | * 851 | * @return SP_OK upon success, a negative error code otherwise. 852 | * 853 | * @since 0.1.0 854 | */ 855 | enum sp_return sp_set_config_dtr(struct sp_port_config *config, enum sp_dtr dtr); 856 | 857 | /** 858 | * Set the DSR pin behaviour for the specified serial port. 859 | * 860 | * @param port Pointer to port structure. 861 | * @param dsr DSR pin mode. 862 | * 863 | * @return SP_OK upon success, a negative error code otherwise. 864 | * 865 | * @since 0.1.0 866 | */ 867 | enum sp_return sp_set_dsr(struct sp_port *port, enum sp_dsr dsr); 868 | 869 | /** 870 | * Get the DSR pin behaviour from a port configuration. 871 | * 872 | * The user should allocate a variable of type enum sp_dsr and pass a pointer to this 873 | * to receive the result. 874 | * 875 | * @param config Pointer to configuration structure. 876 | * @param dsr_ptr Pointer to variable to store result. 877 | * 878 | * @return SP_OK upon success, a negative error code otherwise. 879 | * 880 | * @since 0.1.0 881 | */ 882 | enum sp_return sp_get_config_dsr(const struct sp_port_config *config, enum sp_dsr *dsr_ptr); 883 | 884 | /** 885 | * Set the DSR pin behaviour in a port configuration. 886 | * 887 | * @param config Pointer to configuration structure. 888 | * @param dsr DSR pin mode, or -1 to retain current setting. 889 | * 890 | * @return SP_OK upon success, a negative error code otherwise. 891 | * 892 | * @since 0.1.0 893 | */ 894 | enum sp_return sp_set_config_dsr(struct sp_port_config *config, enum sp_dsr dsr); 895 | 896 | /** 897 | * Set the XON/XOFF configuration for the specified serial port. 898 | * 899 | * @param port Pointer to port structure. 900 | * @param xon_xoff XON/XOFF mode. 901 | * 902 | * @return SP_OK upon success, a negative error code otherwise. 903 | * 904 | * @since 0.1.0 905 | */ 906 | enum sp_return sp_set_xon_xoff(struct sp_port *port, enum sp_xonxoff xon_xoff); 907 | 908 | /** 909 | * Get the XON/XOFF configuration from a port configuration. 910 | * 911 | * The user should allocate a variable of type enum sp_xonxoff and pass a pointer to this 912 | * to receive the result. 913 | * 914 | * @param config Pointer to configuration structure. 915 | * @param xon_xoff_ptr Pointer to variable to store result. 916 | * 917 | * @return SP_OK upon success, a negative error code otherwise. 918 | * 919 | * @since 0.1.0 920 | */ 921 | enum sp_return sp_get_config_xon_xoff(const struct sp_port_config *config, enum sp_xonxoff *xon_xoff_ptr); 922 | 923 | /** 924 | * Set the XON/XOFF configuration in a port configuration. 925 | * 926 | * @param config Pointer to configuration structure. 927 | * @param xon_xoff XON/XOFF mode, or -1 to retain current setting. 928 | * 929 | * @return SP_OK upon success, a negative error code otherwise. 930 | * 931 | * @since 0.1.0 932 | */ 933 | enum sp_return sp_set_config_xon_xoff(struct sp_port_config *config, enum sp_xonxoff xon_xoff); 934 | 935 | /** 936 | * Set the flow control type in a port configuration. 937 | * 938 | * This function is a wrapper that sets the RTS, CTS, DTR, DSR and 939 | * XON/XOFF settings as necessary for the specified flow control 940 | * type. For more fine-grained control of these settings, use their 941 | * individual configuration functions. 942 | * 943 | * @param config Pointer to configuration structure. 944 | * @param flowcontrol Flow control setting to use. 945 | * 946 | * @return SP_OK upon success, a negative error code otherwise. 947 | * 948 | * @since 0.1.0 949 | */ 950 | enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, enum sp_flowcontrol flowcontrol); 951 | 952 | /** 953 | * Set the flow control type for the specified serial port. 954 | * 955 | * This function is a wrapper that sets the RTS, CTS, DTR, DSR and 956 | * XON/XOFF settings as necessary for the specified flow control 957 | * type. For more fine-grained control of these settings, use their 958 | * individual configuration functions. 959 | * 960 | * @param port Pointer to port structure. 961 | * @param flowcontrol Flow control setting to use. 962 | * 963 | * @return SP_OK upon success, a negative error code otherwise. 964 | * 965 | * @since 0.1.0 966 | */ 967 | enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol); 968 | 969 | /** 970 | * @} 971 | * @defgroup Data Reading, writing, and flushing data 972 | * @{ 973 | */ 974 | 975 | /** 976 | * Read bytes from the specified serial port, blocking until complete. 977 | * 978 | * @warning If your program runs on Unix, defines its own signal handlers, and 979 | * needs to abort blocking reads when these are called, then you 980 | * should not use this function. It repeats system calls that return 981 | * with EINTR. To be able to abort a read from a signal handler, you 982 | * should implement your own blocking read using sp_nonblocking_read() 983 | * together with a blocking method that makes sense for your program. 984 | * E.g. you can obtain the file descriptor for an open port using 985 | * sp_get_port_handle() and use this to call select() or pselect(), 986 | * with appropriate arrangements to return if a signal is received. 987 | * 988 | * @param port Pointer to port structure. 989 | * @param buf Buffer in which to store the bytes read. 990 | * @param count Requested number of bytes to read. 991 | * @param timeout Timeout in milliseconds, or zero to wait indefinitely. 992 | * 993 | * @return The number of bytes read on success, or a negative error code. If 994 | * the number of bytes returned is less than that requested, the 995 | * timeout was reached before the requested number of bytes was 996 | * available. If timeout is zero, the function will always return 997 | * either the requested number of bytes or a negative error code. 998 | * 999 | * @since 0.1.0 1000 | */ 1001 | enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, unsigned int timeout); 1002 | 1003 | /** 1004 | * Read bytes from the specified serial port, without blocking. 1005 | * 1006 | * @param port Pointer to port structure. 1007 | * @param buf Buffer in which to store the bytes read. 1008 | * @param count Maximum number of bytes to read. 1009 | * 1010 | * @return The number of bytes read on success, or a negative error code. The 1011 | * number of bytes returned may be any number from zero to the maximum 1012 | * that was requested. 1013 | * 1014 | * @since 0.1.0 1015 | */ 1016 | enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count); 1017 | 1018 | /** 1019 | * Write bytes to the specified serial port, blocking until complete. 1020 | * 1021 | * Note that this function only ensures that the accepted bytes have been 1022 | * written to the OS; they may be held in driver or hardware buffers and not 1023 | * yet physically transmitted. To check whether all written bytes have actually 1024 | * been transmitted, use the sp_output_waiting() function. To wait until all 1025 | * written bytes have actually been transmitted, use the sp_drain() function. 1026 | * 1027 | * @warning If your program runs on Unix, defines its own signal handlers, and 1028 | * needs to abort blocking writes when these are called, then you 1029 | * should not use this function. It repeats system calls that return 1030 | * with EINTR. To be able to abort a write from a signal handler, you 1031 | * should implement your own blocking write using sp_nonblocking_write() 1032 | * together with a blocking method that makes sense for your program. 1033 | * E.g. you can obtain the file descriptor for an open port using 1034 | * sp_get_port_handle() and use this to call select() or pselect(), 1035 | * with appropriate arrangements to return if a signal is received. 1036 | * 1037 | * @param port Pointer to port structure. 1038 | * @param buf Buffer containing the bytes to write. 1039 | * @param count Requested number of bytes to write. 1040 | * @param timeout Timeout in milliseconds, or zero to wait indefinitely. 1041 | * 1042 | * @return The number of bytes written on success, or a negative error code. 1043 | * If the number of bytes returned is less than that requested, the 1044 | * timeout was reached before the requested number of bytes was 1045 | * written. If timeout is zero, the function will always return 1046 | * either the requested number of bytes or a negative error code. In 1047 | * the event of an error there is no way to determine how many bytes 1048 | * were sent before the error occured. 1049 | * 1050 | * @since 0.1.0 1051 | */ 1052 | enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout); 1053 | 1054 | /** 1055 | * Write bytes to the specified serial port, without blocking. 1056 | * 1057 | * Note that this function only ensures that the accepted bytes have been 1058 | * written to the OS; they may be held in driver or hardware buffers and not 1059 | * yet physically transmitted. To check whether all written bytes have actually 1060 | * been transmitted, use the sp_output_waiting() function. To wait until all 1061 | * written bytes have actually been transmitted, use the sp_drain() function. 1062 | * 1063 | * @param port Pointer to port structure. 1064 | * @param buf Buffer containing the bytes to write. 1065 | * @param count Maximum number of bytes to write. 1066 | * 1067 | * @return The number of bytes written on success, or a negative error code. 1068 | * The number of bytes returned may be any number from zero to the 1069 | * maximum that was requested. 1070 | * 1071 | * @since 0.1.0 1072 | */ 1073 | enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_t count); 1074 | 1075 | /** 1076 | * Gets the number of bytes waiting in the input buffer. 1077 | * 1078 | * @param port Pointer to port structure. 1079 | * 1080 | * @return Number of bytes waiting on success, a negative error code otherwise. 1081 | * 1082 | * @since 0.1.0 1083 | */ 1084 | enum sp_return sp_input_waiting(struct sp_port *port); 1085 | 1086 | /** 1087 | * Gets the number of bytes waiting in the output buffer. 1088 | * 1089 | * @param port Pointer to port structure. 1090 | * 1091 | * @return Number of bytes waiting on success, a negative error code otherwise. 1092 | * 1093 | * @since 0.1.0 1094 | */ 1095 | enum sp_return sp_output_waiting(struct sp_port *port); 1096 | 1097 | /** 1098 | * Flush serial port buffers. Data in the selected buffer(s) is discarded. 1099 | * 1100 | * @param port Pointer to port structure. 1101 | * @param buffers Which buffer(s) to flush. 1102 | * 1103 | * @return SP_OK upon success, a negative error code otherwise. 1104 | * 1105 | * @since 0.1.0 1106 | */ 1107 | enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers); 1108 | 1109 | /** 1110 | * Wait for buffered data to be transmitted. 1111 | * 1112 | * @warning If your program runs on Unix, defines its own signal handlers, and 1113 | * needs to abort draining the output buffer when when these are 1114 | * called, then you should not use this function. It repeats system 1115 | * calls that return with EINTR. To be able to abort a drain from a 1116 | * signal handler, you would need to implement your own blocking 1117 | * drain by polling the result of sp_output_waiting(). 1118 | * 1119 | * @param port Pointer to port structure. 1120 | * 1121 | * @return SP_OK upon success, a negative error code otherwise. 1122 | * 1123 | * @since 0.1.0 1124 | */ 1125 | enum sp_return sp_drain(struct sp_port *port); 1126 | 1127 | /** 1128 | * @} 1129 | * @defgroup Waiting Waiting for events 1130 | * @{ 1131 | */ 1132 | 1133 | /** 1134 | * Allocate storage for a set of events. 1135 | * 1136 | * The user should allocate a variable of type struct sp_event_set *, 1137 | * then pass a pointer to this variable to receive the result. 1138 | * 1139 | * The result should be freed after use by calling sp_free_event_set(). 1140 | * 1141 | * @return SP_OK upon success, a negative error code otherwise. 1142 | * 1143 | * @since 0.1.0 1144 | */ 1145 | enum sp_return sp_new_event_set(struct sp_event_set **result_ptr); 1146 | 1147 | /** 1148 | * Add events to a struct sp_event_set for a given port. 1149 | * 1150 | * The port must first be opened by calling sp_open() using the same port 1151 | * structure. 1152 | * 1153 | * After the port is closed or the port structure freed, the results may 1154 | * no longer be valid. 1155 | * 1156 | * @param event_set Event set to update. 1157 | * @param port Pointer to port structure. 1158 | * @param mask Bitmask of events to be waited for. 1159 | * 1160 | * @return SP_OK upon success, a negative error code otherwise. 1161 | * 1162 | * @since 0.1.0 1163 | */ 1164 | enum sp_return sp_add_port_events(struct sp_event_set *event_set, 1165 | const struct sp_port *port, enum sp_event mask); 1166 | 1167 | /** 1168 | * Wait for any of a set of events to occur. 1169 | * 1170 | * @param event_set Event set to wait on. 1171 | * @param timeout Timeout in milliseconds, or zero to wait indefinitely. 1172 | * 1173 | * @return SP_OK upon success, a negative error code otherwise. 1174 | * 1175 | * @since 0.1.0 1176 | */ 1177 | enum sp_return sp_wait(struct sp_event_set *event_set, unsigned int timeout); 1178 | 1179 | /** 1180 | * Free a structure allocated by sp_new_event_set(). 1181 | * 1182 | * @since 0.1.0 1183 | */ 1184 | void sp_free_event_set(struct sp_event_set *event_set); 1185 | 1186 | /** 1187 | * @} 1188 | * @defgroup Signals Port signalling operations 1189 | * @{ 1190 | */ 1191 | 1192 | /** 1193 | * Gets the status of the control signals for the specified port. 1194 | * 1195 | * The user should allocate a variable of type "enum sp_signal" and pass a 1196 | * pointer to this variable to receive the result. The result is a bitmask 1197 | * in which individual signals can be checked by bitwise OR with values of 1198 | * the sp_signal enum. 1199 | * 1200 | * @param port Pointer to port structure. 1201 | * @param signal_mask Pointer to variable to receive result. 1202 | * 1203 | * @return SP_OK upon success, a negative error code otherwise. 1204 | * 1205 | * @since 0.1.0 1206 | */ 1207 | enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signal_mask); 1208 | 1209 | /** 1210 | * Put the port transmit line into the break state. 1211 | * 1212 | * @param port Pointer to port structure. 1213 | * 1214 | * @return SP_OK upon success, a negative error code otherwise. 1215 | * 1216 | * @since 0.1.0 1217 | */ 1218 | enum sp_return sp_start_break(struct sp_port *port); 1219 | 1220 | /** 1221 | * Take the port transmit line out of the break state. 1222 | * 1223 | * @param port Pointer to port structure. 1224 | * 1225 | * @return SP_OK upon success, a negative error code otherwise. 1226 | * 1227 | * @since 0.1.0 1228 | */ 1229 | enum sp_return sp_end_break(struct sp_port *port); 1230 | 1231 | /** 1232 | * @} 1233 | * @defgroup Errors Obtaining error information 1234 | * @{ 1235 | */ 1236 | 1237 | /** 1238 | * Get the error code for a failed operation. 1239 | * 1240 | * In order to obtain the correct result, this function should be called 1241 | * straight after the failure, before executing any other system operations. 1242 | * 1243 | * @return The system's numeric code for the error that caused the last 1244 | * operation to fail. 1245 | * 1246 | * @since 0.1.0 1247 | */ 1248 | int sp_last_error_code(void); 1249 | 1250 | /** 1251 | * Get the error message for a failed operation. 1252 | * 1253 | * In order to obtain the correct result, this function should be called 1254 | * straight after the failure, before executing other system operations. 1255 | * 1256 | * @return The system's message for the error that caused the last 1257 | * operation to fail. This string may be allocated by the function, 1258 | * and should be freed after use by calling sp_free_error_message(). 1259 | * 1260 | * @since 0.1.0 1261 | */ 1262 | char *sp_last_error_message(void); 1263 | 1264 | /** 1265 | * Free an error message returned by sp_last_error_message(). 1266 | * 1267 | * @since 0.1.0 1268 | */ 1269 | void sp_free_error_message(char *message); 1270 | 1271 | /** 1272 | * Set the handler function for library debugging messages. 1273 | * 1274 | * Debugging messages are generated by the library during each operation, 1275 | * to help in diagnosing problems. The handler will be called for each 1276 | * message. The handler can be set to NULL to ignore all debug messages. 1277 | * 1278 | * The handler function should accept a format string and variable length 1279 | * argument list, in the same manner as e.g. printf(). 1280 | * 1281 | * The default handler is sp_default_debug_handler(). 1282 | * 1283 | * @since 0.1.0 1284 | */ 1285 | void sp_set_debug_handler(void (*handler)(const char *format, ...)); 1286 | 1287 | /** 1288 | * Default handler function for library debugging messages. 1289 | * 1290 | * This function prints debug messages to the standard error stream if the 1291 | * environment variable LIBSERIALPORT_DEBUG is set. Otherwise, they are 1292 | * ignored. 1293 | * 1294 | * @since 0.1.0 1295 | */ 1296 | void sp_default_debug_handler(const char *format, ...); 1297 | 1298 | /** @} */ 1299 | 1300 | /** 1301 | * @defgroup Versions Version number querying functions, definitions, and macros 1302 | * 1303 | * This set of API calls returns two different version numbers related 1304 | * to libserialport. The "package version" is the release version number of the 1305 | * libserialport tarball in the usual "major.minor.micro" format, e.g. "0.1.0". 1306 | * 1307 | * The "library version" is independent of that; it is the libtool version 1308 | * number in the "current:revision:age" format, e.g. "2:0:0". 1309 | * See http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning for details. 1310 | * 1311 | * Both version numbers (and/or individual components of them) can be 1312 | * retrieved via the API calls at runtime, and/or they can be checked at 1313 | * compile/preprocessor time using the respective macros. 1314 | * 1315 | * @{ 1316 | */ 1317 | 1318 | /* 1319 | * Package version macros (can be used for conditional compilation). 1320 | */ 1321 | 1322 | /** The libserialport package 'major' version number. */ 1323 | #define SP_PACKAGE_VERSION_MAJOR 0 1324 | 1325 | /** The libserialport package 'minor' version number. */ 1326 | #define SP_PACKAGE_VERSION_MINOR 2 1327 | 1328 | /** The libserialport package 'micro' version number. */ 1329 | #define SP_PACKAGE_VERSION_MICRO 0 1330 | 1331 | /** The libserialport package version ("major.minor.micro") as string. */ 1332 | #define SP_PACKAGE_VERSION_STRING "0.2.0" 1333 | 1334 | /* 1335 | * Library/libtool version macros (can be used for conditional compilation). 1336 | */ 1337 | 1338 | /** The libserialport libtool 'current' version number. */ 1339 | #define SP_LIB_VERSION_CURRENT 0 1340 | 1341 | /** The libserialport libtool 'revision' version number. */ 1342 | #define SP_LIB_VERSION_REVISION 0 1343 | 1344 | /** The libserialport libtool 'age' version number. */ 1345 | #define SP_LIB_VERSION_AGE 0 1346 | 1347 | /** The libserialport libtool version ("current:revision:age") as string. */ 1348 | #define SP_LIB_VERSION_STRING "0:0:0" 1349 | 1350 | /** 1351 | * Get the major libserialport package version number. 1352 | * 1353 | * @return The major package version number. 1354 | * 1355 | * @since 0.1.0 1356 | */ 1357 | int sp_get_major_package_version(void); 1358 | 1359 | /** 1360 | * Get the minor libserialport package version number. 1361 | * 1362 | * @return The minor package version number. 1363 | * 1364 | * @since 0.1.0 1365 | */ 1366 | int sp_get_minor_package_version(void); 1367 | 1368 | /** 1369 | * Get the micro libserialport package version number. 1370 | * 1371 | * @return The micro package version number. 1372 | * 1373 | * @since 0.1.0 1374 | */ 1375 | int sp_get_micro_package_version(void); 1376 | 1377 | /** 1378 | * Get the libserialport package version number as a string. 1379 | * 1380 | * @return The package version number string. The returned string is 1381 | * static and thus should NOT be free'd by the caller. 1382 | * 1383 | * @since 0.1.0 1384 | */ 1385 | const char *sp_get_package_version_string(void); 1386 | 1387 | /** 1388 | * Get the "current" part of the libserialport library version number. 1389 | * 1390 | * @return The "current" library version number. 1391 | * 1392 | * @since 0.1.0 1393 | */ 1394 | int sp_get_current_lib_version(void); 1395 | 1396 | /** 1397 | * Get the "revision" part of the libserialport library version number. 1398 | * 1399 | * @return The "revision" library version number. 1400 | * 1401 | * @since 0.1.0 1402 | */ 1403 | int sp_get_revision_lib_version(void); 1404 | 1405 | /** 1406 | * Get the "age" part of the libserialport library version number. 1407 | * 1408 | * @return The "age" library version number. 1409 | * 1410 | * @since 0.1.0 1411 | */ 1412 | int sp_get_age_lib_version(void); 1413 | 1414 | /** 1415 | * Get the libserialport library version number as a string. 1416 | * 1417 | * @return The library version number string. The returned string is 1418 | * static and thus should NOT be free'd by the caller. 1419 | * 1420 | * @since 0.1.0 1421 | */ 1422 | const char *sp_get_lib_version_string(void); 1423 | 1424 | /** @} */ 1425 | 1426 | #ifdef __cplusplus 1427 | } 1428 | #endif 1429 | 1430 | #endif 1431 | -------------------------------------------------------------------------------- /libserialport_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libserialport project. 3 | * 4 | * Copyright (C) 2014 Martin Ling 5 | * Copyright (C) 2014 Aurelien Jacobs 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation, either version 3 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #ifdef __linux__ 22 | #define _BSD_SOURCE // for timeradd, timersub, timercmp 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #ifdef _WIN32 35 | #include 36 | #include 37 | #include 38 | #include 39 | #undef DEFINE_GUID 40 | #define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ 41 | static const GUID name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } 42 | #include 43 | #include 44 | #else 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #endif 52 | #ifdef __APPLE__ 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #endif 59 | #ifdef __linux__ 60 | #include 61 | #ifndef __ANDROID__ 62 | #include "linux/serial.h" 63 | #endif 64 | #include "linux_termios.h" 65 | 66 | /* TCGETX/TCSETX is not available everywhere. */ 67 | #if defined(TCGETX) && defined(TCSETX) && defined(HAVE_TERMIOX) 68 | #define USE_TERMIOX 69 | #endif 70 | #endif 71 | 72 | /* TIOCINQ/TIOCOUTQ is not available everywhere. */ 73 | #if !defined(TIOCINQ) && defined(FIONREAD) 74 | #define TIOCINQ FIONREAD 75 | #endif 76 | #if !defined(TIOCOUTQ) && defined(FIONWRITE) 77 | #define TIOCOUTQ FIONWRITE 78 | #endif 79 | 80 | /* Non-standard baudrates are not available everywhere. */ 81 | #if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && defined(HAVE_BOTHER) 82 | #define USE_TERMIOS_SPEED 83 | #endif 84 | 85 | struct sp_port { 86 | char *name; 87 | char *description; 88 | enum sp_transport transport; 89 | int usb_bus; 90 | int usb_address; 91 | int usb_vid; 92 | int usb_pid; 93 | char *usb_manufacturer; 94 | char *usb_product; 95 | char *usb_serial; 96 | char *bluetooth_address; 97 | #ifdef _WIN32 98 | char *usb_path; 99 | HANDLE hdl; 100 | COMMTIMEOUTS timeouts; 101 | OVERLAPPED write_ovl; 102 | OVERLAPPED read_ovl; 103 | OVERLAPPED wait_ovl; 104 | DWORD events; 105 | BYTE pending_byte; 106 | BOOL writing; 107 | #else 108 | int fd; 109 | #endif 110 | }; 111 | 112 | struct sp_port_config { 113 | int baudrate; 114 | int bits; 115 | enum sp_parity parity; 116 | int stopbits; 117 | enum sp_rts rts; 118 | enum sp_cts cts; 119 | enum sp_dtr dtr; 120 | enum sp_dsr dsr; 121 | enum sp_xonxoff xon_xoff; 122 | }; 123 | 124 | struct port_data { 125 | #ifdef _WIN32 126 | DCB dcb; 127 | #else 128 | struct termios term; 129 | int controlbits; 130 | int termiox_supported; 131 | int rts_flow; 132 | int cts_flow; 133 | int dtr_flow; 134 | int dsr_flow; 135 | #endif 136 | }; 137 | 138 | #ifdef _WIN32 139 | typedef HANDLE event_handle; 140 | #else 141 | typedef int event_handle; 142 | #endif 143 | 144 | /* Standard baud rates. */ 145 | #ifdef _WIN32 146 | #define BAUD_TYPE DWORD 147 | #define BAUD(n) {CBR_##n, n} 148 | #else 149 | #define BAUD_TYPE speed_t 150 | #define BAUD(n) {B##n, n} 151 | #endif 152 | 153 | struct std_baudrate { 154 | BAUD_TYPE index; 155 | int value; 156 | }; 157 | 158 | extern const struct std_baudrate std_baudrates[]; 159 | 160 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 161 | #define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates) 162 | 163 | extern void (*sp_debug_handler)(const char *format, ...); 164 | 165 | /* Debug output macros. */ 166 | #define DEBUG_FMT(fmt, ...) do { \ 167 | if (sp_debug_handler) \ 168 | sp_debug_handler(fmt ".\n", __VA_ARGS__); \ 169 | } while (0) 170 | #define DEBUG(msg) DEBUG_FMT(msg, NULL) 171 | #define DEBUG_ERROR(err, msg) DEBUG_FMT("%s returning " #err ": " msg, __func__) 172 | #define DEBUG_FAIL(msg) do { \ 173 | char *errmsg = sp_last_error_message(); \ 174 | DEBUG_FMT("%s returning SP_ERR_FAIL: " msg ": %s", __func__, errmsg); \ 175 | sp_free_error_message(errmsg); \ 176 | } while (0); 177 | #define RETURN() do { \ 178 | DEBUG_FMT("%s returning", __func__); \ 179 | return; \ 180 | } while(0) 181 | #define RETURN_CODE(x) do { \ 182 | DEBUG_FMT("%s returning " #x, __func__); \ 183 | return x; \ 184 | } while (0) 185 | #define RETURN_CODEVAL(x) do { \ 186 | switch (x) { \ 187 | case SP_OK: RETURN_CODE(SP_OK); \ 188 | case SP_ERR_ARG: RETURN_CODE(SP_ERR_ARG); \ 189 | case SP_ERR_FAIL: RETURN_CODE(SP_ERR_FAIL); \ 190 | case SP_ERR_MEM: RETURN_CODE(SP_ERR_MEM); \ 191 | case SP_ERR_SUPP: RETURN_CODE(SP_ERR_SUPP); \ 192 | } \ 193 | } while (0) 194 | #define RETURN_OK() RETURN_CODE(SP_OK); 195 | #define RETURN_ERROR(err, msg) do { \ 196 | DEBUG_ERROR(err, msg); \ 197 | return err; \ 198 | } while (0) 199 | #define RETURN_FAIL(msg) do { \ 200 | DEBUG_FAIL(msg); \ 201 | return SP_ERR_FAIL; \ 202 | } while (0) 203 | #define RETURN_INT(x) do { \ 204 | int _x = x; \ 205 | DEBUG_FMT("%s returning %d", __func__, _x); \ 206 | return _x; \ 207 | } while (0) 208 | #define RETURN_STRING(x) do { \ 209 | char *_x = x; \ 210 | DEBUG_FMT("%s returning %s", __func__, _x); \ 211 | return _x; \ 212 | } while (0) 213 | #define RETURN_POINTER(x) do { \ 214 | void *_x = x; \ 215 | DEBUG_FMT("%s returning %p", __func__, _x); \ 216 | return _x; \ 217 | } while (0) 218 | #define SET_ERROR(val, err, msg) do { DEBUG_ERROR(err, msg); val = err; } while (0) 219 | #define SET_FAIL(val, msg) do { DEBUG_FAIL(msg); val = SP_ERR_FAIL; } while (0) 220 | #define TRACE(fmt, ...) DEBUG_FMT("%s(" fmt ") called", __func__, __VA_ARGS__) 221 | #define TRACE_VOID() DEBUG_FMT("%s() called", __func__) 222 | 223 | #define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0) 224 | 225 | SP_PRIV struct sp_port **list_append(struct sp_port **list, const char *portname); 226 | 227 | /* OS-specific Helper functions. */ 228 | SP_PRIV enum sp_return get_port_details(struct sp_port *port); 229 | SP_PRIV enum sp_return list_ports(struct sp_port ***list); 230 | -------------------------------------------------------------------------------- /linux.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libserialport project. 3 | * 4 | * Copyright (C) 2014 Aurelien Jacobs 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifdef __linux__ 21 | 22 | #include "libserialport.h" 23 | #include "libserialport_internal.h" 24 | 25 | SP_PRIV enum sp_return get_port_details(struct sp_port *port) 26 | { 27 | /* Description limited to 127 char, 28 | anything longer would not be user friendly anyway */ 29 | char description[128]; 30 | int bus, address; 31 | unsigned int vid, pid; 32 | char manufacturer[128], product[128], serial[128]; 33 | char baddr[32]; 34 | const char dir_name[] = "/sys/class/tty/%s/device/%s%s"; 35 | char sub_dir[32] = "", file_name[PATH_MAX]; 36 | char *ptr, *dev = port->name + 5; 37 | FILE *file; 38 | int i, count; 39 | 40 | if (strncmp(port->name, "/dev/", 5)) 41 | RETURN_ERROR(SP_ERR_ARG, "Device name not recognized."); 42 | 43 | snprintf(file_name, sizeof(file_name), "/sys/class/tty/%s", dev); 44 | count = readlink(file_name, file_name, sizeof(file_name)); 45 | if (count <= 0 || count >= (int) sizeof(file_name)-1) 46 | RETURN_ERROR(SP_ERR_ARG, "Device not found."); 47 | file_name[count] = 0; 48 | if (strstr(file_name, "bluetooth")) 49 | port->transport = SP_TRANSPORT_BLUETOOTH; 50 | else if (strstr(file_name, "usb")) 51 | port->transport = SP_TRANSPORT_USB; 52 | 53 | if (port->transport == SP_TRANSPORT_USB) { 54 | for (i=0; i<5; i++) { 55 | strcat(sub_dir, "../"); 56 | 57 | snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "busnum"); 58 | if (!(file = fopen(file_name, "r"))) 59 | continue; 60 | count = fscanf(file, "%d", &bus); 61 | fclose(file); 62 | if (count != 1) 63 | continue; 64 | 65 | snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "devnum"); 66 | if (!(file = fopen(file_name, "r"))) 67 | continue; 68 | count = fscanf(file, "%d", &address); 69 | fclose(file); 70 | if (count != 1) 71 | continue; 72 | 73 | snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "idVendor"); 74 | if (!(file = fopen(file_name, "r"))) 75 | continue; 76 | count = fscanf(file, "%4x", &vid); 77 | fclose(file); 78 | if (count != 1) 79 | continue; 80 | 81 | snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "idProduct"); 82 | if (!(file = fopen(file_name, "r"))) 83 | continue; 84 | count = fscanf(file, "%4x", &pid); 85 | fclose(file); 86 | if (count != 1) 87 | continue; 88 | 89 | port->usb_bus = bus; 90 | port->usb_address = address; 91 | port->usb_vid = vid; 92 | port->usb_pid = pid; 93 | 94 | snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "product"); 95 | if ((file = fopen(file_name, "r"))) { 96 | if ((ptr = fgets(description, sizeof(description), file))) { 97 | ptr = description + strlen(description) - 1; 98 | if (ptr >= description && *ptr == '\n') 99 | *ptr = 0; 100 | port->description = strdup(description); 101 | } 102 | fclose(file); 103 | } 104 | if (!file || !ptr) 105 | port->description = strdup(dev); 106 | 107 | snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "manufacturer"); 108 | if ((file = fopen(file_name, "r"))) { 109 | if ((ptr = fgets(manufacturer, sizeof(manufacturer), file))) { 110 | ptr = manufacturer + strlen(manufacturer) - 1; 111 | if (ptr >= manufacturer && *ptr == '\n') 112 | *ptr = 0; 113 | port->usb_manufacturer = strdup(manufacturer); 114 | } 115 | fclose(file); 116 | } 117 | 118 | snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "product"); 119 | if ((file = fopen(file_name, "r"))) { 120 | if ((ptr = fgets(product, sizeof(product), file))) { 121 | ptr = product + strlen(product) - 1; 122 | if (ptr >= product && *ptr == '\n') 123 | *ptr = 0; 124 | port->usb_product = strdup(product); 125 | } 126 | fclose(file); 127 | } 128 | 129 | snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "serial"); 130 | if ((file = fopen(file_name, "r"))) { 131 | if ((ptr = fgets(serial, sizeof(serial), file))) { 132 | ptr = serial + strlen(serial) - 1; 133 | if (ptr >= serial && *ptr == '\n') 134 | *ptr = 0; 135 | port->usb_serial = strdup(serial); 136 | } 137 | fclose(file); 138 | } 139 | 140 | break; 141 | } 142 | } else { 143 | port->description = strdup(dev); 144 | 145 | if (port->transport == SP_TRANSPORT_BLUETOOTH) { 146 | snprintf(file_name, sizeof(file_name), dir_name, dev, "", "address"); 147 | if ((file = fopen(file_name, "r"))) { 148 | if ((ptr = fgets(baddr, sizeof(baddr), file))) { 149 | ptr = baddr + strlen(baddr) - 1; 150 | if (ptr >= baddr && *ptr == '\n') 151 | *ptr = 0; 152 | port->bluetooth_address = strdup(baddr); 153 | } 154 | fclose(file); 155 | } 156 | } 157 | } 158 | 159 | RETURN_OK(); 160 | } 161 | 162 | SP_PRIV enum sp_return list_ports(struct sp_port ***list) 163 | { 164 | char name[PATH_MAX], target[PATH_MAX]; 165 | struct dirent entry, *result; 166 | #ifdef HAVE_SERIAL_STRUCT 167 | struct serial_struct serial_info; 168 | int ioctl_result; 169 | #endif 170 | char buf[sizeof(entry.d_name) + 16]; 171 | int len, fd; 172 | DIR *dir; 173 | int ret = SP_OK; 174 | 175 | DEBUG("Enumerating tty devices"); 176 | if (!(dir = opendir("/sys/class/tty"))) 177 | RETURN_FAIL("could not open /sys/class/tty"); 178 | 179 | DEBUG("Iterating over results"); 180 | while (!readdir_r(dir, &entry, &result) && result) { 181 | snprintf(buf, sizeof(buf), "/sys/class/tty/%s", entry.d_name); 182 | len = readlink(buf, target, sizeof(target)); 183 | if (len <= 0 || len >= (int) sizeof(target)-1) 184 | continue; 185 | target[len] = 0; 186 | if (strstr(target, "virtual")) 187 | continue; 188 | snprintf(name, sizeof(name), "/dev/%s", entry.d_name); 189 | DEBUG_FMT("Found device %s", name); 190 | if (strstr(target, "serial8250")) { 191 | /* The serial8250 driver has a hardcoded number of ports. 192 | * The only way to tell which actually exist on a given system 193 | * is to try to open them and make an ioctl call. */ 194 | DEBUG("serial8250 device, attempting to open"); 195 | if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) { 196 | DEBUG("open failed, skipping"); 197 | continue; 198 | } 199 | #ifdef HAVE_SERIAL_STRUCT 200 | ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info); 201 | #endif 202 | close(fd); 203 | #ifdef HAVE_SERIAL_STRUCT 204 | if (ioctl_result != 0) { 205 | DEBUG("ioctl failed, skipping"); 206 | continue; 207 | } 208 | if (serial_info.type == PORT_UNKNOWN) { 209 | DEBUG("port type is unknown, skipping"); 210 | continue; 211 | } 212 | #endif 213 | } 214 | DEBUG_FMT("Found port %s", name); 215 | *list = list_append(*list, name); 216 | if (!list) { 217 | SET_ERROR(ret, SP_ERR_MEM, "list append failed"); 218 | break; 219 | } 220 | } 221 | closedir(dir); 222 | 223 | return ret; 224 | } 225 | 226 | #endif 227 | -------------------------------------------------------------------------------- /linux_termios.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libserialport project. 3 | * 4 | * Copyright (C) 2013 Martin Ling 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /* 21 | * At the time of writing, glibc does not support the Linux kernel interfaces 22 | * for setting non-standard baud rates and flow control. We therefore have to 23 | * prepare the correct ioctls ourselves, for which we need the declarations in 24 | * linux/termios.h. 25 | * 26 | * We can't include linux/termios.h in serialport.c however, because its 27 | * contents conflict with the termios.h provided by glibc. So this file exists 28 | * to isolate the bits of code which use the kernel termios declarations. 29 | * 30 | * The details vary by architecture. Some architectures have c_ispeed/c_ospeed 31 | * in struct termios, accessed with TCSETS/TCGETS. Others have these fields in 32 | * struct termios2, accessed with TCSETS2/TCGETS2. Some architectures have the 33 | * TCSETX/TCGETX ioctls used with struct termiox, others do not. 34 | */ 35 | 36 | #ifdef __linux__ 37 | 38 | #include 39 | #include 40 | #include "linux_termios.h" 41 | 42 | SP_PRIV unsigned long get_termios_get_ioctl(void) 43 | { 44 | #ifdef HAVE_TERMIOS2 45 | return TCGETS2; 46 | #else 47 | return TCGETS; 48 | #endif 49 | } 50 | 51 | SP_PRIV unsigned long get_termios_set_ioctl(void) 52 | { 53 | #ifdef HAVE_TERMIOS2 54 | return TCSETS2; 55 | #else 56 | return TCSETS; 57 | #endif 58 | } 59 | 60 | SP_PRIV size_t get_termios_size(void) 61 | { 62 | #ifdef HAVE_TERMIOS2 63 | return sizeof(struct termios2); 64 | #else 65 | return sizeof(struct termios); 66 | #endif 67 | } 68 | 69 | #if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && defined(HAVE_BOTHER) 70 | SP_PRIV int get_termios_speed(void *data) 71 | { 72 | #ifdef HAVE_TERMIOS2 73 | struct termios2 *term = (struct termios2 *) data; 74 | #else 75 | struct termios *term = (struct termios *) data; 76 | #endif 77 | if (term->c_ispeed != term->c_ospeed) 78 | return -1; 79 | else 80 | return term->c_ispeed; 81 | } 82 | 83 | SP_PRIV void set_termios_speed(void *data, int speed) 84 | { 85 | #ifdef HAVE_TERMIOS2 86 | struct termios2 *term = (struct termios2 *) data; 87 | #else 88 | struct termios *term = (struct termios *) data; 89 | #endif 90 | term->c_cflag &= ~CBAUD; 91 | term->c_cflag |= BOTHER; 92 | term->c_ispeed = term->c_ospeed = speed; 93 | } 94 | #endif 95 | 96 | #ifdef HAVE_TERMIOX 97 | SP_PRIV size_t get_termiox_size(void) 98 | { 99 | return sizeof(struct termiox); 100 | } 101 | 102 | SP_PRIV int get_termiox_flow(void *data, int *rts, int *cts, int *dtr, int *dsr) 103 | { 104 | struct termiox *termx = (struct termiox *) data; 105 | int flags = 0; 106 | 107 | *rts = (termx->x_cflag & RTSXOFF); 108 | *cts = (termx->x_cflag & CTSXON); 109 | *dtr = (termx->x_cflag & DTRXOFF); 110 | *dsr = (termx->x_cflag & DSRXON); 111 | 112 | return flags; 113 | } 114 | 115 | SP_PRIV void set_termiox_flow(void *data, int rts, int cts, int dtr, int dsr) 116 | { 117 | struct termiox *termx = (struct termiox *) data; 118 | 119 | termx->x_cflag &= ~(RTSXOFF | CTSXON | DTRXOFF | DSRXON); 120 | 121 | if (rts) 122 | termx->x_cflag |= RTSXOFF; 123 | if (cts) 124 | termx->x_cflag |= CTSXON; 125 | if (dtr) 126 | termx->x_cflag |= DTRXOFF; 127 | if (dsr) 128 | termx->x_cflag |= DSRXON; 129 | } 130 | #endif 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /linux_termios.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libserialport project. 3 | * 4 | * Copyright (C) 2013 Martin Ling 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifdef __linux__ 21 | 22 | #ifndef LIBSERIALPORT_LINUX_TERMIOS_H 23 | #define LIBSERIALPORT_LINUX_TERMIOS_H 24 | 25 | #include 26 | 27 | SP_PRIV unsigned long get_termios_get_ioctl(void); 28 | SP_PRIV unsigned long get_termios_set_ioctl(void); 29 | SP_PRIV size_t get_termios_size(void); 30 | SP_PRIV int get_termios_speed(void *data); 31 | SP_PRIV void set_termios_speed(void *data, int speed); 32 | SP_PRIV size_t get_termiox_size(void); 33 | SP_PRIV int get_termiox_flow(void *data, int *rts, int *cts, int *dtr, int *dsr); 34 | SP_PRIV void set_termiox_flow(void *data, int rts, int cts, int dtr, int dsr); 35 | 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /listports/listports.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | ".." 5 | "log" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | ports, err := serial.ListPorts() 11 | if err != nil { 12 | log.Panic(err) 13 | } 14 | 15 | log.Printf("Found %d ports:\n", len(ports)) 16 | 17 | for _, info := range ports { 18 | log.Println(info.Name()) 19 | log.Println("\tName:", info.Name()) 20 | log.Println("\tDescription:", info.Description()) 21 | log.Println("\tTransport:", info.Transport()) 22 | 23 | if bus, addr, err := info.USBBusAddress(); err != nil { 24 | log.Println("\tbus:", bus, "\taddr:", addr) 25 | } else { 26 | log.Println(err) 27 | } 28 | 29 | if vid, pid, err := info.USBVIDPID(); err != nil { 30 | log.Println("\tvid:", vid, "\tpid:", pid) 31 | } else { 32 | log.Println(err) 33 | } 34 | 35 | log.Println("\tUSB Manufacturer:", info.USBManufacturer()) 36 | log.Println("\tUSB Product:", info.USBProduct()) 37 | log.Println("\tUSB Serial Number:", info.USBSerialNumber()) 38 | log.Println("\tBluetooth Address:", info.BluetoothAddress()) 39 | 40 | port, err := info.Open() 41 | if err != nil { 42 | log.Println("\tOpen:", err) 43 | continue 44 | } 45 | 46 | log.Println("\tLocalAddr:", port.LocalAddr().String()) 47 | log.Println("\tRemoteAddr:", port.RemoteAddr().String()) 48 | 49 | if bitrate, err := port.BitRate(); err != nil { 50 | log.Println("\tBit Rate:", err) 51 | } else { 52 | log.Println("\tBit Rate:", bitrate) 53 | } 54 | 55 | if databits, err := port.DataBits(); err != nil { 56 | log.Println("\tData Bits:", err) 57 | } else { 58 | log.Println("\tData Bits:", databits) 59 | } 60 | 61 | if parity, err := port.Parity(); err != nil { 62 | log.Println("\tParity:", err) 63 | } else { 64 | log.Println("\tParity:", parity) 65 | } 66 | 67 | if stopbits, err := port.StopBits(); err != nil { 68 | log.Println("\tStop Bits:", err) 69 | } else { 70 | log.Println("\tStop Bits:", stopbits) 71 | } 72 | 73 | if rts, err := port.RTS(); err != nil { 74 | log.Println("\tRTS:", err) 75 | } else { 76 | log.Println("\tRTS:", rts) 77 | } 78 | 79 | if cts, err := port.CTS(); err != nil { 80 | log.Println("\tCTS:", err) 81 | } else { 82 | log.Println("\tCTS:", cts) 83 | } 84 | 85 | if dtr, err := port.DTR(); err != nil { 86 | log.Println("\tDTR:", err) 87 | } else { 88 | log.Println("\tDTR:", dtr) 89 | } 90 | 91 | if dsr, err := port.DSR(); err != nil { 92 | log.Println("\tDSR:", err) 93 | } else { 94 | log.Println("\tDSR:", dsr) 95 | } 96 | 97 | if xon, err := port.XonXoff(); err != nil { 98 | log.Println("\tXON/XOFF:", err) 99 | } else { 100 | log.Println("\tXON/XOFF:", xon) 101 | } 102 | 103 | /* 104 | if err := port.Apply(&serial.RawOptions); err != nil { 105 | log.Println("\tApply Raw Config:", err) 106 | } else { 107 | log.Println("\tApply Raw Config: ok") 108 | } 109 | */ 110 | 111 | if b, err := port.InputWaiting(); err != nil { 112 | log.Println("\tInput Waiting: ", err) 113 | } else { 114 | log.Println("\tInput Waiting: ", b) 115 | } 116 | 117 | if b, err := port.OutputWaiting(); err != nil { 118 | log.Println("\tOutput Waiting: ", err) 119 | } else { 120 | log.Println("\tOutput Waiting: ", b) 121 | } 122 | 123 | if err := port.Sync(); err != nil { 124 | log.Println("\tSync: ", err) 125 | } 126 | if err := port.Reset(); err != nil { 127 | log.Println("\tReset: ", err) 128 | } 129 | if err := port.ResetInput(); err != nil { 130 | log.Println("\tReset input: ", err) 131 | } 132 | if err := port.ResetOutput(); err != nil { 133 | log.Println("\tReset output: ", err) 134 | } 135 | 136 | buf := make([]byte, 1) 137 | 138 | if err := port.SetDeadline(time.Now()); err != nil { 139 | log.Println("\tSetDeadline: ", err) 140 | } else { 141 | log.Printf("\tSet deadline") 142 | } 143 | 144 | if c, err := port.Read(buf); err != nil { 145 | log.Printf("\tRead immediate %d: %v", c, err) 146 | if err != serial.ErrTimeout { 147 | continue 148 | } 149 | } else { 150 | log.Printf("\tRead immediate %d: %v", c, buf) 151 | } 152 | 153 | if c, err := port.Write([]byte{0}); err != nil { 154 | log.Println("\tWrite immediate:", err) 155 | if err != serial.ErrTimeout { 156 | continue 157 | } 158 | } else { 159 | log.Printf("\tWrite immediate %d: %v", c, buf) 160 | } 161 | 162 | if err := port.SetDeadline(time.Now().Add(time.Millisecond)); err != nil { 163 | log.Println("\tSetDeadline: ", err) 164 | } else { 165 | log.Printf("\tSet deadline") 166 | } 167 | 168 | if c, err := port.Read(buf); err != nil { 169 | log.Printf("\tRead wait %d: %v", c, err) 170 | } else { 171 | log.Printf("\tRead wait %d: %v", c, buf) 172 | } 173 | 174 | if err := port.SetDeadline(time.Now().Add(time.Millisecond)); err != nil { 175 | log.Println("\tSetDeadline: ", err) 176 | } else { 177 | log.Printf("\tSet deadline") 178 | } 179 | 180 | if c, err := port.Write([]byte{0}); err != nil { 181 | log.Println("\tWrite wait:", err) 182 | } else { 183 | log.Printf("\tWrite wait %d: %v", c, buf) 184 | } 185 | 186 | if err := port.SetReadDeadline(time.Time{}); err != nil { 187 | log.Println("\tSetReadDeadline: ", err) 188 | } else { 189 | log.Printf("\tSet read deadline") 190 | } 191 | if err := port.SetWriteDeadline(time.Time{}); err != nil { 192 | log.Println("\tSetWriteDeadline: ", err) 193 | } else { 194 | log.Printf("\tSet write deadline") 195 | } 196 | 197 | if c, err := port.Read(buf); err != nil { 198 | log.Printf("\tRead %d: %v", c, err) 199 | } else { 200 | log.Printf("\tRead %d: %v", c, buf) 201 | } 202 | 203 | if c, err := port.Write([]byte{0}); err != nil { 204 | log.Println("\tWrite:", err) 205 | } else { 206 | log.Printf("\tWrite %d: %v", c, buf) 207 | } 208 | 209 | if err := port.Close(); err != nil { 210 | log.Println(err) 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /macosx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libserialport project. 3 | * 4 | * Copyright (C) 2013-2014 Martin Ling 5 | * Copyright (C) 2014 Aurelien Jacobs 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation, either version 3 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #ifdef __APPLE__ 22 | 23 | #include "libserialport.h" 24 | #include "libserialport_internal.h" 25 | 26 | SP_PRIV enum sp_return get_port_details(struct sp_port *port) 27 | { 28 | /* Description limited to 127 char, 29 | anything longer would not be user friendly anyway */ 30 | char description[128]; 31 | int bus, address, vid, pid = -1; 32 | char manufacturer[128], product[128], serial[128]; 33 | CFMutableDictionaryRef classes; 34 | io_iterator_t iter; 35 | io_object_t ioport, ioparent; 36 | CFTypeRef cf_property, cf_bus, cf_address, cf_vendor, cf_product; 37 | Boolean result; 38 | char path[PATH_MAX], class[16]; 39 | 40 | DEBUG("Getting serial port list"); 41 | if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) 42 | RETURN_FAIL("IOServiceMatching() failed"); 43 | 44 | if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes, 45 | &iter) != KERN_SUCCESS) 46 | RETURN_FAIL("IOServiceGetMatchingServices() failed"); 47 | 48 | DEBUG("Iterating over results"); 49 | while ((ioport = IOIteratorNext(iter))) { 50 | if (!(cf_property = IORegistryEntryCreateCFProperty(ioport, 51 | CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0))) { 52 | IOObjectRelease(ioport); 53 | continue; 54 | } 55 | result = CFStringGetCString(cf_property, path, sizeof(path), 56 | kCFStringEncodingASCII); 57 | CFRelease(cf_property); 58 | if (!result || strcmp(path, port->name)) { 59 | IOObjectRelease(ioport); 60 | continue; 61 | } 62 | DEBUG_FMT("Found port %s", path); 63 | 64 | IORegistryEntryGetParentEntry(ioport, kIOServicePlane, &ioparent); 65 | if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane, 66 | CFSTR("IOProviderClass"), kCFAllocatorDefault, 67 | kIORegistryIterateRecursively | kIORegistryIterateParents))) { 68 | if (CFStringGetCString(cf_property, class, sizeof(class), 69 | kCFStringEncodingASCII) && 70 | strstr(class, "USB")) { 71 | DEBUG("Found USB class device"); 72 | port->transport = SP_TRANSPORT_USB; 73 | } 74 | CFRelease(cf_property); 75 | } 76 | IOObjectRelease(ioparent); 77 | 78 | if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, 79 | CFSTR("USB Interface Name"), kCFAllocatorDefault, 80 | kIORegistryIterateRecursively | kIORegistryIterateParents)) || 81 | (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, 82 | CFSTR("USB Product Name"), kCFAllocatorDefault, 83 | kIORegistryIterateRecursively | kIORegistryIterateParents)) || 84 | (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, 85 | CFSTR("Product Name"), kCFAllocatorDefault, 86 | kIORegistryIterateRecursively | kIORegistryIterateParents)) || 87 | (cf_property = IORegistryEntryCreateCFProperty(ioport, 88 | CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0))) { 89 | if (CFStringGetCString(cf_property, description, sizeof(description), 90 | kCFStringEncodingASCII)) { 91 | DEBUG_FMT("Found description %s", description); 92 | port->description = strdup(description); 93 | } 94 | CFRelease(cf_property); 95 | } else { 96 | DEBUG("No description for this device"); 97 | } 98 | 99 | cf_bus = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane, 100 | CFSTR("USBBusNumber"), 101 | kCFAllocatorDefault, 102 | kIORegistryIterateRecursively 103 | | kIORegistryIterateParents); 104 | cf_address = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane, 105 | CFSTR("USB Address"), 106 | kCFAllocatorDefault, 107 | kIORegistryIterateRecursively 108 | | kIORegistryIterateParents); 109 | if (cf_bus && cf_address && 110 | CFNumberGetValue(cf_bus , kCFNumberIntType, &bus) && 111 | CFNumberGetValue(cf_address, kCFNumberIntType, &address)) { 112 | DEBUG_FMT("Found matching USB bus:address %03d:%03d", bus, address); 113 | port->usb_bus = bus; 114 | port->usb_address = address; 115 | } 116 | if (cf_bus ) CFRelease(cf_bus); 117 | if (cf_address) CFRelease(cf_address); 118 | 119 | cf_vendor = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane, 120 | CFSTR("idVendor"), 121 | kCFAllocatorDefault, 122 | kIORegistryIterateRecursively 123 | | kIORegistryIterateParents); 124 | cf_product = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane, 125 | CFSTR("idProduct"), 126 | kCFAllocatorDefault, 127 | kIORegistryIterateRecursively 128 | | kIORegistryIterateParents); 129 | if (cf_vendor && cf_product && 130 | CFNumberGetValue(cf_vendor , kCFNumberIntType, &vid) && 131 | CFNumberGetValue(cf_product, kCFNumberIntType, &pid)) { 132 | DEBUG_FMT("Found matching USB vid:pid %04X:%04X", vid, pid); 133 | port->usb_vid = vid; 134 | port->usb_pid = pid; 135 | } 136 | if (cf_vendor ) CFRelease(cf_vendor); 137 | if (cf_product) CFRelease(cf_product); 138 | 139 | if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, 140 | CFSTR("USB Vendor Name"), kCFAllocatorDefault, 141 | kIORegistryIterateRecursively | kIORegistryIterateParents))) { 142 | if (CFStringGetCString(cf_property, manufacturer, sizeof(manufacturer), 143 | kCFStringEncodingASCII)) { 144 | DEBUG_FMT("Found manufacturer %s", manufacturer); 145 | port->usb_manufacturer = strdup(manufacturer); 146 | } 147 | CFRelease(cf_property); 148 | } 149 | 150 | if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, 151 | CFSTR("USB Product Name"), kCFAllocatorDefault, 152 | kIORegistryIterateRecursively | kIORegistryIterateParents))) { 153 | if (CFStringGetCString(cf_property, product, sizeof(product), 154 | kCFStringEncodingASCII)) { 155 | DEBUG_FMT("Found product name %s", product); 156 | port->usb_product = strdup(product); 157 | } 158 | CFRelease(cf_property); 159 | } 160 | 161 | if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, 162 | CFSTR("USB Serial Number"), kCFAllocatorDefault, 163 | kIORegistryIterateRecursively | kIORegistryIterateParents))) { 164 | if (CFStringGetCString(cf_property, serial, sizeof(serial), 165 | kCFStringEncodingASCII)) { 166 | DEBUG_FMT("Found serial number %s", serial); 167 | port->usb_serial = strdup(serial); 168 | } 169 | CFRelease(cf_property); 170 | } 171 | 172 | IOObjectRelease(ioport); 173 | break; 174 | } 175 | IOObjectRelease(iter); 176 | 177 | RETURN_OK(); 178 | } 179 | 180 | SP_PRIV enum sp_return list_ports(struct sp_port ***list) 181 | { 182 | CFMutableDictionaryRef classes; 183 | io_iterator_t iter; 184 | char path[PATH_MAX]; 185 | io_object_t port; 186 | CFTypeRef cf_path; 187 | Boolean result; 188 | int ret = SP_OK; 189 | 190 | DEBUG("Creating matching dictionary"); 191 | if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) { 192 | SET_FAIL(ret, "IOServiceMatching() failed"); 193 | goto out_done; 194 | } 195 | 196 | DEBUG("Getting matching services"); 197 | if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes, 198 | &iter) != KERN_SUCCESS) { 199 | SET_FAIL(ret, "IOServiceGetMatchingServices() failed"); 200 | goto out_done; 201 | } 202 | 203 | DEBUG("Iterating over results"); 204 | while ((port = IOIteratorNext(iter))) { 205 | cf_path = IORegistryEntryCreateCFProperty(port, 206 | CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0); 207 | if (cf_path) { 208 | result = CFStringGetCString(cf_path, path, sizeof(path), 209 | kCFStringEncodingASCII); 210 | CFRelease(cf_path); 211 | if (result) { 212 | DEBUG_FMT("Found port %s", path); 213 | if (!(*list = list_append(*list, path))) { 214 | SET_ERROR(ret, SP_ERR_MEM, "list append failed"); 215 | IOObjectRelease(port); 216 | goto out; 217 | } 218 | } 219 | } 220 | IOObjectRelease(port); 221 | } 222 | out: 223 | IOObjectRelease(iter); 224 | out_done: 225 | 226 | return ret; 227 | } 228 | 229 | #endif 230 | -------------------------------------------------------------------------------- /serial.go: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Package serial provides a binding to libserialport for serial port 4 | functionality. Serial ports are commonly used with embedded systems, 5 | such as the Arduino platform. 6 | 7 | Example Usage 8 | 9 | package main 10 | 11 | import ( 12 | "github.com/mikepb/go-serial" 13 | "log" 14 | ) 15 | 16 | func main() { 17 | options := serial.RawOptions 18 | options.BitRate = 115200 19 | p, err := options.Open("/dev/tty") 20 | if err != nil { 21 | log.Panic(err) 22 | } 23 | 24 | defer p.Close() 25 | 26 | buf := make([]byte, 1) 27 | if c, err := p.Read(buf); err != nil { 28 | log.Panic(err) 29 | } else { 30 | log.Println(buf) 31 | } 32 | } 33 | 34 | */ 35 | package serial 36 | 37 | /* 38 | #cgo CFLAGS: -g -O2 -Wall -Wextra -DSP_PRIV= -DSP_API= 39 | #cgo darwin LDFLAGS: -framework IOKit -framework CoreFoundation 40 | 41 | #include 42 | #include 43 | #include 44 | #include "libserialport.h" 45 | 46 | void debug_handler(const char *fmt, ...) { 47 | va_list args; 48 | va_start(args, fmt); 49 | vfprintf(stderr, fmt, args); 50 | va_end(args); 51 | } 52 | 53 | void setdebug(int enable) { 54 | sp_set_debug_handler(enable ? debug_handler : NULL); 55 | } 56 | 57 | */ 58 | import "C" 59 | 60 | import ( 61 | "bytes" 62 | "log" 63 | "net" 64 | "reflect" 65 | "runtime" 66 | "time" 67 | "unsafe" 68 | ) 69 | 70 | // Debug flag 71 | const Debug = false 72 | 73 | // Port access modes 74 | const ( 75 | MODE_READ = C.SP_MODE_READ // Open port for read access 76 | MODE_WRITE = C.SP_MODE_WRITE // Open port for write access 77 | MODE_READ_WRITE = C.SP_MODE_READ_WRITE // Open port for read and write access. 78 | ) 79 | 80 | // Port events. 81 | const ( 82 | EVENT_RX_READY = C.SP_EVENT_RX_READY // Data received and ready to read. 83 | EVENT_TX_READY = C.SP_EVENT_TX_READY // Ready to transmit new data. 84 | EVENT_ERROR = C.SP_EVENT_ERROR // Error occured. 85 | ) 86 | 87 | // Parity settings. 88 | const ( 89 | PARITY_INVALID = iota // Special value to indicate setting should be left alone. 90 | PARITY_NONE // No parity. 91 | PARITY_ODD // Odd parity. 92 | PARITY_EVEN // Even parity. 93 | PARITY_MARK // Mark parity. 94 | PARITY_SPACE // Space parity. 95 | ) 96 | 97 | // RTS pin behaviour. 98 | const ( 99 | RTS_INVALID = iota // Special value to indicate setting should be left alone. 100 | RTS_OFF // RTS off. 101 | RTS_ON // RTS on. 102 | RTS_FLOW_CONTROL // RTS used for flow control. 103 | ) 104 | 105 | // CTS pin behaviour. 106 | const ( 107 | CTS_INVALID = iota // Special value to indicate setting should be left alone. 108 | CTS_IGNORE // CTS ignored. 109 | CTS_FLOW_CONTROL // CTS used for flow control. 110 | ) 111 | 112 | // DTR pin behaviour. 113 | const ( 114 | DTR_INVALID = iota // Special value to indicate setting should be left alone. 115 | DTR_OFF // DTR off. 116 | DTR_ON // DTR on. 117 | DTR_FLOW_CONTROL // DTR used for flow control. 118 | ) 119 | 120 | // DSR pin behaviour. 121 | const ( 122 | DSR_INVALID = iota // Special value to indicate setting should be left alone. 123 | DSR_IGNORE // DSR ignored. 124 | DSR_FLOW_CONTROL // DSR used for flow control. 125 | ) 126 | 127 | // XON/XOFF flow control behaviour. 128 | const ( 129 | XONXOFF_INVALID = iota // Special value to indicate setting should be left alone. 130 | XONXOFF_DISABLED // XON/XOFF disabled. 131 | XONXOFF_IN // XON/XOFF enabled for input only. 132 | XONXOFF_OUT // XON/XOFF enabled for output only. 133 | XONXOFF_INOUT // XON/XOFF enabled for input and output. 134 | ) 135 | 136 | // Standard flow control combinations. 137 | const ( 138 | _ = iota 139 | FLOWCONTROL_NONE // No flow control. 140 | FLOWCONTROL_XONXOFF // Software flow control using XON/XOFF characters. 141 | FLOWCONTROL_RTSCTS // Hardware flow control using RTS/CTS signals. 142 | FLOWCONTROL_DTRDSR // Hardware flow control using DTR/DSR signals. 143 | ) 144 | 145 | // Input signals 146 | const ( 147 | SIG_CTS = C.SP_SIG_CTS // Clear to send 148 | SIG_DSR = C.SP_SIG_DSR // Data set ready 149 | SIG_DCD = C.SP_SIG_DCD // Data carrier detect 150 | SIG_RI = C.SP_SIG_RI // Ring indicator 151 | ) 152 | 153 | // Transport types. 154 | const ( 155 | TRANSPORT_NATIVE = C.SP_TRANSPORT_NATIVE // Native platform serial port. 156 | TRANSPORT_USB = C.SP_TRANSPORT_USB // USB serial port adapter. 157 | TRANSPORT_BLUETOOTH = C.SP_TRANSPORT_BLUETOOTH // Bluetooh serial port adapter. 158 | ) 159 | 160 | // Serial port info. 161 | type Info struct { 162 | p *C.struct_sp_port 163 | opened bool 164 | } 165 | 166 | // Serial port options. 167 | type Options struct { 168 | Mode int // read, write; default is read 169 | BitRate int // number of bits per second (baudrate) 170 | DataBits int // number of data bits (5, 6, 7, 8) 171 | StopBits int // number of stop bits (1, 2) 172 | Parity int // none, odd, even, mark, space 173 | FlowControl int // none, xonxoff, rtscts, dtrdsr 174 | 175 | RTS int 176 | CTS int 177 | DTR int 178 | DSR int 179 | } 180 | 181 | // Serial port. 182 | type Port struct { 183 | Info 184 | c *C.struct_sp_port_config 185 | readDeadline time.Time 186 | writeDeadline time.Time 187 | } 188 | 189 | // Implementation of net.Addr 190 | type Addr struct { 191 | name string 192 | } 193 | 194 | // Implementation of net.Error 195 | type Error struct { 196 | msg string 197 | timeout bool 198 | temporary bool 199 | } 200 | 201 | var RawOptions = Options{ 202 | DataBits: 8, 203 | Parity: PARITY_NONE, 204 | StopBits: 1, 205 | FlowControl: FLOWCONTROL_NONE, 206 | } 207 | 208 | var ErrInvalidArguments = &Error{msg: "Invalid arguments were passed to the function"} 209 | var ErrSystem = &Error{msg: "A system error occured while executing the operation"} 210 | var ErrMemoryAllocation = &Error{msg: "A memory allocation failed while executing the operation"} 211 | var ErrUnsupportedOperation = &Error{msg: "The requested operation is not supported by this system or device"} 212 | var ErrTimeout = &Error{msg: "Operation timed out", timeout: true} 213 | 214 | // Map error codes to errors. 215 | func errmsg(err C.enum_sp_return) error { 216 | switch err { 217 | case C.SP_ERR_ARG: 218 | return ErrInvalidArguments 219 | case C.SP_ERR_FAIL: 220 | return ErrSystem 221 | case C.SP_ERR_MEM: 222 | return ErrMemoryAllocation 223 | case C.SP_ERR_SUPP: 224 | return ErrUnsupportedOperation 225 | } 226 | return nil 227 | } 228 | 229 | // Wrap a sp_port struct in a go Port struct and set finalizer for 230 | // garbage collection. 231 | func newInfo(p *C.struct_sp_port) (*Info, error) { 232 | info := &Info{p: p} 233 | runtime.SetFinalizer(info, (*Info).free) 234 | return info, nil 235 | } 236 | 237 | // Finalizer callback for garbage collection. 238 | func (i *Info) free() { 239 | if i.p != nil { 240 | if i.opened { 241 | C.sp_close(i.p) 242 | } 243 | C.sp_free_port(i.p) 244 | } 245 | i.opened = false 246 | i.p = nil 247 | } 248 | 249 | // Wrap a sp_port struct in a go Port struct and set finalizer for 250 | // garbage collection. 251 | func newPort(info *Info) (*Port, error) { 252 | port := &Port{} 253 | 254 | // copy info 255 | if info != nil { 256 | if err := errmsg(C.sp_copy_port(info.p, &port.p)); err != nil { 257 | return nil, err 258 | } 259 | } 260 | 261 | // set finalizers 262 | runtime.SetFinalizer(port, (*Port).free) 263 | 264 | return port, nil 265 | } 266 | 267 | // Finalizer callback for garbage collection. 268 | func (p *Port) free() { 269 | p.Info.free() 270 | if p.c != nil { 271 | C.sp_free_config(p.c) 272 | } 273 | p.c = nil 274 | } 275 | 276 | // calculate milliseconds until deadline (rounded up) 277 | func deadline2millis(deadline time.Time) int64 { 278 | delta := deadline.Sub(time.Now()) 279 | 280 | duration := time.Duration(delta.Nanoseconds()) 281 | duration += duration + time.Millisecond - time.Nanosecond 282 | duration /= time.Millisecond 283 | 284 | millis := int64(duration) 285 | 286 | if Debug { 287 | log.Printf("timeout: %d ns %d ms", delta, millis) 288 | } 289 | 290 | return millis 291 | } 292 | 293 | // Print libserialport debug messages to stderr. 294 | func SetDebug(enable bool) { 295 | if enable { 296 | C.setdebug(1) 297 | } else { 298 | C.setdebug(0) 299 | } 300 | } 301 | 302 | // Get a port by name. 303 | func PortByName(name string) (*Info, error) { 304 | if p, err := portByName(name); err != nil { 305 | return nil, err 306 | } else { 307 | return newInfo(p) 308 | } 309 | } 310 | func portByName(name string) (*C.struct_sp_port, error) { 311 | var p *C.struct_sp_port 312 | 313 | cname := C.CString(name) 314 | defer C.free(unsafe.Pointer(cname)) 315 | 316 | if err := errmsg(C.sp_get_port_by_name(cname, &p)); err != nil { 317 | return nil, err 318 | } 319 | 320 | return p, nil 321 | } 322 | 323 | // List the serial ports available on the system. 324 | func ListPorts() ([]*Info, error) { 325 | var p **C.struct_sp_port 326 | 327 | if err := C.sp_list_ports(&p); err != C.SP_OK { 328 | return nil, errmsg(err) 329 | } 330 | defer C.sp_free_port_list(p) 331 | 332 | // Convert the C array into a Go slice 333 | // See: https://code.google.com/p/go-wiki/wiki/cgo 334 | pp := (*[1 << 15]*C.struct_sp_port)(unsafe.Pointer(p)) 335 | 336 | // count number of ports 337 | c := 0 338 | for ; uintptr(unsafe.Pointer(pp[c])) != 0; c++ { 339 | } 340 | 341 | // populate 342 | ports := make([]*Info, c) 343 | for j := 0; j < c; j++ { 344 | var pc *C.struct_sp_port 345 | if err := errmsg(C.sp_copy_port(pp[j], &pc)); err != nil { 346 | return nil, err 347 | } 348 | if sp, err := newInfo(pc); err != nil { 349 | return nil, err 350 | } else { 351 | ports[j] = sp 352 | } 353 | } 354 | 355 | return ports, nil 356 | } 357 | 358 | // Get the name of a port. 359 | func (i *Info) Name() string { 360 | return C.GoString(C.sp_get_port_name(i.p)) 361 | } 362 | 363 | // Get a description for a port, to present to end user. 364 | func (i *Info) Description() string { 365 | return C.GoString(C.sp_get_port_description(i.p)) 366 | } 367 | 368 | // Get the transport type used by a port. 369 | func (i *Info) Transport() int { 370 | t := C.sp_get_port_transport(i.p) 371 | return int(t) 372 | } 373 | 374 | // Get the USB bus number and address on bus of a USB serial adapter port. 375 | func (i *Info) USBBusAddress() (int, int, error) { 376 | var bus, address C.int 377 | if err := errmsg(C.sp_get_port_usb_bus_address(i.p, &bus, &address)); err != nil { 378 | return 0, 0, err 379 | } 380 | return int(bus), int(address), nil 381 | } 382 | 383 | // Get the USB Vendor ID and Product ID of a USB serial adapter port. 384 | func (i *Info) USBVIDPID() (int, int, error) { 385 | var vid, pid C.int 386 | if err := errmsg(C.sp_get_port_usb_vid_pid(i.p, &vid, &pid)); err != nil { 387 | return 0, 0, err 388 | } 389 | return int(vid), int(pid), nil 390 | } 391 | 392 | // Get the USB manufacturer string of a USB serial adapter port. 393 | func (i *Info) USBManufacturer() string { 394 | cdesc := C.sp_get_port_usb_manufacturer(i.p) 395 | return C.GoString(cdesc) 396 | } 397 | 398 | // Get the USB product string of a USB serial adapter port. 399 | func (i *Info) USBProduct() string { 400 | cdesc := C.sp_get_port_usb_product(i.p) 401 | return C.GoString(cdesc) 402 | } 403 | 404 | // Get the USB serial number string of a USB serial adapter port. 405 | func (i *Info) USBSerialNumber() string { 406 | cdesc := C.sp_get_port_usb_serial(i.p) 407 | return C.GoString(cdesc) 408 | } 409 | 410 | // Get the MAC address of a Bluetooth serial adapter port. 411 | func (i *Info) BluetoothAddress() string { 412 | cdesc := C.sp_get_port_bluetooth_address(i.p) 413 | return C.GoString(cdesc) 414 | } 415 | 416 | // Open the port for reading and default options. 417 | func (i *Info) Open() (*Port, error) { 418 | return i.OpenPort(&Options{Mode: MODE_READ}) 419 | } 420 | 421 | // Open the port with the specified options. 422 | func (i *Info) OpenPort(options *Options) (*Port, error) { 423 | // create port 424 | port, err := newPort(i) 425 | if err != nil { 426 | return nil, err 427 | } 428 | 429 | // open port 430 | mode := MODE_READ 431 | if options.Mode != 0 { 432 | mode = options.Mode 433 | } 434 | if err = port.open(mode); err != nil { 435 | return nil, err 436 | } 437 | 438 | // apply options 439 | if err = port.Apply(options); err != nil { 440 | port.Close() 441 | return nil, err 442 | } 443 | 444 | return port, nil 445 | } 446 | 447 | func (i *Info) createPortAndInvalidateInfo() (*Port, error) { 448 | port, err := newPort(nil) 449 | if err != nil { 450 | return nil, err 451 | } 452 | 453 | port.p = i.p 454 | port.opened = i.opened 455 | 456 | i.p = nil 457 | i.opened = false 458 | 459 | return port, nil 460 | } 461 | 462 | // Open a port at the given name using the options object. 463 | func (o *Options) Open(name string) (port *Port, err error) { 464 | if info, err := PortByName(name); err != nil { 465 | return nil, err 466 | } else { 467 | return info.OpenPort(o) 468 | } 469 | } 470 | 471 | // Open a port at the given info using the options object. 472 | func (o *Options) OpenAt(info *Info) (port *Port, err error) { 473 | return info.OpenPort(o) 474 | } 475 | 476 | // Open a port for reading. 477 | func Open(name string) (port *Port, err error) { 478 | // get the port by name 479 | if info, err := PortByName(name); err != nil { 480 | return nil, err 481 | } else if p, err := info.createPortAndInvalidateInfo(); p != nil { 482 | return nil, err 483 | } else { 484 | port = p 485 | } 486 | 487 | // open port with read mode 488 | if err = port.open(MODE_READ); err != nil { 489 | return nil, err 490 | } 491 | 492 | return 493 | } 494 | 495 | func (p *Port) open(mode int) error { 496 | if p.opened { 497 | panic("already opened") 498 | } 499 | err := errmsg(C.sp_open(p.p, C.enum_sp_mode(mode))) 500 | p.opened = err == nil 501 | return p.getConf() 502 | } 503 | 504 | // Close the serial port. 505 | func (p *Port) Close() error { 506 | if !p.opened { 507 | panic("already closed") 508 | } 509 | err := errmsg(C.sp_close(p.p)) 510 | p.opened = false 511 | return err 512 | } 513 | 514 | func (p *Port) getConf() error { 515 | if p.c == nil { 516 | if err := errmsg(C.sp_new_config(&p.c)); err != nil { 517 | return err 518 | } 519 | } 520 | return errmsg(C.sp_get_config(p.p, p.c)) 521 | } 522 | 523 | // Apply port options. 524 | func (p *Port) Apply(o *Options) (err error) { 525 | // get port config 526 | var conf *C.struct_sp_port_config 527 | if err = errmsg(C.sp_new_config(&conf)); err != nil { 528 | return 529 | } 530 | defer C.sp_free_config(conf) 531 | 532 | // set bit rate 533 | if o.BitRate != 0 { 534 | err = errmsg(C.sp_set_config_baudrate(conf, C.int(o.BitRate))) 535 | if err != nil { 536 | return 537 | } 538 | } 539 | 540 | // set data bits 541 | if o.DataBits != 0 { 542 | err = errmsg(C.sp_set_config_bits(conf, C.int(o.DataBits))) 543 | if err != nil { 544 | return 545 | } 546 | } 547 | 548 | // set stop bits 549 | if o.StopBits != 0 { 550 | err = errmsg(C.sp_set_config_stopbits(conf, C.int(o.StopBits))) 551 | if err != nil { 552 | return 553 | } 554 | } 555 | 556 | // set parity 557 | if o.Parity != 0 { 558 | cparity := parity2c(o.Parity) 559 | if err = errmsg(C.sp_set_config_parity(conf, cparity)); err != nil { 560 | return 561 | } 562 | } 563 | 564 | // set flow control 565 | if o.FlowControl != 0 { 566 | cfc, err := flow2c(o.FlowControl) 567 | if err != nil { 568 | return err 569 | } 570 | if err = errmsg(C.sp_set_config_flowcontrol(conf, cfc)); err != nil { 571 | return err 572 | } 573 | } 574 | 575 | // set RTS 576 | if o.RTS != 0 { 577 | crts := rts2c(o.RTS) 578 | if err = errmsg(C.sp_set_config_rts(conf, crts)); err != nil { 579 | return 580 | } 581 | } 582 | 583 | // set CTS 584 | if o.CTS != 0 { 585 | ccts := cts2c(o.CTS) 586 | if err = errmsg(C.sp_set_config_cts(conf, ccts)); err != nil { 587 | return 588 | } 589 | } 590 | 591 | // set DTR 592 | if o.DTR != 0 { 593 | cdtr := dtr2c(o.DTR) 594 | if err = errmsg(C.sp_set_config_dtr(conf, cdtr)); err != nil { 595 | return 596 | } 597 | } 598 | 599 | // set DSR 600 | if o.DSR != 0 { 601 | cdsr := dsr2c(o.DSR) 602 | if err = errmsg(C.sp_set_config_dsr(conf, cdsr)); err != nil { 603 | return 604 | } 605 | } 606 | 607 | // apply config 608 | if err = errmsg(C.sp_set_config(p.p, conf)); err != nil { 609 | return 610 | } 611 | 612 | // update local config 613 | return p.getConf() 614 | } 615 | 616 | // Get the baud rate from a port configuration. The port must be 617 | // opened for this operation. 618 | func (p *Port) BitRate() (int, error) { 619 | var bitrate C.int 620 | if err := errmsg(C.sp_get_config_baudrate(p.c, &bitrate)); err != nil { 621 | return 0, err 622 | } 623 | return int(bitrate), nil 624 | } 625 | 626 | // Set the baud rate for the serial port. The port must be opened for 627 | // this operation. Call p.ApplyConfig() to apply the change. 628 | func (p *Port) SetBitRate(bitrate int) error { 629 | if err := errmsg(C.sp_set_baudrate(p.p, C.int(bitrate))); err != nil { 630 | return err 631 | } 632 | return p.getConf() 633 | } 634 | 635 | // Get the data bits from a port configuration. The port must be 636 | // opened for this operation. 637 | func (p *Port) DataBits() (int, error) { 638 | var bits C.int 639 | if err := errmsg(C.sp_get_config_bits(p.c, &bits)); err != nil { 640 | return 0, err 641 | } 642 | return int(bits), nil 643 | } 644 | 645 | // Set the number of data bits for the serial port. The port must be 646 | // opened for this operation. Call p.ApplyConfig() to apply the 647 | // change. 648 | func (p *Port) SetDataBits(bits int) error { 649 | if err := errmsg(C.sp_set_config_bits(p.c, C.int(bits))); err != nil { 650 | return err 651 | } 652 | return p.getConf() 653 | } 654 | 655 | // Get the stop bits from a port configuration. The port must be 656 | // opened for this operation. 657 | func (p *Port) StopBits() (int, error) { 658 | var stopbits C.int 659 | if err := errmsg(C.sp_get_config_stopbits(p.c, &stopbits)); err != nil { 660 | return 0, err 661 | } 662 | return int(stopbits), nil 663 | } 664 | 665 | // Set the stop bits for the serial port. The port must be opened for 666 | // this operation. Call p.ApplyConfig() to apply the change. 667 | func (p *Port) SetStopBits(stopbits int) error { 668 | if err := errmsg(C.sp_set_config_stopbits(p.c, C.int(stopbits))); err != nil { 669 | return err 670 | } 671 | return p.getConf() 672 | } 673 | 674 | // Get the parity setting from a port configuration. The port must be 675 | // opened for this operation. 676 | func (p *Port) Parity() (int, error) { 677 | cparity := C.enum_sp_parity(C.SP_PARITY_INVALID) 678 | if err := errmsg(C.sp_get_config_parity(p.c, &cparity)); err != nil { 679 | return 0, err 680 | } 681 | return c2parity(cparity), nil 682 | } 683 | 684 | // Set the parity setting for the serial port. The port must be opened 685 | // for this operation. Call p.ApplyConfig() to apply the change. 686 | func (p *Port) SetParity(parity int) error { 687 | cparity := parity2c(parity) 688 | if err := errmsg(C.sp_set_config_parity(p.c, cparity)); err != nil { 689 | return err 690 | } 691 | return p.getConf() 692 | } 693 | 694 | func c2parity(cparity C.enum_sp_parity) int { 695 | switch cparity { 696 | case C.SP_PARITY_NONE: 697 | return PARITY_NONE 698 | case C.SP_PARITY_ODD: 699 | return PARITY_ODD 700 | case C.SP_PARITY_EVEN: 701 | return PARITY_EVEN 702 | case C.SP_PARITY_MARK: 703 | return PARITY_MARK 704 | case C.SP_PARITY_SPACE: 705 | return PARITY_SPACE 706 | default: 707 | return PARITY_INVALID 708 | } 709 | } 710 | 711 | func parity2c(parity int) C.enum_sp_parity { 712 | switch parity { 713 | case PARITY_NONE: 714 | return C.SP_PARITY_NONE 715 | case PARITY_ODD: 716 | return C.SP_PARITY_ODD 717 | case PARITY_EVEN: 718 | return C.SP_PARITY_EVEN 719 | case PARITY_MARK: 720 | return C.SP_PARITY_MARK 721 | case PARITY_SPACE: 722 | return C.SP_PARITY_SPACE 723 | default: 724 | return C.SP_PARITY_INVALID 725 | } 726 | } 727 | 728 | // Get the RTS pin behaviour from a port configuration. The port must 729 | // be opened for this operation. 730 | func (p *Port) RTS() (int, error) { 731 | rts := C.enum_sp_rts(C.SP_RTS_INVALID) 732 | if err := errmsg(C.sp_get_config_rts(p.c, &rts)); err != nil { 733 | return 0, err 734 | } 735 | return c2rts(rts), nil 736 | } 737 | 738 | // Set the RTS pin behaviour in a port configuration. The port must be 739 | // opened for this operation. Call p.ApplyConfig() to apply the 740 | // change. 741 | func (p *Port) SetRTS(rts int) error { 742 | crts := rts2c(rts) 743 | if err := errmsg(C.sp_set_config_rts(p.c, crts)); err != nil { 744 | return err 745 | } 746 | return p.getConf() 747 | } 748 | 749 | func c2rts(rts C.enum_sp_rts) int { 750 | switch rts { 751 | case C.SP_RTS_OFF: 752 | return RTS_OFF 753 | case C.SP_RTS_ON: 754 | return RTS_ON 755 | case C.SP_RTS_FLOW_CONTROL: 756 | return RTS_FLOW_CONTROL 757 | default: 758 | return RTS_INVALID 759 | } 760 | } 761 | 762 | func rts2c(rts int) C.enum_sp_rts { 763 | switch rts { 764 | case RTS_OFF: 765 | return C.SP_RTS_OFF 766 | case RTS_ON: 767 | return C.SP_RTS_ON 768 | case RTS_FLOW_CONTROL: 769 | return C.SP_RTS_FLOW_CONTROL 770 | default: 771 | return C.SP_RTS_INVALID 772 | } 773 | } 774 | 775 | // Get the CTS pin behaviour from a port configuration. The port must 776 | // be opened for this operation. 777 | func (p *Port) CTS() (int, error) { 778 | cts := C.enum_sp_cts(C.SP_CTS_INVALID) 779 | if err := errmsg(C.sp_get_config_cts(p.c, &cts)); err != nil { 780 | return 0, err 781 | } 782 | return c2cts(cts), nil 783 | } 784 | 785 | // Set the CTS pin behaviour in a port configuration. The port must be 786 | // opened for this operation. Call p.ApplyConfig() to apply the 787 | // change. 788 | func (p *Port) SetCTS(cts int) error { 789 | ccts := cts2c(cts) 790 | if err := errmsg(C.sp_set_config_cts(p.c, ccts)); err != nil { 791 | return err 792 | } 793 | return p.getConf() 794 | } 795 | 796 | func c2cts(cts C.enum_sp_cts) int { 797 | switch cts { 798 | case C.SP_CTS_IGNORE: 799 | return CTS_IGNORE 800 | case C.SP_CTS_FLOW_CONTROL: 801 | return CTS_FLOW_CONTROL 802 | default: 803 | return CTS_INVALID 804 | } 805 | } 806 | 807 | func cts2c(cts int) C.enum_sp_cts { 808 | switch cts { 809 | case CTS_IGNORE: 810 | return C.SP_CTS_IGNORE 811 | case CTS_FLOW_CONTROL: 812 | return C.SP_CTS_FLOW_CONTROL 813 | default: 814 | return C.SP_CTS_INVALID 815 | } 816 | } 817 | 818 | // Get the DTR pin behaviour from a port configuration. The port must 819 | // be opened for this operation. 820 | func (p *Port) DTR() (int, error) { 821 | dtr := C.enum_sp_dtr(C.SP_DTR_INVALID) 822 | if err := errmsg(C.sp_get_config_dtr(p.c, &dtr)); err != nil { 823 | return 0, err 824 | } 825 | return c2dtr(dtr), nil 826 | } 827 | 828 | // Set the DTR pin behaviour in a port configuration. The port must be 829 | // opened for this operation. Call p.ApplyConfig() to apply the 830 | // change. 831 | func (p *Port) SetDTR(dtr int) error { 832 | cdtr := dtr2c(dtr) 833 | if err := errmsg(C.sp_set_config_dtr(p.c, cdtr)); err != nil { 834 | return err 835 | } 836 | return p.getConf() 837 | } 838 | 839 | func c2dtr(dtr C.enum_sp_dtr) int { 840 | switch dtr { 841 | case C.SP_DTR_OFF: 842 | return DTR_OFF 843 | case C.SP_DTR_ON: 844 | return DTR_ON 845 | case C.SP_DTR_FLOW_CONTROL: 846 | return DTR_FLOW_CONTROL 847 | default: 848 | return DTR_INVALID 849 | } 850 | } 851 | 852 | func dtr2c(dtr int) C.enum_sp_dtr { 853 | switch dtr { 854 | case DTR_OFF: 855 | return C.SP_DTR_OFF 856 | case DTR_ON: 857 | return C.SP_DTR_ON 858 | case DTR_FLOW_CONTROL: 859 | return C.SP_DTR_FLOW_CONTROL 860 | default: 861 | return C.SP_DTR_INVALID 862 | } 863 | } 864 | 865 | // Get the DSR pin behaviour from a port configuration. The port must 866 | // be opened for this operation. 867 | func (p *Port) DSR() (int, error) { 868 | dsr := C.enum_sp_dsr(C.SP_DSR_INVALID) 869 | if err := errmsg(C.sp_get_config_dsr(p.c, &dsr)); err != nil { 870 | return 0, err 871 | } 872 | return c2dsr(dsr), nil 873 | } 874 | 875 | // Set the DSR pin behaviour in a port configuration. The port must be 876 | // opened for this operation. Call p.ApplyConfig() to apply the 877 | // change. 878 | func (p *Port) SetDSR(dsr int) error { 879 | cdsr := dsr2c(dsr) 880 | if err := errmsg(C.sp_set_config_dsr(p.c, cdsr)); err != nil { 881 | return err 882 | } 883 | return p.getConf() 884 | } 885 | 886 | func c2dsr(dsr C.enum_sp_dsr) int { 887 | switch dsr { 888 | case C.SP_DSR_IGNORE: 889 | return DSR_IGNORE 890 | case C.SP_DSR_FLOW_CONTROL: 891 | return DSR_FLOW_CONTROL 892 | default: 893 | return DSR_INVALID 894 | } 895 | } 896 | 897 | func dsr2c(dsr int) C.enum_sp_dsr { 898 | switch dsr { 899 | case DSR_IGNORE: 900 | return C.SP_DSR_IGNORE 901 | case DSR_FLOW_CONTROL: 902 | return C.SP_DSR_FLOW_CONTROL 903 | default: 904 | return C.SP_DSR_INVALID 905 | } 906 | } 907 | 908 | // Get the XON/XOFF configuration from a port configuration. The port 909 | // must be opened for this operation. 910 | func (p *Port) XonXoff() (int, error) { 911 | xon := C.enum_sp_xonxoff(C.SP_XONXOFF_INVALID) 912 | if err := errmsg(C.sp_get_config_xon_xoff(p.c, &xon)); err != nil { 913 | return 0, err 914 | } 915 | return c2xon(xon), nil 916 | } 917 | 918 | // Set the XON/XOFF configuration in a port configuration. The port 919 | // must be opened for this operation. Call p.ApplyConfig() to apply 920 | // the change. 921 | func (p *Port) SetXonXoff(xon int) error { 922 | cxon := xon2c(xon) 923 | if err := errmsg(C.sp_set_config_xon_xoff(p.c, cxon)); err != nil { 924 | return err 925 | } 926 | return p.getConf() 927 | } 928 | 929 | func c2xon(xon C.enum_sp_xonxoff) int { 930 | switch xon { 931 | case C.SP_XONXOFF_DISABLED: 932 | return XONXOFF_DISABLED 933 | case C.SP_XONXOFF_IN: 934 | return XONXOFF_IN 935 | case C.SP_XONXOFF_OUT: 936 | return XONXOFF_OUT 937 | default: 938 | return XONXOFF_INVALID 939 | } 940 | } 941 | 942 | func xon2c(xon int) C.enum_sp_xonxoff { 943 | switch xon { 944 | case XONXOFF_DISABLED: 945 | return C.SP_XONXOFF_DISABLED 946 | case XONXOFF_IN: 947 | return C.SP_XONXOFF_IN 948 | case XONXOFF_OUT: 949 | return C.SP_XONXOFF_OUT 950 | default: 951 | return C.SP_XONXOFF_INVALID 952 | } 953 | } 954 | 955 | // Set the flow control type in a port configuration. The port must be 956 | // opened for this operation. Call p.ApplyConfig() to apply the 957 | // change. 958 | func (p *Port) SetFlowControl(fc int) error { 959 | cfc, err := flow2c(fc) 960 | if err != nil { 961 | return err 962 | } 963 | 964 | if err := errmsg(C.sp_set_config_flowcontrol(p.c, cfc)); err != nil { 965 | return err 966 | } 967 | 968 | return p.getConf() 969 | } 970 | 971 | func flow2c(fc int) (cfc C.enum_sp_flowcontrol, err error) { 972 | switch fc { 973 | case FLOWCONTROL_NONE: 974 | cfc = C.SP_FLOWCONTROL_NONE 975 | case FLOWCONTROL_XONXOFF: 976 | cfc = C.SP_FLOWCONTROL_XONXOFF 977 | case FLOWCONTROL_RTSCTS: 978 | cfc = C.SP_FLOWCONTROL_RTSCTS 979 | case FLOWCONTROL_DTRDSR: 980 | cfc = C.SP_FLOWCONTROL_DTRDSR 981 | default: 982 | err = ErrInvalidArguments 983 | } 984 | return 985 | } 986 | 987 | // Implementation of io.Reader interface. 988 | func (p *Port) Read(b []byte) (int, error) { 989 | var c int32 990 | var start time.Time 991 | 992 | if Debug { 993 | start = time.Now() 994 | } 995 | 996 | buf, size := unsafe.Pointer(&b[0]), C.size_t(len(b)) 997 | 998 | if p.readDeadline.IsZero() { 999 | 1000 | // no deadline 1001 | c = C.sp_blocking_read(p.p, buf, size, 0) 1002 | 1003 | } else if millis := deadline2millis(p.readDeadline); millis <= 0 { 1004 | 1005 | // call nonblocking read 1006 | c = C.sp_nonblocking_read(p.p, buf, size) 1007 | 1008 | } else { 1009 | 1010 | // call blocking read 1011 | c = C.sp_blocking_read(p.p, buf, size, C.uint(millis)) 1012 | 1013 | } 1014 | 1015 | if Debug { 1016 | log.Printf("read time: %d ns", time.Since(start).Nanoseconds()) 1017 | } 1018 | 1019 | n := int(c) 1020 | 1021 | // check for error 1022 | if n < 0 { 1023 | return 0, errmsg(c) 1024 | } else if n != len(b) { 1025 | return n, ErrTimeout 1026 | } 1027 | 1028 | // update slice length 1029 | reflect.ValueOf(&b).Elem().SetLen(int(c)) 1030 | 1031 | return n, nil 1032 | } 1033 | 1034 | // Implementation of io.Writer interface. 1035 | func (p *Port) Write(b []byte) (int, error) { 1036 | var c int32 1037 | var start time.Time 1038 | 1039 | if Debug { 1040 | start = time.Now() 1041 | } 1042 | 1043 | buf, size := unsafe.Pointer(&b[0]), C.size_t(len(b)) 1044 | 1045 | if p.writeDeadline.IsZero() { 1046 | 1047 | // no deadline 1048 | c = C.sp_blocking_write(p.p, buf, size, 0) 1049 | 1050 | } else if millis := deadline2millis(p.writeDeadline); millis <= 0 { 1051 | 1052 | // call nonblocking write 1053 | c = C.sp_nonblocking_write(p.p, buf, size) 1054 | 1055 | } else { 1056 | 1057 | // call blocking write 1058 | c = C.sp_blocking_write(p.p, buf, size, C.uint(millis)) 1059 | 1060 | } 1061 | 1062 | if Debug { 1063 | log.Printf("write time: %d ns", time.Since(start).Nanoseconds()) 1064 | } 1065 | 1066 | n := int(c) 1067 | 1068 | // check for error 1069 | if n < 0 { 1070 | return 0, errmsg(c) 1071 | } else if n != len(b) { 1072 | return n, ErrTimeout 1073 | } 1074 | 1075 | return n, nil 1076 | } 1077 | 1078 | // WriteString is like Write, but writes the contents of string s 1079 | // rather than a slice of bytes. 1080 | func (p *Port) WriteString(s string) (int, error) { 1081 | return p.Write(bytes.NewBufferString(s).Bytes()) 1082 | } 1083 | 1084 | // Implementation of net.Conn.LocalAddr 1085 | func (p *Port) LocalAddr() net.Addr { 1086 | return &Addr{name: p.Name()} 1087 | } 1088 | 1089 | // Implementation of net.Conn.RemoteAddr 1090 | func (p *Port) RemoteAddr() net.Addr { 1091 | return &Addr{name: p.Name()} 1092 | } 1093 | 1094 | // Implementation of net.Conn.SetDeadline 1095 | func (p *Port) SetDeadline(t time.Time) error { 1096 | p.readDeadline = t 1097 | p.writeDeadline = t 1098 | return nil 1099 | } 1100 | 1101 | // Implementation of net.Conn.SetReadDeadline 1102 | func (p *Port) SetReadDeadline(t time.Time) error { 1103 | p.readDeadline = t 1104 | return nil 1105 | } 1106 | 1107 | // Implementation of net.Conn.SetWriteDeadline 1108 | func (p *Port) SetWriteDeadline(t time.Time) error { 1109 | p.writeDeadline = t 1110 | return nil 1111 | } 1112 | 1113 | // Gets the number of bytes waiting in the input buffer. 1114 | func (p *Port) InputWaiting() (int, error) { 1115 | c := C.sp_input_waiting(p.p) 1116 | if c < 0 { 1117 | return 0, errmsg(c) 1118 | } 1119 | return int(c), nil 1120 | } 1121 | 1122 | // Gets the number of bytes waiting in the output buffer. 1123 | func (p *Port) OutputWaiting() (int, error) { 1124 | c := C.sp_output_waiting(p.p) 1125 | if c < 0 { 1126 | return 0, errmsg(c) 1127 | } 1128 | return int(c), nil 1129 | } 1130 | 1131 | // Wait for buffered data to be transmitted. 1132 | func (p *Port) Sync() error { 1133 | return errmsg(C.sp_drain(p.p)) 1134 | } 1135 | 1136 | // Discard buffered data. 1137 | func (p *Port) Reset() error { 1138 | return errmsg(C.sp_flush(p.p, C.SP_BUF_BOTH)) 1139 | } 1140 | 1141 | // Discard buffered input data. 1142 | func (p *Port) ResetInput() error { 1143 | return errmsg(C.sp_flush(p.p, C.SP_BUF_INPUT)) 1144 | } 1145 | 1146 | // Discard buffered output data. 1147 | func (p *Port) ResetOutput() error { 1148 | return errmsg(C.sp_flush(p.p, C.SP_BUF_OUTPUT)) 1149 | } 1150 | 1151 | // Implementation of net.Addr.Network() 1152 | func (a *Addr) Network() string { 1153 | return "serial" 1154 | } 1155 | 1156 | // Implementation of net.Addr.String() 1157 | func (a *Addr) String() string { 1158 | return a.name 1159 | } 1160 | 1161 | // Implementation of error.Error() 1162 | func (e *Error) Error() string { 1163 | return e.msg 1164 | } 1165 | 1166 | // Implementation of net.Error.Timeout() 1167 | func (e *Error) Timeout() bool { 1168 | return e.timeout 1169 | } 1170 | 1171 | // Implementation of net.Error.Temporary() 1172 | func (e *Error) Temporary() bool { 1173 | return e.temporary 1174 | } 1175 | -------------------------------------------------------------------------------- /serialport.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libserialport project. 3 | * 4 | * Copyright (C) 2010-2012 Bert Vermeulen 5 | * Copyright (C) 2010-2012 Uwe Hermann 6 | * Copyright (C) 2013 Martin Ling 7 | * Copyright (C) 2013 Matthias Heidbrink 8 | * Copyright (C) 2014 Aurelien Jacobs 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU Lesser General Public License as 12 | * published by the Free Software Foundation, either version 3 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #include "libserialport.h" 25 | #include "libserialport_internal.h" 26 | 27 | const struct std_baudrate std_baudrates[] = { 28 | #ifdef _WIN32 29 | /* 30 | * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to 31 | * have documented CBR_* macros. 32 | */ 33 | BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800), 34 | BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600), 35 | BAUD(115200), BAUD(128000), BAUD(256000), 36 | #else 37 | BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200), 38 | BAUD(300), BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800), 39 | BAUD(9600), BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200), 40 | BAUD(230400), 41 | #if !defined(__APPLE__) && !defined(__OpenBSD__) 42 | BAUD(460800), 43 | #endif 44 | #endif 45 | }; 46 | 47 | void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler; 48 | 49 | static enum sp_return get_config(struct sp_port *port, struct port_data *data, 50 | struct sp_port_config *config); 51 | 52 | static enum sp_return set_config(struct sp_port *port, struct port_data *data, 53 | const struct sp_port_config *config); 54 | 55 | SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) 56 | { 57 | struct sp_port *port; 58 | #ifndef NO_PORT_METADATA 59 | enum sp_return ret; 60 | #endif 61 | int len; 62 | 63 | TRACE("%s, %p", portname, port_ptr); 64 | 65 | if (!port_ptr) 66 | RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); 67 | 68 | *port_ptr = NULL; 69 | 70 | if (!portname) 71 | RETURN_ERROR(SP_ERR_ARG, "Null port name"); 72 | 73 | DEBUG_FMT("Building structure for port %s", portname); 74 | 75 | if (!(port = malloc(sizeof(struct sp_port)))) 76 | RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed"); 77 | 78 | len = strlen(portname) + 1; 79 | 80 | if (!(port->name = malloc(len))) { 81 | free(port); 82 | RETURN_ERROR(SP_ERR_MEM, "Port name malloc failed"); 83 | } 84 | 85 | memcpy(port->name, portname, len); 86 | 87 | #ifdef _WIN32 88 | port->usb_path = NULL; 89 | port->hdl = INVALID_HANDLE_VALUE; 90 | #else 91 | port->fd = -1; 92 | #endif 93 | 94 | port->description = NULL; 95 | port->transport = SP_TRANSPORT_NATIVE; 96 | port->usb_bus = -1; 97 | port->usb_address = -1; 98 | port->usb_vid = -1; 99 | port->usb_pid = -1; 100 | port->usb_manufacturer = NULL; 101 | port->usb_product = NULL; 102 | port->usb_serial = NULL; 103 | port->bluetooth_address = NULL; 104 | 105 | #ifndef NO_PORT_METADATA 106 | if ((ret = get_port_details(port)) != SP_OK) { 107 | sp_free_port(port); 108 | return ret; 109 | } 110 | #endif 111 | 112 | *port_ptr = port; 113 | 114 | RETURN_OK(); 115 | } 116 | 117 | SP_API char *sp_get_port_name(const struct sp_port *port) 118 | { 119 | TRACE("%p", port); 120 | 121 | if (!port) 122 | return NULL; 123 | 124 | RETURN_STRING(port->name); 125 | } 126 | 127 | SP_API char *sp_get_port_description(struct sp_port *port) 128 | { 129 | TRACE("%p", port); 130 | 131 | if (!port || !port->description) 132 | return NULL; 133 | 134 | RETURN_STRING(port->description); 135 | } 136 | 137 | SP_API enum sp_transport sp_get_port_transport(struct sp_port *port) 138 | { 139 | TRACE("%p", port); 140 | 141 | if (!port) 142 | RETURN_ERROR(SP_ERR_ARG, "Null port"); 143 | 144 | RETURN_INT(port->transport); 145 | } 146 | 147 | SP_API enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port, 148 | int *usb_bus,int *usb_address) 149 | { 150 | TRACE("%p", port); 151 | 152 | if (!port) 153 | RETURN_ERROR(SP_ERR_ARG, "Null port"); 154 | if (port->transport != SP_TRANSPORT_USB) 155 | RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport"); 156 | if (port->usb_bus < 0 || port->usb_address < 0) 157 | RETURN_ERROR(SP_ERR_SUPP, "Bus and address values are not available"); 158 | 159 | if (usb_bus) *usb_bus = port->usb_bus; 160 | if (usb_address) *usb_address = port->usb_address; 161 | 162 | RETURN_OK(); 163 | } 164 | 165 | SP_API enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, 166 | int *usb_vid, int *usb_pid) 167 | { 168 | TRACE("%p", port); 169 | 170 | if (!port) 171 | RETURN_ERROR(SP_ERR_ARG, "Null port"); 172 | if (port->transport != SP_TRANSPORT_USB) 173 | RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport"); 174 | if (port->usb_vid < 0 || port->usb_pid < 0) 175 | RETURN_ERROR(SP_ERR_SUPP, "VID:PID values are not available"); 176 | 177 | if (usb_vid) *usb_vid = port->usb_vid; 178 | if (usb_pid) *usb_pid = port->usb_pid; 179 | 180 | RETURN_OK(); 181 | } 182 | 183 | SP_API char *sp_get_port_usb_manufacturer(const struct sp_port *port) 184 | { 185 | TRACE("%p", port); 186 | 187 | if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_manufacturer) 188 | return NULL; 189 | 190 | RETURN_STRING(port->usb_manufacturer); 191 | } 192 | 193 | SP_API char *sp_get_port_usb_product(const struct sp_port *port) 194 | { 195 | TRACE("%p", port); 196 | 197 | if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_product) 198 | return NULL; 199 | 200 | RETURN_STRING(port->usb_product); 201 | } 202 | 203 | SP_API char *sp_get_port_usb_serial(const struct sp_port *port) 204 | { 205 | TRACE("%p", port); 206 | 207 | if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_serial) 208 | return NULL; 209 | 210 | RETURN_STRING(port->usb_serial); 211 | } 212 | 213 | SP_API char *sp_get_port_bluetooth_address(const struct sp_port *port) 214 | { 215 | TRACE("%p", port); 216 | 217 | if (!port || port->transport != SP_TRANSPORT_BLUETOOTH 218 | || !port->bluetooth_address) 219 | return NULL; 220 | 221 | RETURN_STRING(port->bluetooth_address); 222 | } 223 | 224 | SP_API enum sp_return sp_get_port_handle(const struct sp_port *port, 225 | void *result_ptr) 226 | { 227 | TRACE("%p, %p", port, result_ptr); 228 | 229 | if (!port) 230 | RETURN_ERROR(SP_ERR_ARG, "Null port"); 231 | 232 | #ifdef _WIN32 233 | HANDLE *handle_ptr = result_ptr; 234 | *handle_ptr = port->hdl; 235 | #else 236 | int *fd_ptr = result_ptr; 237 | *fd_ptr = port->fd; 238 | #endif 239 | 240 | RETURN_OK(); 241 | } 242 | 243 | SP_API enum sp_return sp_copy_port(const struct sp_port *port, 244 | struct sp_port **copy_ptr) 245 | { 246 | TRACE("%p, %p", port, copy_ptr); 247 | 248 | if (!copy_ptr) 249 | RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); 250 | 251 | *copy_ptr = NULL; 252 | 253 | if (!port) 254 | RETURN_ERROR(SP_ERR_ARG, "Null port"); 255 | 256 | if (!port->name) 257 | RETURN_ERROR(SP_ERR_ARG, "Null port name"); 258 | 259 | DEBUG("Copying port structure"); 260 | 261 | RETURN_INT(sp_get_port_by_name(port->name, copy_ptr)); 262 | } 263 | 264 | SP_API void sp_free_port(struct sp_port *port) 265 | { 266 | TRACE("%p", port); 267 | 268 | if (!port) { 269 | DEBUG("Null port"); 270 | RETURN(); 271 | } 272 | 273 | DEBUG("Freeing port structure"); 274 | 275 | if (port->name) 276 | free(port->name); 277 | if (port->description) 278 | free(port->description); 279 | if (port->usb_manufacturer) 280 | free(port->usb_manufacturer); 281 | if (port->usb_product) 282 | free(port->usb_product); 283 | if (port->usb_serial) 284 | free(port->usb_serial); 285 | if (port->bluetooth_address) 286 | free(port->bluetooth_address); 287 | #ifdef _WIN32 288 | if (port->usb_path) 289 | free(port->usb_path); 290 | #endif 291 | 292 | free(port); 293 | 294 | RETURN(); 295 | } 296 | 297 | SP_PRIV struct sp_port **list_append(struct sp_port **list, 298 | const char *portname) 299 | { 300 | void *tmp; 301 | unsigned int count; 302 | 303 | for (count = 0; list[count]; count++); 304 | if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2)))) 305 | goto fail; 306 | list = tmp; 307 | if (sp_get_port_by_name(portname, &list[count]) != SP_OK) 308 | goto fail; 309 | list[count + 1] = NULL; 310 | return list; 311 | 312 | fail: 313 | sp_free_port_list(list); 314 | return NULL; 315 | } 316 | 317 | SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr) 318 | { 319 | struct sp_port **list; 320 | int ret; 321 | 322 | TRACE("%p", list_ptr); 323 | 324 | if (!list_ptr) 325 | RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); 326 | 327 | DEBUG("Enumerating ports"); 328 | 329 | if (!(list = malloc(sizeof(struct sp_port **)))) 330 | RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed"); 331 | 332 | list[0] = NULL; 333 | 334 | #ifdef NO_ENUMERATION 335 | ret = SP_ERR_SUPP; 336 | #else 337 | ret = list_ports(&list); 338 | #endif 339 | 340 | switch (ret) { 341 | case SP_OK: 342 | *list_ptr = list; 343 | RETURN_OK(); 344 | case SP_ERR_SUPP: 345 | DEBUG_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform"); 346 | default: 347 | if (list) 348 | sp_free_port_list(list); 349 | *list_ptr = NULL; 350 | return ret; 351 | } 352 | } 353 | 354 | SP_API void sp_free_port_list(struct sp_port **list) 355 | { 356 | unsigned int i; 357 | 358 | TRACE("%p", list); 359 | 360 | if (!list) { 361 | DEBUG("Null list"); 362 | RETURN(); 363 | } 364 | 365 | DEBUG("Freeing port list"); 366 | 367 | for (i = 0; list[i]; i++) 368 | sp_free_port(list[i]); 369 | free(list); 370 | 371 | RETURN(); 372 | } 373 | 374 | #define CHECK_PORT() do { \ 375 | if (port == NULL) \ 376 | RETURN_ERROR(SP_ERR_ARG, "Null port"); \ 377 | if (port->name == NULL) \ 378 | RETURN_ERROR(SP_ERR_ARG, "Null port name"); \ 379 | } while (0) 380 | #ifdef _WIN32 381 | #define CHECK_PORT_HANDLE() do { \ 382 | if (port->hdl == INVALID_HANDLE_VALUE) \ 383 | RETURN_ERROR(SP_ERR_ARG, "Invalid port handle"); \ 384 | } while (0) 385 | #else 386 | #define CHECK_PORT_HANDLE() do { \ 387 | if (port->fd < 0) \ 388 | RETURN_ERROR(SP_ERR_ARG, "Invalid port fd"); \ 389 | } while (0) 390 | #endif 391 | #define CHECK_OPEN_PORT() do { \ 392 | CHECK_PORT(); \ 393 | CHECK_PORT_HANDLE(); \ 394 | } while (0) 395 | 396 | SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) 397 | { 398 | struct port_data data; 399 | struct sp_port_config config; 400 | enum sp_return ret; 401 | 402 | TRACE("%p, 0x%x", port, flags); 403 | 404 | CHECK_PORT(); 405 | 406 | if (flags > SP_MODE_READ_WRITE) 407 | RETURN_ERROR(SP_ERR_ARG, "Invalid flags"); 408 | 409 | DEBUG_FMT("Opening port %s", port->name); 410 | 411 | #ifdef _WIN32 412 | DWORD desired_access = 0, flags_and_attributes = 0, errors; 413 | char *escaped_port_name; 414 | COMSTAT status; 415 | 416 | /* Prefix port name with '\\.\' to work with ports above COM9. */ 417 | if (!(escaped_port_name = malloc(strlen(port->name) + 5))) 418 | RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed"); 419 | sprintf(escaped_port_name, "\\\\.\\%s", port->name); 420 | 421 | /* Map 'flags' to the OS-specific settings. */ 422 | flags_and_attributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED; 423 | if (flags & SP_MODE_READ) 424 | desired_access |= GENERIC_READ; 425 | if (flags & SP_MODE_WRITE) 426 | desired_access |= GENERIC_WRITE; 427 | 428 | port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0, 429 | OPEN_EXISTING, flags_and_attributes, 0); 430 | 431 | free(escaped_port_name); 432 | 433 | if (port->hdl == INVALID_HANDLE_VALUE) 434 | RETURN_FAIL("port CreateFile() failed"); 435 | 436 | /* All timeouts initially disabled. */ 437 | port->timeouts.ReadIntervalTimeout = 0; 438 | port->timeouts.ReadTotalTimeoutMultiplier = 0; 439 | port->timeouts.ReadTotalTimeoutConstant = 0; 440 | port->timeouts.WriteTotalTimeoutMultiplier = 0; 441 | port->timeouts.WriteTotalTimeoutConstant = 0; 442 | 443 | if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) { 444 | sp_close(port); 445 | RETURN_FAIL("SetCommTimeouts() failed"); 446 | } 447 | 448 | /* Prepare OVERLAPPED structures. */ 449 | #define INIT_OVERLAPPED(ovl) do { \ 450 | memset(&port->ovl, 0, sizeof(port->ovl)); \ 451 | port->ovl.hEvent = INVALID_HANDLE_VALUE; \ 452 | if ((port->ovl.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL)) \ 453 | == INVALID_HANDLE_VALUE) { \ 454 | sp_close(port); \ 455 | RETURN_FAIL(#ovl "CreateEvent() failed"); \ 456 | } \ 457 | } while (0) 458 | 459 | INIT_OVERLAPPED(read_ovl); 460 | INIT_OVERLAPPED(write_ovl); 461 | INIT_OVERLAPPED(wait_ovl); 462 | 463 | /* Set event mask for RX and error events. */ 464 | if (SetCommMask(port->hdl, EV_RXCHAR | EV_ERR) == 0) { 465 | sp_close(port); 466 | RETURN_FAIL("SetCommMask() failed"); 467 | } 468 | 469 | /* Start background operation for RX and error events. */ 470 | if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) { 471 | if (GetLastError() != ERROR_IO_PENDING) { 472 | sp_close(port); 473 | RETURN_FAIL("WaitCommEvent() failed"); 474 | } 475 | } 476 | 477 | port->writing = FALSE; 478 | 479 | #else 480 | int flags_local = O_NONBLOCK | O_NOCTTY; 481 | 482 | /* Map 'flags' to the OS-specific settings. */ 483 | if ((flags & SP_MODE_READ_WRITE) == SP_MODE_READ_WRITE) 484 | flags_local |= O_RDWR; 485 | else if (flags & SP_MODE_READ) 486 | flags_local |= O_RDONLY; 487 | else if (flags & SP_MODE_WRITE) 488 | flags_local |= O_WRONLY; 489 | 490 | if ((port->fd = open(port->name, flags_local)) < 0) 491 | RETURN_FAIL("open() failed"); 492 | #endif 493 | 494 | ret = get_config(port, &data, &config); 495 | 496 | if (ret < 0) { 497 | sp_close(port); 498 | RETURN_CODEVAL(ret); 499 | } 500 | 501 | /* Set sane port settings. */ 502 | #ifdef _WIN32 503 | data.dcb.fBinary = TRUE; 504 | data.dcb.fDsrSensitivity = FALSE; 505 | data.dcb.fErrorChar = FALSE; 506 | data.dcb.fNull = FALSE; 507 | data.dcb.fAbortOnError = TRUE; 508 | #else 509 | /* Turn off all fancy termios tricks, give us a raw channel. */ 510 | data.term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IMAXBEL); 511 | #ifdef IUCLC 512 | data.term.c_iflag &= ~IUCLC; 513 | #endif 514 | data.term.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET); 515 | #ifdef OLCUC 516 | data.term.c_oflag &= ~OLCUC; 517 | #endif 518 | #ifdef NLDLY 519 | data.term.c_oflag &= ~NLDLY; 520 | #endif 521 | #ifdef CRDLY 522 | data.term.c_oflag &= ~CRDLY; 523 | #endif 524 | #ifdef TABDLY 525 | data.term.c_oflag &= ~TABDLY; 526 | #endif 527 | #ifdef BSDLY 528 | data.term.c_oflag &= ~BSDLY; 529 | #endif 530 | #ifdef VTDLY 531 | data.term.c_oflag &= ~VTDLY; 532 | #endif 533 | #ifdef FFDLY 534 | data.term.c_oflag &= ~FFDLY; 535 | #endif 536 | #ifdef OFILL 537 | data.term.c_oflag &= ~OFILL; 538 | #endif 539 | data.term.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN); 540 | data.term.c_cc[VMIN] = 0; 541 | data.term.c_cc[VTIME] = 0; 542 | 543 | /* Ignore modem status lines; enable receiver; leave control lines alone on close. */ 544 | data.term.c_cflag |= (CLOCAL | CREAD | HUPCL); 545 | #endif 546 | 547 | #ifdef _WIN32 548 | if (ClearCommError(port->hdl, &errors, &status) == 0) 549 | RETURN_FAIL("ClearCommError() failed"); 550 | #endif 551 | 552 | ret = set_config(port, &data, &config); 553 | 554 | if (ret < 0) { 555 | sp_close(port); 556 | RETURN_CODEVAL(ret); 557 | } 558 | 559 | RETURN_OK(); 560 | } 561 | 562 | SP_API enum sp_return sp_close(struct sp_port *port) 563 | { 564 | TRACE("%p", port); 565 | 566 | CHECK_OPEN_PORT(); 567 | 568 | DEBUG_FMT("Closing port %s", port->name); 569 | 570 | #ifdef _WIN32 571 | /* Returns non-zero upon success, 0 upon failure. */ 572 | if (CloseHandle(port->hdl) == 0) 573 | RETURN_FAIL("port CloseHandle() failed"); 574 | port->hdl = INVALID_HANDLE_VALUE; 575 | 576 | /* Close event handles for overlapped structures. */ 577 | #define CLOSE_OVERLAPPED(ovl) do { \ 578 | if (port->ovl.hEvent != INVALID_HANDLE_VALUE && \ 579 | CloseHandle(port->ovl.hEvent) == 0) \ 580 | RETURN_FAIL(# ovl "event CloseHandle() failed"); \ 581 | } while (0) 582 | CLOSE_OVERLAPPED(read_ovl); 583 | CLOSE_OVERLAPPED(write_ovl); 584 | CLOSE_OVERLAPPED(wait_ovl); 585 | 586 | #else 587 | /* Returns 0 upon success, -1 upon failure. */ 588 | if (close(port->fd) == -1) 589 | RETURN_FAIL("close() failed"); 590 | port->fd = -1; 591 | #endif 592 | 593 | RETURN_OK(); 594 | } 595 | 596 | SP_API enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers) 597 | { 598 | TRACE("%p, 0x%x", port, buffers); 599 | 600 | CHECK_OPEN_PORT(); 601 | 602 | if (buffers > SP_BUF_BOTH) 603 | RETURN_ERROR(SP_ERR_ARG, "Invalid buffer selection"); 604 | 605 | const char *buffer_names[] = {"no", "input", "output", "both"}; 606 | 607 | DEBUG_FMT("Flushing %s buffers on port %s", 608 | buffer_names[buffers], port->name); 609 | 610 | #ifdef _WIN32 611 | DWORD flags = 0; 612 | if (buffers & SP_BUF_INPUT) 613 | flags |= PURGE_RXCLEAR; 614 | if (buffers & SP_BUF_OUTPUT) 615 | flags |= PURGE_TXCLEAR; 616 | 617 | /* Returns non-zero upon success, 0 upon failure. */ 618 | if (PurgeComm(port->hdl, flags) == 0) 619 | RETURN_FAIL("PurgeComm() failed"); 620 | #else 621 | int flags = 0; 622 | if (buffers == SP_BUF_BOTH) 623 | flags = TCIOFLUSH; 624 | else if (buffers == SP_BUF_INPUT) 625 | flags = TCIFLUSH; 626 | else if (buffers == SP_BUF_OUTPUT) 627 | flags = TCOFLUSH; 628 | 629 | /* Returns 0 upon success, -1 upon failure. */ 630 | if (tcflush(port->fd, flags) < 0) 631 | RETURN_FAIL("tcflush() failed"); 632 | #endif 633 | RETURN_OK(); 634 | } 635 | 636 | SP_API enum sp_return sp_drain(struct sp_port *port) 637 | { 638 | TRACE("%p", port); 639 | 640 | CHECK_OPEN_PORT(); 641 | 642 | DEBUG_FMT("Draining port %s", port->name); 643 | 644 | #ifdef _WIN32 645 | /* Returns non-zero upon success, 0 upon failure. */ 646 | if (FlushFileBuffers(port->hdl) == 0) 647 | RETURN_FAIL("FlushFileBuffers() failed"); 648 | RETURN_OK(); 649 | #else 650 | int result; 651 | while (1) { 652 | #ifdef __ANDROID__ 653 | int arg = 1; 654 | result = ioctl(port->fd, TCSBRK, &arg); 655 | #else 656 | result = tcdrain(port->fd); 657 | #endif 658 | if (result < 0) { 659 | if (errno == EINTR) { 660 | DEBUG("tcdrain() was interrupted"); 661 | continue; 662 | } else { 663 | RETURN_FAIL("tcdrain() failed"); 664 | } 665 | } else { 666 | RETURN_OK(); 667 | } 668 | } 669 | #endif 670 | } 671 | 672 | SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, 673 | size_t count, unsigned int timeout) 674 | { 675 | TRACE("%p, %p, %d, %d", port, buf, count, timeout); 676 | 677 | CHECK_OPEN_PORT(); 678 | 679 | if (!buf) 680 | RETURN_ERROR(SP_ERR_ARG, "Null buffer"); 681 | 682 | if (timeout) 683 | DEBUG_FMT("Writing %d bytes to port %s, timeout %d ms", 684 | count, port->name, timeout); 685 | else 686 | DEBUG_FMT("Writing %d bytes to port %s, no timeout", 687 | count, port->name); 688 | 689 | if (count == 0) 690 | RETURN_INT(0); 691 | 692 | #ifdef _WIN32 693 | DWORD bytes_written = 0; 694 | BOOL result; 695 | 696 | /* Wait for previous non-blocking write to complete, if any. */ 697 | if (port->writing) { 698 | DEBUG("Waiting for previous write to complete"); 699 | result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE); 700 | port->writing = 0; 701 | if (!result) 702 | RETURN_FAIL("Previous write failed to complete"); 703 | DEBUG("Previous write completed"); 704 | } 705 | 706 | /* Set timeout. */ 707 | port->timeouts.WriteTotalTimeoutConstant = timeout; 708 | if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) 709 | RETURN_FAIL("SetCommTimeouts() failed"); 710 | 711 | /* Start write. */ 712 | if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl) == 0) { 713 | if (GetLastError() == ERROR_IO_PENDING) { 714 | DEBUG("Waiting for write to complete"); 715 | GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE); 716 | DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, count); 717 | RETURN_INT(bytes_written); 718 | } else { 719 | RETURN_FAIL("WriteFile() failed"); 720 | } 721 | } else { 722 | DEBUG("Write completed immediately"); 723 | RETURN_INT(count); 724 | } 725 | #else 726 | size_t bytes_written = 0; 727 | unsigned char *ptr = (unsigned char *) buf; 728 | struct timeval start, delta, now, end = {0, 0}; 729 | fd_set fds; 730 | int result; 731 | 732 | if (timeout) { 733 | /* Get time at start of operation. */ 734 | gettimeofday(&start, NULL); 735 | /* Define duration of timeout. */ 736 | delta.tv_sec = timeout / 1000; 737 | delta.tv_usec = (timeout % 1000) * 1000; 738 | /* Calculate time at which we should give up. */ 739 | timeradd(&start, &delta, &end); 740 | } 741 | 742 | /* Loop until we have written the requested number of bytes. */ 743 | while (bytes_written < count) 744 | { 745 | /* Wait until space is available. */ 746 | FD_ZERO(&fds); 747 | FD_SET(port->fd, &fds); 748 | if (timeout) { 749 | gettimeofday(&now, NULL); 750 | if (timercmp(&now, &end, >)) { 751 | DEBUG("write timed out"); 752 | RETURN_INT(bytes_written); 753 | } 754 | timersub(&end, &now, &delta); 755 | } 756 | result = select(port->fd + 1, NULL, &fds, NULL, timeout ? &delta : NULL); 757 | if (result < 0) { 758 | if (errno == EINTR) { 759 | DEBUG("select() call was interrupted, repeating"); 760 | continue; 761 | } else { 762 | RETURN_FAIL("select() failed"); 763 | } 764 | } else if (result == 0) { 765 | DEBUG("write timed out"); 766 | RETURN_INT(bytes_written); 767 | } 768 | 769 | /* Do write. */ 770 | result = write(port->fd, ptr, count - bytes_written); 771 | 772 | if (result < 0) { 773 | if (errno == EAGAIN) 774 | /* This shouldn't happen because we did a select() first, but handle anyway. */ 775 | continue; 776 | else 777 | /* This is an actual failure. */ 778 | RETURN_FAIL("write() failed"); 779 | } 780 | 781 | bytes_written += result; 782 | ptr += result; 783 | } 784 | 785 | RETURN_INT(bytes_written); 786 | #endif 787 | } 788 | 789 | SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, 790 | const void *buf, size_t count) 791 | { 792 | TRACE("%p, %p, %d", port, buf, count); 793 | 794 | CHECK_OPEN_PORT(); 795 | 796 | if (!buf) 797 | RETURN_ERROR(SP_ERR_ARG, "Null buffer"); 798 | 799 | DEBUG_FMT("Writing up to %d bytes to port %s", count, port->name); 800 | 801 | if (count == 0) 802 | RETURN_INT(0); 803 | 804 | #ifdef _WIN32 805 | DWORD written = 0; 806 | BYTE *ptr = (BYTE *) buf; 807 | 808 | /* Check whether previous write is complete. */ 809 | if (port->writing) { 810 | if (HasOverlappedIoCompleted(&port->write_ovl)) { 811 | DEBUG("Previous write completed"); 812 | port->writing = 0; 813 | } else { 814 | DEBUG("Previous write not complete"); 815 | /* Can't take a new write until the previous one finishes. */ 816 | RETURN_INT(0); 817 | } 818 | } 819 | 820 | /* Set timeout. */ 821 | port->timeouts.WriteTotalTimeoutConstant = 0; 822 | if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) 823 | RETURN_FAIL("SetCommTimeouts() failed"); 824 | 825 | /* Keep writing data until the OS has to actually start an async IO for it. 826 | * At that point we know the buffer is full. */ 827 | while (written < count) 828 | { 829 | /* Copy first byte of user buffer. */ 830 | port->pending_byte = *ptr++; 831 | 832 | /* Start asynchronous write. */ 833 | if (WriteFile(port->hdl, &port->pending_byte, 1, NULL, &port->write_ovl) == 0) { 834 | if (GetLastError() == ERROR_IO_PENDING) { 835 | if (HasOverlappedIoCompleted(&port->write_ovl)) { 836 | DEBUG("Asynchronous write completed immediately"); 837 | port->writing = 0; 838 | written++; 839 | continue; 840 | } else { 841 | DEBUG("Asynchronous write running"); 842 | port->writing = 1; 843 | RETURN_INT(++written); 844 | } 845 | } else { 846 | /* Actual failure of some kind. */ 847 | RETURN_FAIL("WriteFile() failed"); 848 | } 849 | } else { 850 | DEBUG("Single byte written immediately"); 851 | written++; 852 | } 853 | } 854 | 855 | DEBUG("All bytes written immediately"); 856 | 857 | RETURN_INT(written); 858 | #else 859 | /* Returns the number of bytes written, or -1 upon failure. */ 860 | ssize_t written = write(port->fd, buf, count); 861 | 862 | if (written < 0) 863 | RETURN_FAIL("write() failed"); 864 | else 865 | RETURN_INT(written); 866 | #endif 867 | } 868 | 869 | SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, 870 | size_t count, unsigned int timeout) 871 | { 872 | TRACE("%p, %p, %d, %d", port, buf, count, timeout); 873 | 874 | CHECK_OPEN_PORT(); 875 | 876 | if (!buf) 877 | RETURN_ERROR(SP_ERR_ARG, "Null buffer"); 878 | 879 | if (timeout) 880 | DEBUG_FMT("Reading %d bytes from port %s, timeout %d ms", 881 | count, port->name, timeout); 882 | else 883 | DEBUG_FMT("Reading %d bytes from port %s, no timeout", 884 | count, port->name); 885 | 886 | if (count == 0) 887 | RETURN_INT(0); 888 | 889 | #ifdef _WIN32 890 | DWORD bytes_read = 0; 891 | 892 | /* Set timeout. */ 893 | port->timeouts.ReadIntervalTimeout = 0; 894 | port->timeouts.ReadTotalTimeoutConstant = timeout; 895 | if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) 896 | RETURN_FAIL("SetCommTimeouts() failed"); 897 | 898 | /* Start read. */ 899 | if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0) { 900 | if (GetLastError() == ERROR_IO_PENDING) { 901 | DEBUG("Waiting for read to complete"); 902 | GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE); 903 | DEBUG_FMT("Read completed, %d/%d bytes read", bytes_read, count); 904 | } else { 905 | RETURN_FAIL("ReadFile() failed"); 906 | } 907 | } else { 908 | DEBUG("Read completed immediately"); 909 | bytes_read = count; 910 | } 911 | 912 | /* Start background operation for subsequent events. */ 913 | if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) { 914 | if (GetLastError() != ERROR_IO_PENDING) 915 | RETURN_FAIL("WaitCommEvent() failed"); 916 | } 917 | 918 | RETURN_INT(bytes_read); 919 | 920 | #else 921 | size_t bytes_read = 0; 922 | unsigned char *ptr = (unsigned char *) buf; 923 | struct timeval start, delta, now, end = {0, 0}; 924 | fd_set fds; 925 | int result; 926 | 927 | if (timeout) { 928 | /* Get time at start of operation. */ 929 | gettimeofday(&start, NULL); 930 | /* Define duration of timeout. */ 931 | delta.tv_sec = timeout / 1000; 932 | delta.tv_usec = (timeout % 1000) * 1000; 933 | /* Calculate time at which we should give up. */ 934 | timeradd(&start, &delta, &end); 935 | } 936 | 937 | /* Loop until we have the requested number of bytes. */ 938 | while (bytes_read < count) 939 | { 940 | /* Wait until data is available. */ 941 | FD_ZERO(&fds); 942 | FD_SET(port->fd, &fds); 943 | if (timeout) { 944 | gettimeofday(&now, NULL); 945 | if (timercmp(&now, &end, >)) 946 | /* Timeout has expired. */ 947 | RETURN_INT(bytes_read); 948 | timersub(&end, &now, &delta); 949 | } 950 | result = select(port->fd + 1, &fds, NULL, NULL, timeout ? &delta : NULL); 951 | if (result < 0) { 952 | if (errno == EINTR) { 953 | DEBUG("select() call was interrupted, repeating"); 954 | continue; 955 | } else { 956 | RETURN_FAIL("select() failed"); 957 | } 958 | } else if (result == 0) { 959 | DEBUG("read timed out"); 960 | RETURN_INT(bytes_read); 961 | } 962 | 963 | /* Do read. */ 964 | result = read(port->fd, ptr, count - bytes_read); 965 | 966 | if (result < 0) { 967 | if (errno == EAGAIN) 968 | /* This shouldn't happen because we did a select() first, but handle anyway. */ 969 | continue; 970 | else 971 | /* This is an actual failure. */ 972 | RETURN_FAIL("read() failed"); 973 | } else if (result == 0) { 974 | /* unexpected EOF */ 975 | RETURN_FAIL("Unexpected EOF"); 976 | } 977 | 978 | bytes_read += result; 979 | ptr += result; 980 | } 981 | 982 | RETURN_INT(bytes_read); 983 | #endif 984 | } 985 | 986 | SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, 987 | size_t count) 988 | { 989 | TRACE("%p, %p, %d", port, buf, count); 990 | 991 | CHECK_OPEN_PORT(); 992 | 993 | if (!buf) 994 | RETURN_ERROR(SP_ERR_ARG, "Null buffer"); 995 | 996 | DEBUG_FMT("Reading up to %d bytes from port %s", count, port->name); 997 | 998 | #ifdef _WIN32 999 | DWORD bytes_read; 1000 | 1001 | /* Set timeout. */ 1002 | port->timeouts.ReadIntervalTimeout = MAXDWORD; 1003 | port->timeouts.ReadTotalTimeoutConstant = 0; 1004 | if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) 1005 | RETURN_FAIL("SetCommTimeouts() failed"); 1006 | 1007 | /* Do read. */ 1008 | if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0) 1009 | RETURN_FAIL("ReadFile() failed"); 1010 | 1011 | /* Get number of bytes read. */ 1012 | if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0) 1013 | RETURN_FAIL("GetOverlappedResult() failed"); 1014 | 1015 | if (bytes_read > 0) { 1016 | /* Start background operation for subsequent events. */ 1017 | if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) { 1018 | if (GetLastError() != ERROR_IO_PENDING) 1019 | RETURN_FAIL("WaitCommEvent() failed"); 1020 | } 1021 | } 1022 | 1023 | RETURN_INT(bytes_read); 1024 | #else 1025 | ssize_t bytes_read; 1026 | 1027 | /* Returns the number of bytes read, or -1 upon failure. */ 1028 | if ((bytes_read = read(port->fd, buf, count)) < 0) { 1029 | if (errno == EAGAIN) 1030 | /* No bytes available. */ 1031 | bytes_read = 0; 1032 | else 1033 | /* This is an actual failure. */ 1034 | RETURN_FAIL("read() failed"); 1035 | } 1036 | RETURN_INT(bytes_read); 1037 | #endif 1038 | } 1039 | 1040 | SP_API enum sp_return sp_input_waiting(struct sp_port *port) 1041 | { 1042 | TRACE("%p", port); 1043 | 1044 | CHECK_OPEN_PORT(); 1045 | 1046 | DEBUG_FMT("Checking input bytes waiting on port %s", port->name); 1047 | 1048 | #ifdef _WIN32 1049 | DWORD errors; 1050 | COMSTAT comstat; 1051 | 1052 | if (ClearCommError(port->hdl, &errors, &comstat) == 0) 1053 | RETURN_FAIL("ClearCommError() failed"); 1054 | RETURN_INT(comstat.cbInQue); 1055 | #else 1056 | int bytes_waiting; 1057 | if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0) 1058 | RETURN_FAIL("TIOCINQ ioctl failed"); 1059 | RETURN_INT(bytes_waiting); 1060 | #endif 1061 | } 1062 | 1063 | SP_API enum sp_return sp_output_waiting(struct sp_port *port) 1064 | { 1065 | TRACE("%p", port); 1066 | 1067 | CHECK_OPEN_PORT(); 1068 | 1069 | DEBUG_FMT("Checking output bytes waiting on port %s", port->name); 1070 | 1071 | #ifdef _WIN32 1072 | DWORD errors; 1073 | COMSTAT comstat; 1074 | 1075 | if (ClearCommError(port->hdl, &errors, &comstat) == 0) 1076 | RETURN_FAIL("ClearCommError() failed"); 1077 | RETURN_INT(comstat.cbOutQue); 1078 | #else 1079 | int bytes_waiting; 1080 | if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0) 1081 | RETURN_FAIL("TIOCOUTQ ioctl failed"); 1082 | RETURN_INT(bytes_waiting); 1083 | #endif 1084 | } 1085 | 1086 | SP_API enum sp_return sp_new_event_set(struct sp_event_set **result_ptr) 1087 | { 1088 | struct sp_event_set *result; 1089 | 1090 | TRACE("%p", result_ptr); 1091 | 1092 | if (!result_ptr) 1093 | RETURN_ERROR(SP_ERR_ARG, "Null result"); 1094 | 1095 | *result_ptr = NULL; 1096 | 1097 | if (!(result = malloc(sizeof(struct sp_event_set)))) 1098 | RETURN_ERROR(SP_ERR_MEM, "sp_event_set malloc() failed"); 1099 | 1100 | memset(result, 0, sizeof(struct sp_event_set)); 1101 | 1102 | *result_ptr = result; 1103 | 1104 | RETURN_OK(); 1105 | } 1106 | 1107 | static enum sp_return add_handle(struct sp_event_set *event_set, 1108 | event_handle handle, enum sp_event mask) 1109 | { 1110 | void *new_handles; 1111 | enum sp_event *new_masks; 1112 | 1113 | TRACE("%p, %d, %d", event_set, handle, mask); 1114 | 1115 | if (!(new_handles = realloc(event_set->handles, 1116 | sizeof(event_handle) * (event_set->count + 1)))) 1117 | RETURN_ERROR(SP_ERR_MEM, "handle array realloc() failed"); 1118 | 1119 | if (!(new_masks = realloc(event_set->masks, 1120 | sizeof(enum sp_event) * (event_set->count + 1)))) 1121 | RETURN_ERROR(SP_ERR_MEM, "mask array realloc() failed"); 1122 | 1123 | event_set->handles = new_handles; 1124 | event_set->masks = new_masks; 1125 | 1126 | ((event_handle *) event_set->handles)[event_set->count] = handle; 1127 | event_set->masks[event_set->count] = mask; 1128 | 1129 | event_set->count++; 1130 | 1131 | RETURN_OK(); 1132 | } 1133 | 1134 | SP_API enum sp_return sp_add_port_events(struct sp_event_set *event_set, 1135 | const struct sp_port *port, enum sp_event mask) 1136 | { 1137 | TRACE("%p, %p, %d", event_set, port, mask); 1138 | 1139 | if (!event_set) 1140 | RETURN_ERROR(SP_ERR_ARG, "Null event set"); 1141 | 1142 | if (!port) 1143 | RETURN_ERROR(SP_ERR_ARG, "Null port"); 1144 | 1145 | if (mask > (SP_EVENT_RX_READY | SP_EVENT_TX_READY | SP_EVENT_ERROR)) 1146 | RETURN_ERROR(SP_ERR_ARG, "Invalid event mask"); 1147 | 1148 | if (!mask) 1149 | RETURN_OK(); 1150 | 1151 | #ifdef _WIN32 1152 | enum sp_event handle_mask; 1153 | if ((handle_mask = mask & SP_EVENT_TX_READY)) 1154 | TRY(add_handle(event_set, port->write_ovl.hEvent, handle_mask)); 1155 | if ((handle_mask = mask & (SP_EVENT_RX_READY | SP_EVENT_ERROR))) 1156 | TRY(add_handle(event_set, port->wait_ovl.hEvent, handle_mask)); 1157 | #else 1158 | TRY(add_handle(event_set, port->fd, mask)); 1159 | #endif 1160 | 1161 | RETURN_OK(); 1162 | } 1163 | 1164 | SP_API void sp_free_event_set(struct sp_event_set *event_set) 1165 | { 1166 | TRACE("%p", event_set); 1167 | 1168 | if (!event_set) { 1169 | DEBUG("Null event set"); 1170 | RETURN(); 1171 | } 1172 | 1173 | DEBUG("Freeing event set"); 1174 | 1175 | if (event_set->handles) 1176 | free(event_set->handles); 1177 | if (event_set->masks) 1178 | free(event_set->masks); 1179 | 1180 | free(event_set); 1181 | 1182 | RETURN(); 1183 | } 1184 | 1185 | SP_API enum sp_return sp_wait(struct sp_event_set *event_set, 1186 | unsigned int timeout) 1187 | { 1188 | TRACE("%p, %d", event_set, timeout); 1189 | 1190 | if (!event_set) 1191 | RETURN_ERROR(SP_ERR_ARG, "Null event set"); 1192 | 1193 | #ifdef _WIN32 1194 | if (WaitForMultipleObjects(event_set->count, event_set->handles, FALSE, 1195 | timeout ? timeout : INFINITE) == WAIT_FAILED) 1196 | RETURN_FAIL("WaitForMultipleObjects() failed"); 1197 | 1198 | RETURN_OK(); 1199 | #else 1200 | struct timeval start, delta, now, end = {0, 0}; 1201 | int result, timeout_remaining; 1202 | struct pollfd *pollfds; 1203 | unsigned int i; 1204 | 1205 | if (!(pollfds = malloc(sizeof(struct pollfd) * event_set->count))) 1206 | RETURN_ERROR(SP_ERR_MEM, "pollfds malloc() failed"); 1207 | 1208 | for (i = 0; i < event_set->count; i++) { 1209 | pollfds[i].fd = ((int *) event_set->handles)[i]; 1210 | pollfds[i].events = 0; 1211 | pollfds[i].revents = 0; 1212 | if (event_set->masks[i] & SP_EVENT_RX_READY) 1213 | pollfds[i].events |= POLLIN; 1214 | if (event_set->masks[i] & SP_EVENT_TX_READY) 1215 | pollfds[i].events |= POLLOUT; 1216 | if (event_set->masks[i] & SP_EVENT_ERROR) 1217 | pollfds[i].events |= POLLERR; 1218 | } 1219 | 1220 | if (timeout) { 1221 | /* Get time at start of operation. */ 1222 | gettimeofday(&start, NULL); 1223 | /* Define duration of timeout. */ 1224 | delta.tv_sec = timeout / 1000; 1225 | delta.tv_usec = (timeout % 1000) * 1000; 1226 | /* Calculate time at which we should give up. */ 1227 | timeradd(&start, &delta, &end); 1228 | } 1229 | 1230 | /* Loop until an event occurs. */ 1231 | while (1) 1232 | { 1233 | if (timeout) { 1234 | gettimeofday(&now, NULL); 1235 | if (timercmp(&now, &end, >)) { 1236 | DEBUG("wait timed out"); 1237 | break; 1238 | } 1239 | timersub(&end, &now, &delta); 1240 | timeout_remaining = delta.tv_sec * 1000 + delta.tv_usec / 1000; 1241 | } 1242 | 1243 | result = poll(pollfds, event_set->count, timeout ? timeout_remaining : -1); 1244 | 1245 | if (result < 0) { 1246 | if (errno == EINTR) { 1247 | DEBUG("poll() call was interrupted, repeating"); 1248 | continue; 1249 | } else { 1250 | free(pollfds); 1251 | RETURN_FAIL("poll() failed"); 1252 | } 1253 | } else if (result == 0) { 1254 | DEBUG("poll() timed out"); 1255 | break; 1256 | } else { 1257 | DEBUG("poll() completed"); 1258 | break; 1259 | } 1260 | } 1261 | 1262 | free(pollfds); 1263 | RETURN_OK(); 1264 | #endif 1265 | } 1266 | 1267 | #ifdef USE_TERMIOS_SPEED 1268 | static enum sp_return get_baudrate(int fd, int *baudrate) 1269 | { 1270 | void *data; 1271 | 1272 | TRACE("%d, %p", fd, baudrate); 1273 | 1274 | DEBUG("Getting baud rate"); 1275 | 1276 | if (!(data = malloc(get_termios_size()))) 1277 | RETURN_ERROR(SP_ERR_MEM, "termios malloc failed"); 1278 | 1279 | if (ioctl(fd, get_termios_get_ioctl(), data) < 0) { 1280 | free(data); 1281 | RETURN_FAIL("getting termios failed"); 1282 | } 1283 | 1284 | *baudrate = get_termios_speed(data); 1285 | 1286 | free(data); 1287 | 1288 | RETURN_OK(); 1289 | } 1290 | 1291 | static enum sp_return set_baudrate(int fd, int baudrate) 1292 | { 1293 | void *data; 1294 | 1295 | TRACE("%d, %d", fd, baudrate); 1296 | 1297 | DEBUG("Getting baud rate"); 1298 | 1299 | if (!(data = malloc(get_termios_size()))) 1300 | RETURN_ERROR(SP_ERR_MEM, "termios malloc failed"); 1301 | 1302 | if (ioctl(fd, get_termios_get_ioctl(), data) < 0) { 1303 | free(data); 1304 | RETURN_FAIL("getting termios failed"); 1305 | } 1306 | 1307 | DEBUG("Setting baud rate"); 1308 | 1309 | set_termios_speed(data, baudrate); 1310 | 1311 | if (ioctl(fd, get_termios_set_ioctl(), data) < 0) { 1312 | free(data); 1313 | RETURN_FAIL("setting termios failed"); 1314 | } 1315 | 1316 | free(data); 1317 | 1318 | RETURN_OK(); 1319 | } 1320 | #endif /* USE_TERMIOS_SPEED */ 1321 | 1322 | #ifdef USE_TERMIOX 1323 | static enum sp_return get_flow(int fd, struct port_data *data) 1324 | { 1325 | void *termx; 1326 | 1327 | TRACE("%d, %p", fd, data); 1328 | 1329 | DEBUG("Getting advanced flow control"); 1330 | 1331 | if (!(termx = malloc(get_termiox_size()))) 1332 | RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed"); 1333 | 1334 | if (ioctl(fd, TCGETX, termx) < 0) { 1335 | free(termx); 1336 | RETURN_FAIL("getting termiox failed"); 1337 | } 1338 | 1339 | get_termiox_flow(termx, &data->rts_flow, &data->cts_flow, 1340 | &data->dtr_flow, &data->dsr_flow); 1341 | 1342 | free(termx); 1343 | 1344 | RETURN_OK(); 1345 | } 1346 | 1347 | static enum sp_return set_flow(int fd, struct port_data *data) 1348 | { 1349 | void *termx; 1350 | 1351 | TRACE("%d, %p", fd, data); 1352 | 1353 | DEBUG("Getting advanced flow control"); 1354 | 1355 | if (!(termx = malloc(get_termiox_size()))) 1356 | RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed"); 1357 | 1358 | if (ioctl(fd, TCGETX, termx) < 0) { 1359 | free(termx); 1360 | RETURN_FAIL("getting termiox failed"); 1361 | } 1362 | 1363 | DEBUG("Setting advanced flow control"); 1364 | 1365 | set_termiox_flow(termx, data->rts_flow, data->cts_flow, 1366 | data->dtr_flow, data->dsr_flow); 1367 | 1368 | if (ioctl(fd, TCSETX, termx) < 0) { 1369 | free(termx); 1370 | RETURN_FAIL("setting termiox failed"); 1371 | } 1372 | 1373 | free(termx); 1374 | 1375 | RETURN_OK(); 1376 | } 1377 | #endif /* USE_TERMIOX */ 1378 | 1379 | static enum sp_return get_config(struct sp_port *port, struct port_data *data, 1380 | struct sp_port_config *config) 1381 | { 1382 | unsigned int i; 1383 | 1384 | TRACE("%p, %p, %p", port, data, config); 1385 | 1386 | DEBUG_FMT("Getting configuration for port %s", port->name); 1387 | 1388 | #ifdef _WIN32 1389 | if (!GetCommState(port->hdl, &data->dcb)) 1390 | RETURN_FAIL("GetCommState() failed"); 1391 | 1392 | for (i = 0; i < NUM_STD_BAUDRATES; i++) { 1393 | if (data->dcb.BaudRate == std_baudrates[i].index) { 1394 | config->baudrate = std_baudrates[i].value; 1395 | break; 1396 | } 1397 | } 1398 | 1399 | if (i == NUM_STD_BAUDRATES) 1400 | /* BaudRate field can be either an index or a custom baud rate. */ 1401 | config->baudrate = data->dcb.BaudRate; 1402 | 1403 | config->bits = data->dcb.ByteSize; 1404 | 1405 | if (data->dcb.fParity) 1406 | switch (data->dcb.Parity) { 1407 | case NOPARITY: 1408 | config->parity = SP_PARITY_NONE; 1409 | break; 1410 | case ODDPARITY: 1411 | config->parity = SP_PARITY_ODD; 1412 | break; 1413 | case EVENPARITY: 1414 | config->parity = SP_PARITY_EVEN; 1415 | break; 1416 | case MARKPARITY: 1417 | config->parity = SP_PARITY_MARK; 1418 | break; 1419 | case SPACEPARITY: 1420 | config->parity = SP_PARITY_SPACE; 1421 | break; 1422 | default: 1423 | config->parity = -1; 1424 | } 1425 | else 1426 | config->parity = SP_PARITY_NONE; 1427 | 1428 | switch (data->dcb.StopBits) { 1429 | case ONESTOPBIT: 1430 | config->stopbits = 1; 1431 | break; 1432 | case TWOSTOPBITS: 1433 | config->stopbits = 2; 1434 | break; 1435 | default: 1436 | config->stopbits = -1; 1437 | } 1438 | 1439 | switch (data->dcb.fRtsControl) { 1440 | case RTS_CONTROL_DISABLE: 1441 | config->rts = SP_RTS_OFF; 1442 | break; 1443 | case RTS_CONTROL_ENABLE: 1444 | config->rts = SP_RTS_ON; 1445 | break; 1446 | case RTS_CONTROL_HANDSHAKE: 1447 | config->rts = SP_RTS_FLOW_CONTROL; 1448 | break; 1449 | default: 1450 | config->rts = -1; 1451 | } 1452 | 1453 | config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE; 1454 | 1455 | switch (data->dcb.fDtrControl) { 1456 | case DTR_CONTROL_DISABLE: 1457 | config->dtr = SP_DTR_OFF; 1458 | break; 1459 | case DTR_CONTROL_ENABLE: 1460 | config->dtr = SP_DTR_ON; 1461 | break; 1462 | case DTR_CONTROL_HANDSHAKE: 1463 | config->dtr = SP_DTR_FLOW_CONTROL; 1464 | break; 1465 | default: 1466 | config->dtr = -1; 1467 | } 1468 | 1469 | config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE; 1470 | 1471 | if (data->dcb.fInX) { 1472 | if (data->dcb.fOutX) 1473 | config->xon_xoff = SP_XONXOFF_INOUT; 1474 | else 1475 | config->xon_xoff = SP_XONXOFF_IN; 1476 | } else { 1477 | if (data->dcb.fOutX) 1478 | config->xon_xoff = SP_XONXOFF_OUT; 1479 | else 1480 | config->xon_xoff = SP_XONXOFF_DISABLED; 1481 | } 1482 | 1483 | #else // !_WIN32 1484 | 1485 | if (tcgetattr(port->fd, &data->term) < 0) 1486 | RETURN_FAIL("tcgetattr() failed"); 1487 | 1488 | if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0) 1489 | RETURN_FAIL("TIOCMGET ioctl failed"); 1490 | 1491 | #ifdef USE_TERMIOX 1492 | int ret = get_flow(port->fd, data); 1493 | 1494 | if (ret == SP_ERR_FAIL && errno == EINVAL) 1495 | data->termiox_supported = 0; 1496 | else if (ret < 0) 1497 | RETURN_CODEVAL(ret); 1498 | else 1499 | data->termiox_supported = 1; 1500 | #else 1501 | data->termiox_supported = 0; 1502 | #endif 1503 | 1504 | for (i = 0; i < NUM_STD_BAUDRATES; i++) { 1505 | if (cfgetispeed(&data->term) == std_baudrates[i].index) { 1506 | config->baudrate = std_baudrates[i].value; 1507 | break; 1508 | } 1509 | } 1510 | 1511 | if (i == NUM_STD_BAUDRATES) { 1512 | #ifdef __APPLE__ 1513 | config->baudrate = (int)data->term.c_ispeed; 1514 | #elif defined(USE_TERMIOS_SPEED) 1515 | TRY(get_baudrate(port->fd, &config->baudrate)); 1516 | #else 1517 | config->baudrate = -1; 1518 | #endif 1519 | } 1520 | 1521 | switch (data->term.c_cflag & CSIZE) { 1522 | case CS8: 1523 | config->bits = 8; 1524 | break; 1525 | case CS7: 1526 | config->bits = 7; 1527 | break; 1528 | case CS6: 1529 | config->bits = 6; 1530 | break; 1531 | case CS5: 1532 | config->bits = 5; 1533 | break; 1534 | default: 1535 | config->bits = -1; 1536 | } 1537 | 1538 | if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR)) 1539 | config->parity = SP_PARITY_NONE; 1540 | else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR)) 1541 | config->parity = -1; 1542 | #ifdef CMSPAR 1543 | else if (data->term.c_cflag & CMSPAR) 1544 | config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_MARK : SP_PARITY_SPACE; 1545 | #endif 1546 | else 1547 | config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN; 1548 | 1549 | config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1; 1550 | 1551 | if (data->term.c_cflag & CRTSCTS) { 1552 | config->rts = SP_RTS_FLOW_CONTROL; 1553 | config->cts = SP_CTS_FLOW_CONTROL; 1554 | } else { 1555 | if (data->termiox_supported && data->rts_flow) 1556 | config->rts = SP_RTS_FLOW_CONTROL; 1557 | else 1558 | config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF; 1559 | 1560 | config->cts = (data->termiox_supported && data->cts_flow) ? 1561 | SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE; 1562 | } 1563 | 1564 | if (data->termiox_supported && data->dtr_flow) 1565 | config->dtr = SP_DTR_FLOW_CONTROL; 1566 | else 1567 | config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF; 1568 | 1569 | config->dsr = (data->termiox_supported && data->dsr_flow) ? 1570 | SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE; 1571 | 1572 | if (data->term.c_iflag & IXOFF) { 1573 | if (data->term.c_iflag & IXON) 1574 | config->xon_xoff = SP_XONXOFF_INOUT; 1575 | else 1576 | config->xon_xoff = SP_XONXOFF_IN; 1577 | } else { 1578 | if (data->term.c_iflag & IXON) 1579 | config->xon_xoff = SP_XONXOFF_OUT; 1580 | else 1581 | config->xon_xoff = SP_XONXOFF_DISABLED; 1582 | } 1583 | #endif 1584 | 1585 | RETURN_OK(); 1586 | } 1587 | 1588 | static enum sp_return set_config(struct sp_port *port, struct port_data *data, 1589 | const struct sp_port_config *config) 1590 | { 1591 | unsigned int i; 1592 | #ifdef __APPLE__ 1593 | BAUD_TYPE baud_nonstd; 1594 | 1595 | baud_nonstd = B0; 1596 | #endif 1597 | #ifdef USE_TERMIOS_SPEED 1598 | int baud_nonstd = 0; 1599 | #endif 1600 | 1601 | TRACE("%p, %p, %p", port, data, config); 1602 | 1603 | DEBUG_FMT("Setting configuration for port %s", port->name); 1604 | 1605 | #ifdef _WIN32 1606 | if (config->baudrate >= 0) { 1607 | for (i = 0; i < NUM_STD_BAUDRATES; i++) { 1608 | if (config->baudrate == std_baudrates[i].value) { 1609 | data->dcb.BaudRate = std_baudrates[i].index; 1610 | break; 1611 | } 1612 | } 1613 | 1614 | if (i == NUM_STD_BAUDRATES) 1615 | data->dcb.BaudRate = config->baudrate; 1616 | } 1617 | 1618 | if (config->bits >= 0) 1619 | data->dcb.ByteSize = config->bits; 1620 | 1621 | if (config->parity >= 0) { 1622 | switch (config->parity) { 1623 | case SP_PARITY_NONE: 1624 | data->dcb.Parity = NOPARITY; 1625 | break; 1626 | case SP_PARITY_ODD: 1627 | data->dcb.Parity = ODDPARITY; 1628 | break; 1629 | case SP_PARITY_EVEN: 1630 | data->dcb.Parity = EVENPARITY; 1631 | break; 1632 | case SP_PARITY_MARK: 1633 | data->dcb.Parity = MARKPARITY; 1634 | break; 1635 | case SP_PARITY_SPACE: 1636 | data->dcb.Parity = SPACEPARITY; 1637 | break; 1638 | default: 1639 | RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting"); 1640 | } 1641 | } 1642 | 1643 | if (config->stopbits >= 0) { 1644 | switch (config->stopbits) { 1645 | /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */ 1646 | case 1: 1647 | data->dcb.StopBits = ONESTOPBIT; 1648 | break; 1649 | case 2: 1650 | data->dcb.StopBits = TWOSTOPBITS; 1651 | break; 1652 | default: 1653 | RETURN_ERROR(SP_ERR_ARG, "Invalid stop bit setting"); 1654 | } 1655 | } 1656 | 1657 | if (config->rts >= 0) { 1658 | switch (config->rts) { 1659 | case SP_RTS_OFF: 1660 | data->dcb.fRtsControl = RTS_CONTROL_DISABLE; 1661 | break; 1662 | case SP_RTS_ON: 1663 | data->dcb.fRtsControl = RTS_CONTROL_ENABLE; 1664 | break; 1665 | case SP_RTS_FLOW_CONTROL: 1666 | data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; 1667 | break; 1668 | default: 1669 | RETURN_ERROR(SP_ERR_ARG, "Invalid RTS setting"); 1670 | } 1671 | } 1672 | 1673 | if (config->cts >= 0) { 1674 | switch (config->cts) { 1675 | case SP_CTS_IGNORE: 1676 | data->dcb.fOutxCtsFlow = FALSE; 1677 | break; 1678 | case SP_CTS_FLOW_CONTROL: 1679 | data->dcb.fOutxCtsFlow = TRUE; 1680 | break; 1681 | default: 1682 | RETURN_ERROR(SP_ERR_ARG, "Invalid CTS setting"); 1683 | } 1684 | } 1685 | 1686 | if (config->dtr >= 0) { 1687 | switch (config->dtr) { 1688 | case SP_DTR_OFF: 1689 | data->dcb.fDtrControl = DTR_CONTROL_DISABLE; 1690 | break; 1691 | case SP_DTR_ON: 1692 | data->dcb.fDtrControl = DTR_CONTROL_ENABLE; 1693 | break; 1694 | case SP_DTR_FLOW_CONTROL: 1695 | data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; 1696 | break; 1697 | default: 1698 | RETURN_ERROR(SP_ERR_ARG, "Invalid DTR setting"); 1699 | } 1700 | } 1701 | 1702 | if (config->dsr >= 0) { 1703 | switch (config->dsr) { 1704 | case SP_DSR_IGNORE: 1705 | data->dcb.fOutxDsrFlow = FALSE; 1706 | break; 1707 | case SP_DSR_FLOW_CONTROL: 1708 | data->dcb.fOutxDsrFlow = TRUE; 1709 | break; 1710 | default: 1711 | RETURN_ERROR(SP_ERR_ARG, "Invalid DSR setting"); 1712 | } 1713 | } 1714 | 1715 | if (config->xon_xoff >= 0) { 1716 | switch (config->xon_xoff) { 1717 | case SP_XONXOFF_DISABLED: 1718 | data->dcb.fInX = FALSE; 1719 | data->dcb.fOutX = FALSE; 1720 | break; 1721 | case SP_XONXOFF_IN: 1722 | data->dcb.fInX = TRUE; 1723 | data->dcb.fOutX = FALSE; 1724 | break; 1725 | case SP_XONXOFF_OUT: 1726 | data->dcb.fInX = FALSE; 1727 | data->dcb.fOutX = TRUE; 1728 | break; 1729 | case SP_XONXOFF_INOUT: 1730 | data->dcb.fInX = TRUE; 1731 | data->dcb.fOutX = TRUE; 1732 | break; 1733 | default: 1734 | RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting"); 1735 | } 1736 | } 1737 | 1738 | if (!SetCommState(port->hdl, &data->dcb)) 1739 | RETURN_FAIL("SetCommState() failed"); 1740 | 1741 | #else /* !_WIN32 */ 1742 | 1743 | int controlbits; 1744 | 1745 | if (config->baudrate >= 0) { 1746 | for (i = 0; i < NUM_STD_BAUDRATES; i++) { 1747 | if (config->baudrate == std_baudrates[i].value) { 1748 | if (cfsetospeed(&data->term, std_baudrates[i].index) < 0) 1749 | RETURN_FAIL("cfsetospeed() failed"); 1750 | 1751 | if (cfsetispeed(&data->term, std_baudrates[i].index) < 0) 1752 | RETURN_FAIL("cfsetispeed() failed"); 1753 | break; 1754 | } 1755 | } 1756 | 1757 | /* Non-standard baud rate */ 1758 | if (i == NUM_STD_BAUDRATES) { 1759 | #ifdef __APPLE__ 1760 | /* Set "dummy" baud rate. */ 1761 | if (cfsetspeed(&data->term, B9600) < 0) 1762 | RETURN_FAIL("cfsetspeed() failed"); 1763 | baud_nonstd = config->baudrate; 1764 | #elif defined(USE_TERMIOS_SPEED) 1765 | baud_nonstd = 1; 1766 | #else 1767 | RETURN_ERROR(SP_ERR_SUPP, "Non-standard baudrate not supported"); 1768 | #endif 1769 | } 1770 | } 1771 | 1772 | if (config->bits >= 0) { 1773 | data->term.c_cflag &= ~CSIZE; 1774 | switch (config->bits) { 1775 | case 8: 1776 | data->term.c_cflag |= CS8; 1777 | break; 1778 | case 7: 1779 | data->term.c_cflag |= CS7; 1780 | break; 1781 | case 6: 1782 | data->term.c_cflag |= CS6; 1783 | break; 1784 | case 5: 1785 | data->term.c_cflag |= CS5; 1786 | break; 1787 | default: 1788 | RETURN_ERROR(SP_ERR_ARG, "Invalid data bits setting"); 1789 | } 1790 | } 1791 | 1792 | if (config->parity >= 0) { 1793 | data->term.c_iflag &= ~IGNPAR; 1794 | data->term.c_cflag &= ~(PARENB | PARODD); 1795 | #ifdef CMSPAR 1796 | data->term.c_cflag &= ~CMSPAR; 1797 | #endif 1798 | switch (config->parity) { 1799 | case SP_PARITY_NONE: 1800 | data->term.c_iflag |= IGNPAR; 1801 | break; 1802 | case SP_PARITY_EVEN: 1803 | data->term.c_cflag |= PARENB; 1804 | break; 1805 | case SP_PARITY_ODD: 1806 | data->term.c_cflag |= PARENB | PARODD; 1807 | break; 1808 | #ifdef CMSPAR 1809 | case SP_PARITY_MARK: 1810 | data->term.c_cflag |= PARENB | PARODD; 1811 | data->term.c_cflag |= CMSPAR; 1812 | break; 1813 | case SP_PARITY_SPACE: 1814 | data->term.c_cflag |= PARENB; 1815 | data->term.c_cflag |= CMSPAR; 1816 | break; 1817 | #else 1818 | case SP_PARITY_MARK: 1819 | case SP_PARITY_SPACE: 1820 | RETURN_ERROR(SP_ERR_SUPP, "Mark/space parity not supported"); 1821 | #endif 1822 | default: 1823 | RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting"); 1824 | } 1825 | } 1826 | 1827 | if (config->stopbits >= 0) { 1828 | data->term.c_cflag &= ~CSTOPB; 1829 | switch (config->stopbits) { 1830 | case 1: 1831 | data->term.c_cflag &= ~CSTOPB; 1832 | break; 1833 | case 2: 1834 | data->term.c_cflag |= CSTOPB; 1835 | break; 1836 | default: 1837 | RETURN_ERROR(SP_ERR_ARG, "Invalid stop bits setting"); 1838 | } 1839 | } 1840 | 1841 | if (config->rts >= 0 || config->cts >= 0) { 1842 | if (data->termiox_supported) { 1843 | data->rts_flow = data->cts_flow = 0; 1844 | switch (config->rts) { 1845 | case SP_RTS_OFF: 1846 | case SP_RTS_ON: 1847 | controlbits = TIOCM_RTS; 1848 | if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0) 1849 | RETURN_FAIL("Setting RTS signal level failed"); 1850 | break; 1851 | case SP_RTS_FLOW_CONTROL: 1852 | data->rts_flow = 1; 1853 | break; 1854 | default: 1855 | break; 1856 | } 1857 | if (config->cts == SP_CTS_FLOW_CONTROL) 1858 | data->cts_flow = 1; 1859 | 1860 | if (data->rts_flow && data->cts_flow) 1861 | data->term.c_iflag |= CRTSCTS; 1862 | else 1863 | data->term.c_iflag &= ~CRTSCTS; 1864 | } else { 1865 | /* Asymmetric use of RTS/CTS not supported. */ 1866 | if (data->term.c_iflag & CRTSCTS) { 1867 | /* Flow control can only be disabled for both RTS & CTS together. */ 1868 | if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) { 1869 | if (config->cts != SP_CTS_IGNORE) 1870 | RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together"); 1871 | } 1872 | if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) { 1873 | if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL) 1874 | RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together"); 1875 | } 1876 | } else { 1877 | /* Flow control can only be enabled for both RTS & CTS together. */ 1878 | if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) || 1879 | ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL))) 1880 | RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be enabled together"); 1881 | } 1882 | 1883 | if (config->rts >= 0) { 1884 | if (config->rts == SP_RTS_FLOW_CONTROL) { 1885 | data->term.c_iflag |= CRTSCTS; 1886 | } else { 1887 | controlbits = TIOCM_RTS; 1888 | if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, 1889 | &controlbits) < 0) 1890 | RETURN_FAIL("Setting RTS signal level failed"); 1891 | } 1892 | } 1893 | } 1894 | } 1895 | 1896 | if (config->dtr >= 0 || config->dsr >= 0) { 1897 | if (data->termiox_supported) { 1898 | data->dtr_flow = data->dsr_flow = 0; 1899 | switch (config->dtr) { 1900 | case SP_DTR_OFF: 1901 | case SP_DTR_ON: 1902 | controlbits = TIOCM_DTR; 1903 | if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0) 1904 | RETURN_FAIL("Setting DTR signal level failed"); 1905 | break; 1906 | case SP_DTR_FLOW_CONTROL: 1907 | data->dtr_flow = 1; 1908 | break; 1909 | default: 1910 | break; 1911 | } 1912 | if (config->dsr == SP_DSR_FLOW_CONTROL) 1913 | data->dsr_flow = 1; 1914 | } else { 1915 | /* DTR/DSR flow control not supported. */ 1916 | if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL) 1917 | RETURN_ERROR(SP_ERR_SUPP, "DTR/DSR flow control not supported"); 1918 | 1919 | if (config->dtr >= 0) { 1920 | controlbits = TIOCM_DTR; 1921 | if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, 1922 | &controlbits) < 0) 1923 | RETURN_FAIL("Setting DTR signal level failed"); 1924 | } 1925 | } 1926 | } 1927 | 1928 | if (config->xon_xoff >= 0) { 1929 | data->term.c_iflag &= ~(IXON | IXOFF | IXANY); 1930 | switch (config->xon_xoff) { 1931 | case SP_XONXOFF_DISABLED: 1932 | break; 1933 | case SP_XONXOFF_IN: 1934 | data->term.c_iflag |= IXOFF; 1935 | break; 1936 | case SP_XONXOFF_OUT: 1937 | data->term.c_iflag |= IXON | IXANY; 1938 | break; 1939 | case SP_XONXOFF_INOUT: 1940 | data->term.c_iflag |= IXON | IXOFF | IXANY; 1941 | break; 1942 | default: 1943 | RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting"); 1944 | } 1945 | } 1946 | 1947 | if (tcsetattr(port->fd, TCSANOW, &data->term) < 0) 1948 | RETURN_FAIL("tcsetattr() failed"); 1949 | 1950 | #ifdef __APPLE__ 1951 | if (baud_nonstd != B0) { 1952 | if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1) 1953 | RETURN_FAIL("IOSSIOSPEED ioctl failed"); 1954 | /* Set baud rates in data->term to correct, but incompatible 1955 | * with tcsetattr() value, same as delivered by tcgetattr(). */ 1956 | if (cfsetspeed(&data->term, baud_nonstd) < 0) 1957 | RETURN_FAIL("cfsetspeed() failed"); 1958 | } 1959 | #elif defined(__linux__) 1960 | #ifdef USE_TERMIOS_SPEED 1961 | if (baud_nonstd) 1962 | TRY(set_baudrate(port->fd, config->baudrate)); 1963 | #endif 1964 | #ifdef USE_TERMIOX 1965 | if (data->termiox_supported) 1966 | TRY(set_flow(port->fd, data)); 1967 | #endif 1968 | #endif 1969 | 1970 | #endif /* !_WIN32 */ 1971 | 1972 | RETURN_OK(); 1973 | } 1974 | 1975 | SP_API enum sp_return sp_new_config(struct sp_port_config **config_ptr) 1976 | { 1977 | struct sp_port_config *config; 1978 | 1979 | TRACE("%p", config_ptr); 1980 | 1981 | if (!config_ptr) 1982 | RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); 1983 | 1984 | *config_ptr = NULL; 1985 | 1986 | if (!(config = malloc(sizeof(struct sp_port_config)))) 1987 | RETURN_ERROR(SP_ERR_MEM, "config malloc failed"); 1988 | 1989 | config->baudrate = -1; 1990 | config->bits = -1; 1991 | config->parity = -1; 1992 | config->stopbits = -1; 1993 | config->rts = -1; 1994 | config->cts = -1; 1995 | config->dtr = -1; 1996 | config->dsr = -1; 1997 | 1998 | *config_ptr = config; 1999 | 2000 | RETURN_OK(); 2001 | } 2002 | 2003 | SP_API void sp_free_config(struct sp_port_config *config) 2004 | { 2005 | TRACE("%p", config); 2006 | 2007 | if (!config) 2008 | DEBUG("Null config"); 2009 | else 2010 | free(config); 2011 | 2012 | RETURN(); 2013 | } 2014 | 2015 | SP_API enum sp_return sp_get_config(struct sp_port *port, 2016 | struct sp_port_config *config) 2017 | { 2018 | struct port_data data; 2019 | 2020 | TRACE("%p, %p", port, config); 2021 | 2022 | CHECK_OPEN_PORT(); 2023 | 2024 | if (!config) 2025 | RETURN_ERROR(SP_ERR_ARG, "Null config"); 2026 | 2027 | TRY(get_config(port, &data, config)); 2028 | 2029 | RETURN_OK(); 2030 | } 2031 | 2032 | SP_API enum sp_return sp_set_config(struct sp_port *port, 2033 | const struct sp_port_config *config) 2034 | { 2035 | struct port_data data; 2036 | struct sp_port_config prev_config; 2037 | 2038 | TRACE("%p, %p", port, config); 2039 | 2040 | CHECK_OPEN_PORT(); 2041 | 2042 | if (!config) 2043 | RETURN_ERROR(SP_ERR_ARG, "Null config"); 2044 | 2045 | TRY(get_config(port, &data, &prev_config)); 2046 | TRY(set_config(port, &data, config)); 2047 | 2048 | RETURN_OK(); 2049 | } 2050 | 2051 | #define CREATE_ACCESSORS(x, type) \ 2052 | SP_API enum sp_return sp_set_##x(struct sp_port *port, type x) { \ 2053 | struct port_data data; \ 2054 | struct sp_port_config config; \ 2055 | TRACE("%p, %d", port, x); \ 2056 | CHECK_OPEN_PORT(); \ 2057 | TRY(get_config(port, &data, &config)); \ 2058 | config.x = x; \ 2059 | TRY(set_config(port, &data, &config)); \ 2060 | RETURN_OK(); \ 2061 | } \ 2062 | SP_API enum sp_return sp_get_config_##x(const struct sp_port_config *config, \ 2063 | type *x) { \ 2064 | TRACE("%p, %p", config, x); \ 2065 | if (!config) \ 2066 | RETURN_ERROR(SP_ERR_ARG, "Null config"); \ 2067 | *x = config->x; \ 2068 | RETURN_OK(); \ 2069 | } \ 2070 | SP_API enum sp_return sp_set_config_##x(struct sp_port_config *config, \ 2071 | type x) { \ 2072 | TRACE("%p, %d", config, x); \ 2073 | if (!config) \ 2074 | RETURN_ERROR(SP_ERR_ARG, "Null config"); \ 2075 | config->x = x; \ 2076 | RETURN_OK(); \ 2077 | } 2078 | 2079 | CREATE_ACCESSORS(baudrate, int) 2080 | CREATE_ACCESSORS(bits, int) 2081 | CREATE_ACCESSORS(parity, enum sp_parity) 2082 | CREATE_ACCESSORS(stopbits, int) 2083 | CREATE_ACCESSORS(rts, enum sp_rts) 2084 | CREATE_ACCESSORS(cts, enum sp_cts) 2085 | CREATE_ACCESSORS(dtr, enum sp_dtr) 2086 | CREATE_ACCESSORS(dsr, enum sp_dsr) 2087 | CREATE_ACCESSORS(xon_xoff, enum sp_xonxoff) 2088 | 2089 | SP_API enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, 2090 | enum sp_flowcontrol flowcontrol) 2091 | { 2092 | if (!config) 2093 | RETURN_ERROR(SP_ERR_ARG, "Null configuration"); 2094 | 2095 | if (flowcontrol > SP_FLOWCONTROL_DTRDSR) 2096 | RETURN_ERROR(SP_ERR_ARG, "Invalid flow control setting"); 2097 | 2098 | if (flowcontrol == SP_FLOWCONTROL_XONXOFF) 2099 | config->xon_xoff = SP_XONXOFF_INOUT; 2100 | else 2101 | config->xon_xoff = SP_XONXOFF_DISABLED; 2102 | 2103 | if (flowcontrol == SP_FLOWCONTROL_RTSCTS) { 2104 | config->rts = SP_RTS_FLOW_CONTROL; 2105 | config->cts = SP_CTS_FLOW_CONTROL; 2106 | } else { 2107 | if (config->rts == SP_RTS_FLOW_CONTROL) 2108 | config->rts = SP_RTS_ON; 2109 | config->cts = SP_CTS_IGNORE; 2110 | } 2111 | 2112 | if (flowcontrol == SP_FLOWCONTROL_DTRDSR) { 2113 | config->dtr = SP_DTR_FLOW_CONTROL; 2114 | config->dsr = SP_DSR_FLOW_CONTROL; 2115 | } else { 2116 | if (config->dtr == SP_DTR_FLOW_CONTROL) 2117 | config->dtr = SP_DTR_ON; 2118 | config->dsr = SP_DSR_IGNORE; 2119 | } 2120 | 2121 | RETURN_OK(); 2122 | } 2123 | 2124 | SP_API enum sp_return sp_set_flowcontrol(struct sp_port *port, 2125 | enum sp_flowcontrol flowcontrol) 2126 | { 2127 | struct port_data data; 2128 | struct sp_port_config config; 2129 | 2130 | TRACE("%p, %d", port, flowcontrol); 2131 | 2132 | CHECK_OPEN_PORT(); 2133 | 2134 | TRY(get_config(port, &data, &config)); 2135 | 2136 | TRY(sp_set_config_flowcontrol(&config, flowcontrol)); 2137 | 2138 | TRY(set_config(port, &data, &config)); 2139 | 2140 | RETURN_OK(); 2141 | } 2142 | 2143 | SP_API enum sp_return sp_get_signals(struct sp_port *port, 2144 | enum sp_signal *signals) 2145 | { 2146 | TRACE("%p, %p", port, signals); 2147 | 2148 | CHECK_OPEN_PORT(); 2149 | 2150 | if (!signals) 2151 | RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); 2152 | 2153 | DEBUG_FMT("Getting control signals for port %s", port->name); 2154 | 2155 | *signals = 0; 2156 | #ifdef _WIN32 2157 | DWORD bits; 2158 | if (GetCommModemStatus(port->hdl, &bits) == 0) 2159 | RETURN_FAIL("GetCommModemStatus() failed"); 2160 | if (bits & MS_CTS_ON) 2161 | *signals |= SP_SIG_CTS; 2162 | if (bits & MS_DSR_ON) 2163 | *signals |= SP_SIG_DSR; 2164 | if (bits & MS_RLSD_ON) 2165 | *signals |= SP_SIG_DCD; 2166 | if (bits & MS_RING_ON) 2167 | *signals |= SP_SIG_RI; 2168 | #else 2169 | int bits; 2170 | if (ioctl(port->fd, TIOCMGET, &bits) < 0) 2171 | RETURN_FAIL("TIOCMGET ioctl failed"); 2172 | if (bits & TIOCM_CTS) 2173 | *signals |= SP_SIG_CTS; 2174 | if (bits & TIOCM_DSR) 2175 | *signals |= SP_SIG_DSR; 2176 | if (bits & TIOCM_CAR) 2177 | *signals |= SP_SIG_DCD; 2178 | if (bits & TIOCM_RNG) 2179 | *signals |= SP_SIG_RI; 2180 | #endif 2181 | RETURN_OK(); 2182 | } 2183 | 2184 | SP_API enum sp_return sp_start_break(struct sp_port *port) 2185 | { 2186 | TRACE("%p", port); 2187 | 2188 | CHECK_OPEN_PORT(); 2189 | #ifdef _WIN32 2190 | if (SetCommBreak(port->hdl) == 0) 2191 | RETURN_FAIL("SetCommBreak() failed"); 2192 | #else 2193 | if (ioctl(port->fd, TIOCSBRK, 1) < 0) 2194 | RETURN_FAIL("TIOCSBRK ioctl failed"); 2195 | #endif 2196 | 2197 | RETURN_OK(); 2198 | } 2199 | 2200 | SP_API enum sp_return sp_end_break(struct sp_port *port) 2201 | { 2202 | TRACE("%p", port); 2203 | 2204 | CHECK_OPEN_PORT(); 2205 | #ifdef _WIN32 2206 | if (ClearCommBreak(port->hdl) == 0) 2207 | RETURN_FAIL("ClearCommBreak() failed"); 2208 | #else 2209 | if (ioctl(port->fd, TIOCCBRK, 1) < 0) 2210 | RETURN_FAIL("TIOCCBRK ioctl failed"); 2211 | #endif 2212 | 2213 | RETURN_OK(); 2214 | } 2215 | 2216 | SP_API int sp_last_error_code(void) 2217 | { 2218 | TRACE_VOID(); 2219 | #ifdef _WIN32 2220 | RETURN_INT(GetLastError()); 2221 | #else 2222 | RETURN_INT(errno); 2223 | #endif 2224 | } 2225 | 2226 | SP_API char *sp_last_error_message(void) 2227 | { 2228 | TRACE_VOID(); 2229 | 2230 | #ifdef _WIN32 2231 | LPVOID message; 2232 | DWORD error = GetLastError(); 2233 | 2234 | FormatMessage( 2235 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 2236 | FORMAT_MESSAGE_FROM_SYSTEM | 2237 | FORMAT_MESSAGE_IGNORE_INSERTS, 2238 | NULL, 2239 | error, 2240 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 2241 | (LPTSTR) &message, 2242 | 0, NULL ); 2243 | 2244 | RETURN_STRING(message); 2245 | #else 2246 | RETURN_STRING(strerror(errno)); 2247 | #endif 2248 | } 2249 | 2250 | SP_API void sp_free_error_message(char *message) 2251 | { 2252 | TRACE("%s", message); 2253 | 2254 | #ifdef _WIN32 2255 | LocalFree(message); 2256 | #else 2257 | (void)message; 2258 | #endif 2259 | 2260 | RETURN(); 2261 | } 2262 | 2263 | SP_API void sp_set_debug_handler(void (*handler)(const char *format, ...)) 2264 | { 2265 | TRACE("%p", handler); 2266 | 2267 | sp_debug_handler = handler; 2268 | 2269 | RETURN(); 2270 | } 2271 | 2272 | SP_API void sp_default_debug_handler(const char *format, ...) 2273 | { 2274 | va_list args; 2275 | va_start(args, format); 2276 | if (getenv("LIBSERIALPORT_DEBUG")) { 2277 | fputs("sp: ", stderr); 2278 | vfprintf(stderr, format, args); 2279 | } 2280 | va_end(args); 2281 | } 2282 | 2283 | SP_API int sp_get_major_package_version(void) 2284 | { 2285 | return SP_PACKAGE_VERSION_MAJOR; 2286 | } 2287 | 2288 | SP_API int sp_get_minor_package_version(void) 2289 | { 2290 | return SP_PACKAGE_VERSION_MINOR; 2291 | } 2292 | 2293 | SP_API int sp_get_micro_package_version(void) 2294 | { 2295 | return SP_PACKAGE_VERSION_MICRO; 2296 | } 2297 | 2298 | SP_API const char *sp_get_package_version_string(void) 2299 | { 2300 | return SP_PACKAGE_VERSION_STRING; 2301 | } 2302 | 2303 | SP_API int sp_get_current_lib_version(void) 2304 | { 2305 | return SP_LIB_VERSION_CURRENT; 2306 | } 2307 | 2308 | SP_API int sp_get_revision_lib_version(void) 2309 | { 2310 | return SP_LIB_VERSION_REVISION; 2311 | } 2312 | 2313 | SP_API int sp_get_age_lib_version(void) 2314 | { 2315 | return SP_LIB_VERSION_AGE; 2316 | } 2317 | 2318 | SP_API const char *sp_get_lib_version_string(void) 2319 | { 2320 | return SP_LIB_VERSION_STRING; 2321 | } 2322 | 2323 | /** @} */ 2324 | -------------------------------------------------------------------------------- /windows.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libserialport project. 3 | * 4 | * Copyright (C) 2013-2014 Martin Ling 5 | * Copyright (C) 2014 Aurelien Jacobs 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as 9 | * published by the Free Software Foundation, either version 3 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #ifdef _WIN32 22 | 23 | #include "libserialport.h" 24 | #include "libserialport_internal.h" 25 | 26 | /* USB path is a string of at most 8 decimal numbers < 128 separated by dots */ 27 | #define MAX_USB_PATH (8*3 + 7*1 + 1) 28 | 29 | static void enumerate_hub(struct sp_port *port, char *hub_name, 30 | char *parent_path); 31 | 32 | static char *wc_to_utf8(PWCHAR wc_buffer, ULONG size) 33 | { 34 | WCHAR wc_str[size/sizeof(WCHAR)+1]; 35 | char *utf8_str; 36 | 37 | /* zero terminate the wide char string */ 38 | memcpy(wc_str, wc_buffer, size); 39 | wc_str[sizeof(wc_str)-1] = 0; 40 | 41 | /* compute the size of the utf8 converted string */ 42 | if (!(size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1, 43 | NULL, 0, NULL, NULL))) 44 | return NULL; 45 | 46 | /* allocate utf8 output buffer */ 47 | if (!(utf8_str = malloc(size))) 48 | return NULL; 49 | 50 | /* actually converted to utf8 */ 51 | if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1, 52 | utf8_str, size, NULL, NULL)) { 53 | free(utf8_str); 54 | return NULL; 55 | } 56 | 57 | return utf8_str; 58 | } 59 | 60 | static char *get_root_hub_name(HANDLE host_controller) 61 | { 62 | USB_ROOT_HUB_NAME root_hub_name; 63 | PUSB_ROOT_HUB_NAME root_hub_name_wc; 64 | char *root_hub_name_utf8; 65 | ULONG size = 0; 66 | 67 | /* compute the size of the root hub name string */ 68 | if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0, 69 | &root_hub_name, sizeof(root_hub_name), &size, NULL)) 70 | return NULL; 71 | 72 | /* allocate wide char root hub name string */ 73 | size = root_hub_name.ActualLength; 74 | if (!(root_hub_name_wc = malloc(size))) 75 | return NULL; 76 | 77 | /* actually get the root hub name string */ 78 | if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, 79 | NULL, 0, root_hub_name_wc, size, &size, NULL)) { 80 | free(root_hub_name_wc); 81 | return NULL; 82 | } 83 | 84 | /* convert the root hub name string to utf8 */ 85 | root_hub_name_utf8 = wc_to_utf8(root_hub_name_wc->RootHubName, size); 86 | free(root_hub_name_wc); 87 | return root_hub_name_utf8; 88 | } 89 | 90 | static char *get_external_hub_name(HANDLE hub, ULONG connection_index) 91 | { 92 | USB_NODE_CONNECTION_NAME ext_hub_name; 93 | PUSB_NODE_CONNECTION_NAME ext_hub_name_wc; 94 | char *ext_hub_name_utf8; 95 | ULONG size; 96 | 97 | /* compute the size of the external hub name string */ 98 | ext_hub_name.ConnectionIndex = connection_index; 99 | if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME, 100 | &ext_hub_name, sizeof(ext_hub_name), 101 | &ext_hub_name, sizeof(ext_hub_name), &size, NULL)) 102 | return NULL; 103 | 104 | /* allocate wide char external hub name string */ 105 | size = ext_hub_name.ActualLength; 106 | if (size <= sizeof(ext_hub_name) 107 | || !(ext_hub_name_wc = malloc(size))) 108 | return NULL; 109 | 110 | /* get the name of the external hub attached to the specified port */ 111 | ext_hub_name_wc->ConnectionIndex = connection_index; 112 | if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME, 113 | ext_hub_name_wc, size, 114 | ext_hub_name_wc, size, &size, NULL)) { 115 | free(ext_hub_name_wc); 116 | return NULL; 117 | } 118 | 119 | /* convert the external hub name string to utf8 */ 120 | ext_hub_name_utf8 = wc_to_utf8(ext_hub_name_wc->NodeName, size); 121 | free(ext_hub_name_wc); 122 | return ext_hub_name_utf8; 123 | } 124 | 125 | static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index, 126 | UCHAR descriptor_index) 127 | { 128 | char desc_req_buf[sizeof(USB_DESCRIPTOR_REQUEST) + 129 | MAXIMUM_USB_STRING_LENGTH] = { 0 }; 130 | PUSB_DESCRIPTOR_REQUEST desc_req = (void *) desc_req_buf; 131 | PUSB_STRING_DESCRIPTOR desc = (void *) (desc_req + 1); 132 | ULONG size = sizeof(desc_req_buf); 133 | 134 | desc_req->ConnectionIndex = connection_index; 135 | desc_req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) 136 | | descriptor_index; 137 | desc_req->SetupPacket.wIndex = 0; 138 | desc_req->SetupPacket.wLength = size - sizeof(*desc_req); 139 | 140 | if (!DeviceIoControl(hub_device, 141 | IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, 142 | desc_req, size, desc_req, size, &size, NULL) 143 | || size < 2 144 | || desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE 145 | || desc->bLength != size - sizeof(*desc_req) 146 | || desc->bLength % 2) 147 | return NULL; 148 | 149 | return wc_to_utf8(desc->bString, desc->bLength); 150 | } 151 | 152 | static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device, 153 | ULONG nb_ports, char *parent_path) 154 | { 155 | char path[MAX_USB_PATH]; 156 | ULONG index = 0; 157 | 158 | for (index = 1; index <= nb_ports; index++) { 159 | PUSB_NODE_CONNECTION_INFORMATION_EX connection_info_ex; 160 | ULONG size = sizeof(*connection_info_ex) + 30*sizeof(USB_PIPE_INFO); 161 | 162 | if (!(connection_info_ex = malloc(size))) 163 | break; 164 | 165 | connection_info_ex->ConnectionIndex = index; 166 | if (!DeviceIoControl(hub_device, 167 | IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, 168 | connection_info_ex, size, 169 | connection_info_ex, size, &size, NULL)) { 170 | /* try to get CONNECTION_INFORMATION if CONNECTION_INFORMATION_EX 171 | did not work */ 172 | PUSB_NODE_CONNECTION_INFORMATION connection_info; 173 | 174 | size = sizeof(*connection_info) + 30*sizeof(USB_PIPE_INFO); 175 | if (!(connection_info = malloc(size))) { 176 | free(connection_info_ex); 177 | continue; 178 | } 179 | connection_info->ConnectionIndex = index; 180 | if (!DeviceIoControl(hub_device, 181 | IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, 182 | connection_info, size, 183 | connection_info, size, &size, NULL)) { 184 | free(connection_info); 185 | free(connection_info_ex); 186 | continue; 187 | } 188 | 189 | connection_info_ex->ConnectionIndex = connection_info->ConnectionIndex; 190 | connection_info_ex->DeviceDescriptor = connection_info->DeviceDescriptor; 191 | connection_info_ex->DeviceIsHub = connection_info->DeviceIsHub; 192 | connection_info_ex->DeviceAddress = connection_info->DeviceAddress; 193 | free(connection_info); 194 | } 195 | 196 | if (connection_info_ex->DeviceIsHub) { 197 | /* recursively enumerate external hub */ 198 | PCHAR ext_hub_name; 199 | if ((ext_hub_name = get_external_hub_name(hub_device, index))) { 200 | snprintf(path, sizeof(path), "%s%ld.", 201 | parent_path, connection_info_ex->ConnectionIndex); 202 | enumerate_hub(port, ext_hub_name, path); 203 | } 204 | free(connection_info_ex); 205 | } else { 206 | snprintf(path, sizeof(path), "%s%ld", 207 | parent_path, connection_info_ex->ConnectionIndex); 208 | 209 | /* check if this device is the one we search for */ 210 | if (strcmp(path, port->usb_path)) { 211 | free(connection_info_ex); 212 | continue; 213 | } 214 | 215 | /* finally grab detailed informations regarding the device */ 216 | port->usb_address = connection_info_ex->DeviceAddress + 1; 217 | port->usb_vid = connection_info_ex->DeviceDescriptor.idVendor; 218 | port->usb_pid = connection_info_ex->DeviceDescriptor.idProduct; 219 | 220 | if (connection_info_ex->DeviceDescriptor.iManufacturer) 221 | port->usb_manufacturer = get_string_descriptor(hub_device,index, 222 | connection_info_ex->DeviceDescriptor.iManufacturer); 223 | if (connection_info_ex->DeviceDescriptor.iProduct) 224 | port->usb_product = get_string_descriptor(hub_device, index, 225 | connection_info_ex->DeviceDescriptor.iProduct); 226 | if (connection_info_ex->DeviceDescriptor.iSerialNumber) 227 | port->usb_serial = get_string_descriptor(hub_device, index, 228 | connection_info_ex->DeviceDescriptor.iSerialNumber); 229 | 230 | free(connection_info_ex); 231 | break; 232 | } 233 | } 234 | } 235 | 236 | static void enumerate_hub(struct sp_port *port, char *hub_name, 237 | char *parent_path) 238 | { 239 | USB_NODE_INFORMATION hub_info; 240 | HANDLE hub_device; 241 | ULONG size = sizeof(hub_info); 242 | char *device_name; 243 | 244 | /* open the hub with its full name */ 245 | if (!(device_name = malloc(strlen("\\\\.\\") + strlen(hub_name) + 1))) 246 | return; 247 | strcpy(device_name, "\\\\.\\"); 248 | strcat(device_name, hub_name); 249 | hub_device = CreateFile(device_name, GENERIC_WRITE, FILE_SHARE_WRITE, 250 | NULL, OPEN_EXISTING, 0, NULL); 251 | free(device_name); 252 | if (hub_device == INVALID_HANDLE_VALUE) 253 | return; 254 | 255 | /* get the number of ports of the hub */ 256 | if (DeviceIoControl(hub_device, IOCTL_USB_GET_NODE_INFORMATION, 257 | &hub_info, size, &hub_info, size, &size, NULL)) 258 | /* enumerate the ports of the hub */ 259 | enumerate_hub_ports(port, hub_device, 260 | hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts, parent_path); 261 | 262 | CloseHandle(hub_device); 263 | } 264 | 265 | static void enumerate_host_controller(struct sp_port *port, 266 | HANDLE host_controller_device) 267 | { 268 | char *root_hub_name; 269 | 270 | if ((root_hub_name = get_root_hub_name(host_controller_device))) { 271 | enumerate_hub(port, root_hub_name, ""); 272 | free(root_hub_name); 273 | } 274 | } 275 | 276 | static void get_usb_details(struct sp_port *port, DEVINST dev_inst_match) 277 | { 278 | HDEVINFO device_info; 279 | SP_DEVINFO_DATA device_info_data; 280 | ULONG i, size = 0; 281 | 282 | device_info = SetupDiGetClassDevs(&GUID_CLASS_USB_HOST_CONTROLLER,NULL,NULL, 283 | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 284 | device_info_data.cbSize = sizeof(device_info_data); 285 | 286 | for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) { 287 | SP_DEVICE_INTERFACE_DATA device_interface_data; 288 | PSP_DEVICE_INTERFACE_DETAIL_DATA device_detail_data; 289 | DEVINST dev_inst = dev_inst_match; 290 | HANDLE host_controller_device; 291 | 292 | device_interface_data.cbSize = sizeof(device_interface_data); 293 | if (!SetupDiEnumDeviceInterfaces(device_info, 0, 294 | &GUID_CLASS_USB_HOST_CONTROLLER, 295 | i, &device_interface_data)) 296 | continue; 297 | 298 | if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data, 299 | NULL, 0, &size, NULL) 300 | && GetLastError() != ERROR_INSUFFICIENT_BUFFER) 301 | continue; 302 | 303 | if (!(device_detail_data = malloc(size))) 304 | continue; 305 | device_detail_data->cbSize = sizeof(*device_detail_data); 306 | if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data, 307 | device_detail_data, size, &size, 308 | NULL)) { 309 | free(device_detail_data); 310 | continue; 311 | } 312 | 313 | while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS 314 | && dev_inst != device_info_data.DevInst) { } 315 | if (dev_inst != device_info_data.DevInst) { 316 | free(device_detail_data); 317 | continue; 318 | } 319 | 320 | port->usb_bus = i + 1; 321 | 322 | host_controller_device = CreateFile(device_detail_data->DevicePath, 323 | GENERIC_WRITE, FILE_SHARE_WRITE, 324 | NULL, OPEN_EXISTING, 0, NULL); 325 | if (host_controller_device != INVALID_HANDLE_VALUE) { 326 | enumerate_host_controller(port, host_controller_device); 327 | CloseHandle(host_controller_device); 328 | } 329 | free(device_detail_data); 330 | } 331 | 332 | SetupDiDestroyDeviceInfoList(device_info); 333 | return; 334 | } 335 | 336 | SP_PRIV enum sp_return get_port_details(struct sp_port *port) 337 | { 338 | /* Description limited to 127 char, 339 | anything longer would not be user friendly anyway */ 340 | char description[128]; 341 | SP_DEVINFO_DATA device_info_data = { .cbSize = sizeof(device_info_data) }; 342 | HDEVINFO device_info; 343 | int i; 344 | 345 | device_info = SetupDiGetClassDevs(NULL, 0, 0, 346 | DIGCF_PRESENT | DIGCF_ALLCLASSES); 347 | if (device_info == INVALID_HANDLE_VALUE) 348 | RETURN_FAIL("SetupDiGetClassDevs() failed"); 349 | 350 | for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) { 351 | HKEY device_key; 352 | DEVINST dev_inst; 353 | char value[8], class[16]; 354 | DWORD size, type; 355 | CONFIGRET cr; 356 | 357 | /* check if this is the device we are looking for */ 358 | device_key = SetupDiOpenDevRegKey(device_info, &device_info_data, 359 | DICS_FLAG_GLOBAL, 0, 360 | DIREG_DEV, KEY_QUERY_VALUE); 361 | if (device_key == INVALID_HANDLE_VALUE) 362 | continue; 363 | size = sizeof(value); 364 | if (RegQueryValueExA(device_key, "PortName", NULL, &type, (LPBYTE)value, 365 | &size) != ERROR_SUCCESS || type != REG_SZ) { 366 | RegCloseKey(device_key); 367 | continue; 368 | } 369 | RegCloseKey(device_key); 370 | value[sizeof(value)-1] = 0; 371 | if (strcmp(value, port->name)) 372 | continue; 373 | 374 | /* check port transport type */ 375 | dev_inst = device_info_data.DevInst; 376 | size = sizeof(class); 377 | cr = CR_FAILURE; 378 | while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS && 379 | (cr = CM_Get_DevNode_Registry_PropertyA(dev_inst, 380 | CM_DRP_CLASS, 0, class, &size, 0)) != CR_SUCCESS) { } 381 | if (cr == CR_SUCCESS) { 382 | if (!strcmp(class, "USB")) 383 | port->transport = SP_TRANSPORT_USB; 384 | } 385 | 386 | /* get port description (friendly name) */ 387 | dev_inst = device_info_data.DevInst; 388 | size = sizeof(description); 389 | while ((cr = CM_Get_DevNode_Registry_PropertyA(dev_inst, 390 | CM_DRP_FRIENDLYNAME, 0, description, &size, 0)) != CR_SUCCESS 391 | && CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS) { } 392 | if (cr == CR_SUCCESS) 393 | port->description = strdup(description); 394 | 395 | /* get more informations for USB connected ports */ 396 | if (port->transport == SP_TRANSPORT_USB) { 397 | char usb_path[MAX_USB_PATH] = "", tmp[MAX_USB_PATH]; 398 | char device_id[MAX_DEVICE_ID_LEN]; 399 | 400 | /* recurse over parents to build the USB device path */ 401 | dev_inst = device_info_data.DevInst; 402 | do { 403 | /* verify that this layer of the tree is USB related */ 404 | if (CM_Get_Device_IDA(dev_inst, device_id, 405 | sizeof(device_id), 0) != CR_SUCCESS 406 | || strncmp(device_id, "USB\\", 4)) 407 | continue; 408 | 409 | /* discard one layer for composite devices */ 410 | char compat_ids[512], *p = compat_ids; 411 | size = sizeof(compat_ids); 412 | if (CM_Get_DevNode_Registry_PropertyA(dev_inst, 413 | CM_DRP_COMPATIBLEIDS, 0, 414 | &compat_ids, 415 | &size, 0) == CR_SUCCESS) { 416 | while (*p) { 417 | if (!strncmp(p, "USB\\COMPOSITE", 13)) 418 | break; 419 | p += strlen(p) + 1; 420 | } 421 | if (*p) 422 | continue; 423 | } 424 | 425 | /* stop the recursion when reaching the USB root */ 426 | if (!strncmp(device_id, "USB\\ROOT", 8)) 427 | break; 428 | 429 | /* prepend the address of current USB layer to the USB path */ 430 | DWORD address; 431 | size = sizeof(address); 432 | if (CM_Get_DevNode_Registry_PropertyA(dev_inst, CM_DRP_ADDRESS, 433 | 0, &address, &size, 0) == CR_SUCCESS) { 434 | strcpy(tmp, usb_path); 435 | snprintf(usb_path, sizeof(usb_path), "%d%s%s", 436 | (int)address, *tmp ? "." : "", tmp); 437 | } 438 | } while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS); 439 | 440 | port->usb_path = strdup(usb_path); 441 | 442 | /* wake up the USB device to be able to read string descriptor */ 443 | char *escaped_port_name; 444 | HANDLE handle; 445 | if (!(escaped_port_name = malloc(strlen(port->name) + 5))) 446 | RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed"); 447 | sprintf(escaped_port_name, "\\\\.\\%s", port->name); 448 | handle = CreateFile(escaped_port_name, GENERIC_READ, 0, 0, 449 | OPEN_EXISTING, 450 | FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0); 451 | free(escaped_port_name); 452 | CloseHandle(handle); 453 | 454 | /* retrieve USB device details from the device descriptor */ 455 | get_usb_details(port, device_info_data.DevInst); 456 | } 457 | break; 458 | } 459 | 460 | SetupDiDestroyDeviceInfoList(device_info); 461 | 462 | RETURN_OK(); 463 | } 464 | 465 | SP_PRIV enum sp_return list_ports(struct sp_port ***list) 466 | { 467 | HKEY key; 468 | TCHAR *value, *data; 469 | DWORD max_value_len, max_data_size, max_data_len; 470 | DWORD value_len, data_size, data_len; 471 | DWORD type, index = 0; 472 | char *name; 473 | int name_len; 474 | int ret = SP_OK; 475 | 476 | DEBUG("Opening registry key"); 477 | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 478 | 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) { 479 | SET_FAIL(ret, "RegOpenKeyEx() failed"); 480 | goto out_done; 481 | } 482 | DEBUG("Querying registry key value and data sizes"); 483 | if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 484 | &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) { 485 | SET_FAIL(ret, "RegQueryInfoKey() failed"); 486 | goto out_close; 487 | } 488 | max_data_len = max_data_size / sizeof(TCHAR); 489 | if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) { 490 | SET_ERROR(ret, SP_ERR_MEM, "registry value malloc failed"); 491 | goto out_close; 492 | } 493 | if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) { 494 | SET_ERROR(ret, SP_ERR_MEM, "registry data malloc failed"); 495 | goto out_free_value; 496 | } 497 | DEBUG("Iterating over values"); 498 | while ( 499 | value_len = max_value_len + 1, 500 | data_size = max_data_size, 501 | RegEnumValue(key, index, value, &value_len, 502 | NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS) 503 | { 504 | if (type == REG_SZ) { 505 | data_len = data_size / sizeof(TCHAR); 506 | data[data_len] = '\0'; 507 | #ifdef UNICODE 508 | name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL); 509 | #else 510 | name_len = data_len + 1; 511 | #endif 512 | if (!(name = malloc(name_len))) { 513 | SET_ERROR(ret, SP_ERR_MEM, "registry port name malloc failed"); 514 | goto out; 515 | } 516 | #ifdef UNICODE 517 | WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL); 518 | #else 519 | strcpy(name, data); 520 | #endif 521 | DEBUG_FMT("Found port %s", name); 522 | if (!(*list = list_append(*list, name))) { 523 | SET_ERROR(ret, SP_ERR_MEM, "list append failed"); 524 | free(name); 525 | goto out; 526 | } 527 | free(name); 528 | } 529 | index++; 530 | } 531 | out: 532 | free(data); 533 | out_free_value: 534 | free(value); 535 | out_close: 536 | RegCloseKey(key); 537 | out_done: 538 | 539 | return ret; 540 | } 541 | 542 | #endif 543 | --------------------------------------------------------------------------------