]> sigrok.org Git - libserialport.git/blobdiff - serialport.c
Constify the sp_get_port_description() parameter.
[libserialport.git] / serialport.c
index cf384c18c48321d5e08ea7849ca51cc97c7dd855..074534edb8a898c280109a25b3da9ae537e1820e 100644 (file)
@@ -24,7 +24,7 @@
 #include "libserialport.h"
 #include "libserialport_internal.h"
 
-const struct std_baudrate std_baudrates[] = {
+static const struct std_baudrate std_baudrates[] = {
 #ifdef _WIN32
        /*
         * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
@@ -44,6 +44,8 @@ const struct std_baudrate std_baudrates[] = {
 #endif
 };
 
+#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
+
 void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
 
 static enum sp_return get_config(struct sp_port *port, struct port_data *data,
@@ -124,7 +126,7 @@ SP_API char *sp_get_port_name(const struct sp_port *port)
        RETURN_STRING(port->name);
 }
 
-SP_API char *sp_get_port_description(struct sp_port *port)
+SP_API char *sp_get_port_description(const struct sp_port *port)
 {
        TRACE("%p", port);
 
@@ -134,7 +136,7 @@ SP_API char *sp_get_port_description(struct sp_port *port)
        RETURN_STRING(port->description);
 }
 
-SP_API enum sp_transport sp_get_port_transport(struct sp_port *port)
+SP_API enum sp_transport sp_get_port_transport(const struct sp_port *port)
 {
        TRACE("%p", port);
 
@@ -320,39 +322,37 @@ fail:
 
 SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr)
 {
+#ifndef NO_ENUMERATION
        struct sp_port **list;
        int ret;
+#endif
 
        TRACE("%p", list_ptr);
 
        if (!list_ptr)
                RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
 
+#ifdef NO_ENUMERATION
+       RETURN_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform");
+#else
        DEBUG("Enumerating ports");
 
-       if (!(list = malloc(sizeof(struct sp_port **))))
+       if (!(list = malloc(sizeof(struct sp_port *))))
                RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed");
 
        list[0] = NULL;
 
-#ifdef NO_ENUMERATION
-       ret = SP_ERR_SUPP;
-#else
        ret = list_ports(&list);
-#endif
 
-       switch (ret) {
-       case SP_OK:
+       if (ret == SP_OK) {
                *list_ptr = list;
-               RETURN_OK();
-       case SP_ERR_SUPP:
-               DEBUG_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform");
-       default:
-               if (list)
-                       sp_free_port_list(list);
+       } else {
+               sp_free_port_list(list);
                *list_ptr = NULL;
-               return ret;
        }
+
+       RETURN_CODEVAL(ret);
+#endif
 }
 
 SP_API void sp_free_port_list(struct sp_port **list)
@@ -397,6 +397,43 @@ SP_API void sp_free_port_list(struct sp_port **list)
        CHECK_PORT_HANDLE(); \
 } while (0)
 
+#ifdef WIN32
+/** To be called after port receive buffer is emptied. */
+static enum sp_return restart_wait(struct sp_port *port)
+{
+       DWORD wait_result;
+
+       if (port->wait_running) {
+               /* Check status of running wait operation. */
+               if (GetOverlappedResult(port->hdl, &port->wait_ovl,
+                               &wait_result, FALSE)) {
+                       DEBUG("Previous wait completed");
+                       port->wait_running = FALSE;
+               } else if (GetLastError() == ERROR_IO_INCOMPLETE) {
+                       DEBUG("Previous wait still running");
+                       RETURN_OK();
+               } else {
+                       RETURN_FAIL("GetOverlappedResult() failed");
+               }
+       }
+
+       if (!port->wait_running) {
+               /* Start new wait operation. */
+               if (WaitCommEvent(port->hdl, &port->events,
+                               &port->wait_ovl)) {
+                       DEBUG("New wait returned, events already pending");
+               } else if (GetLastError() == ERROR_IO_PENDING) {
+                       DEBUG("New wait running in background");
+                       port->wait_running = TRUE;
+               } else {
+                       RETURN_FAIL("WaitCommEvent() failed");
+               }
+       }
+
+       RETURN_OK();
+}
+#endif
+
 SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
 {
        struct port_data data;
@@ -470,16 +507,15 @@ SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
                RETURN_FAIL("SetCommMask() failed");
        }
 
-       /* Start background operation for RX and error events. */
-       if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) {
-               if (GetLastError() != ERROR_IO_PENDING) {
-                       sp_close(port);
-                       RETURN_FAIL("WaitCommEvent() failed");
-               }
-       }
-
        port->writing = FALSE;
+       port->wait_running = FALSE;
+
+       ret = restart_wait(port);
 
+       if (ret < 0) {
+               sp_close(port);
+               RETURN_CODEVAL(ret);
+       }
 #else
        int flags_local = O_NONBLOCK | O_NOCTTY;
 
@@ -508,7 +544,7 @@ SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
        data.dcb.fDsrSensitivity = FALSE;
        data.dcb.fErrorChar = FALSE;
        data.dcb.fNull = FALSE;
-       data.dcb.fAbortOnError = TRUE;
+       data.dcb.fAbortOnError = FALSE;
 #else
        /* Turn off all fancy termios tricks, give us a raw channel. */
        data.term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IMAXBEL);
@@ -621,6 +657,9 @@ SP_API enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers)
        /* Returns non-zero upon success, 0 upon failure. */
        if (PurgeComm(port->hdl, flags) == 0)
                RETURN_FAIL("PurgeComm() failed");
+
+       if (buffers & SP_BUF_INPUT)
+               TRY(restart_wait(port));
 #else
        int flags = 0;
        if (buffers == SP_BUF_BOTH)
@@ -892,7 +931,8 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
 
 #ifdef _WIN32
        DWORD bytes_read = 0;
-       DWORD wait_result = 0;
+       DWORD bytes_remaining;
+       int ret;
 
        /* Set timeout. */
        port->timeouts.ReadIntervalTimeout = 0;
@@ -914,16 +954,16 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
                bytes_read = count;
        }
 
-       /* Restart wait operation if needed. */
-       if (GetOverlappedResult(port->hdl, &port->wait_ovl, &wait_result, FALSE)) {
-               /* Previous wait completed, start a new one. */
-               if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) {
-                       if (GetLastError() != ERROR_IO_PENDING)
-                               RETURN_FAIL("WaitCommEvent() failed");
-               }
-       } else if (GetLastError() != ERROR_IO_INCOMPLETE) {
-               RETURN_FAIL("GetOverlappedResult() failed");
-       }
+       ret = sp_input_waiting(port);
+
+       if (ret < 0)
+               RETURN_CODEVAL(ret);
+
+       bytes_remaining = ret;
+
+       /* Restart wait operation if buffer was emptied. */
+       if (bytes_read > 0 && bytes_remaining == 0)
+               TRY(restart_wait(port));
 
        RETURN_INT(bytes_read);
 
@@ -1003,7 +1043,8 @@ SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf,
 
 #ifdef _WIN32
        DWORD bytes_read;
-       DWORD wait_result;
+       DWORD bytes_remaining;
+       int ret;
 
        /* Set timeout. */
        port->timeouts.ReadIntervalTimeout = MAXDWORD;
@@ -1019,16 +1060,16 @@ SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf,
        if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
                RETURN_FAIL("GetOverlappedResult() failed");
 
-       /* Restart wait operation if needed. */
-       if (GetOverlappedResult(port->hdl, &port->wait_ovl, &wait_result, FALSE)) {
-               /* Previous wait completed, start a new one. */
-               if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) {
-                       if (GetLastError() != ERROR_IO_PENDING)
-                               RETURN_FAIL("WaitCommEvent() failed");
-               }
-       } else if (GetLastError() != ERROR_IO_INCOMPLETE) {
-               RETURN_FAIL("GetOverlappedResult() failed");
-       }
+       ret = sp_input_waiting(port);
+
+       if (ret < 0)
+               RETURN_CODEVAL(ret);
+
+       bytes_remaining = ret;
+
+       /* Restart wait operation if buffer was emptied. */
+       if (bytes_read > 0 && bytes_remaining == 0)
+               TRY(restart_wait(port));
 
        RETURN_INT(bytes_read);
 #else
@@ -1126,11 +1167,12 @@ static enum sp_return add_handle(struct sp_event_set *event_set,
                        sizeof(event_handle) * (event_set->count + 1))))
                RETURN_ERROR(SP_ERR_MEM, "Handle array realloc() failed");
 
+       event_set->handles = new_handles;
+
        if (!(new_masks = realloc(event_set->masks,
                        sizeof(enum sp_event) * (event_set->count + 1))))
                RETURN_ERROR(SP_ERR_MEM, "Mask array realloc() failed");
 
-       event_set->handles = new_handles;
        event_set->masks = new_masks;
 
        ((event_handle *) event_set->handles)[event_set->count] = handle;