X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=serialport.c;h=39500f8f93fa699e17c5b13bf6292551ae388198;hb=27911925c11b01943e2a569ebb71fe259c387329;hp=80527be098a85eed8d624ce7ff8dd4e5dc594e12;hpb=5f64c28551d7ee7dbecf5215cb75d63c3cf8303b;p=libserialport.git diff --git a/serialport.c b/serialport.c index 80527be..39500f8 100644 --- a/serialport.c +++ b/serialport.c @@ -334,6 +334,8 @@ SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr) if (!list_ptr) RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); + *list_ptr = NULL; + #ifdef NO_ENUMERATION RETURN_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform"); #else @@ -749,23 +751,24 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, } /* Set timeout. */ - port->timeouts.WriteTotalTimeoutConstant = timeout_ms; - if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) - RETURN_FAIL("SetCommTimeouts() failed"); + if (port->timeouts.WriteTotalTimeoutConstant != timeout_ms) { + port->timeouts.WriteTotalTimeoutConstant = timeout_ms; + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) + RETURN_FAIL("SetCommTimeouts() failed"); + } /* Start write. */ - if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl) == 0) { - if (GetLastError() == ERROR_IO_PENDING) { - DEBUG("Waiting for write to complete"); - GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE); - DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, count); - RETURN_INT(bytes_written); - } else { - RETURN_FAIL("WriteFile() failed"); - } - } else { + if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl)) { DEBUG("Write completed immediately"); RETURN_INT(count); + } else if (GetLastError() == ERROR_IO_PENDING) { + DEBUG("Waiting for write to complete"); + if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE) == 0) + RETURN_FAIL("GetOverlappedResult() failed"); + DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, count); + RETURN_INT(bytes_written); + } else { + RETURN_FAIL("WriteFile() failed"); } #else size_t bytes_written = 0; @@ -862,9 +865,11 @@ SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, } /* Set timeout. */ - port->timeouts.WriteTotalTimeoutConstant = 0; - if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) - RETURN_FAIL("SetCommTimeouts() failed"); + if (port->timeouts.WriteTotalTimeoutConstant != 0) { + port->timeouts.WriteTotalTimeoutConstant = 0; + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) + RETURN_FAIL("SetCommTimeouts() failed"); + } /* * Keep writing data until the OS has to actually start an async IO @@ -911,6 +916,26 @@ SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, #endif } +#ifdef _WIN32 +/* Restart wait operation if buffer was emptied. */ +static enum sp_return restart_wait_if_needed(struct sp_port *port, unsigned int bytes_read) +{ + DWORD errors; + COMSTAT comstat; + + if (bytes_read == 0) + RETURN_OK(); + + if (ClearCommError(port->hdl, &errors, &comstat) == 0) + RETURN_FAIL("ClearCommError() failed"); + + if (comstat.cbInQue == 0) + TRY(restart_wait(port)); + + RETURN_OK(); +} +#endif + SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, unsigned int timeout_ms) { @@ -933,39 +958,30 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, #ifdef _WIN32 DWORD bytes_read = 0; - DWORD bytes_remaining; - int ret; /* Set timeout. */ - port->timeouts.ReadIntervalTimeout = 0; - port->timeouts.ReadTotalTimeoutConstant = timeout_ms; - if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) - RETURN_FAIL("SetCommTimeouts() failed"); + if (port->timeouts.ReadIntervalTimeout != 0 || + port->timeouts.ReadTotalTimeoutConstant != timeout_ms) { + port->timeouts.ReadIntervalTimeout = 0; + port->timeouts.ReadTotalTimeoutConstant = timeout_ms; + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) + RETURN_FAIL("SetCommTimeouts() failed"); + } /* Start read. */ - if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0) { - if (GetLastError() == ERROR_IO_PENDING) { - DEBUG("Waiting for read to complete"); - GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE); - DEBUG_FMT("Read completed, %d/%d bytes read", bytes_read, count); - } else { - RETURN_FAIL("ReadFile() failed"); - } - } else { + if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl)) { DEBUG("Read completed immediately"); bytes_read = count; + } else if (GetLastError() == ERROR_IO_PENDING) { + DEBUG("Waiting for read to complete"); + if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0) + RETURN_FAIL("GetOverlappedResult() failed"); + DEBUG_FMT("Read completed, %d/%d bytes read", bytes_read, count); + } else { + RETURN_FAIL("ReadFile() 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)); + TRY(restart_wait_if_needed(port, bytes_read)); RETURN_INT(bytes_read); @@ -1045,14 +1061,15 @@ SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, #ifdef _WIN32 DWORD bytes_read; - DWORD bytes_remaining; - int ret; /* Set timeout. */ - port->timeouts.ReadIntervalTimeout = MAXDWORD; - port->timeouts.ReadTotalTimeoutConstant = 0; - if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) - RETURN_FAIL("SetCommTimeouts() failed"); + if (port->timeouts.ReadIntervalTimeout != MAXDWORD || + port->timeouts.ReadTotalTimeoutConstant != 0) { + port->timeouts.ReadIntervalTimeout = MAXDWORD; + port->timeouts.ReadTotalTimeoutConstant = 0; + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) + RETURN_FAIL("SetCommTimeouts() failed"); + } /* Do read. */ if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0) @@ -1062,16 +1079,7 @@ 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"); - 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)); + TRY(restart_wait_if_needed(port, bytes_read)); RETURN_INT(bytes_read); #else @@ -2117,6 +2125,8 @@ SP_API enum sp_return sp_set_##x(struct sp_port *port, type x) { \ SP_API enum sp_return sp_get_config_##x(const struct sp_port_config *config, \ type *x) { \ TRACE("%p, %p", config, x); \ + if (!x) \ + RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); \ if (!config) \ RETURN_ERROR(SP_ERR_ARG, "Null config"); \ *x = config->x; \ @@ -2283,10 +2293,10 @@ SP_API char *sp_last_error_message(void) TRACE_VOID(); #ifdef _WIN32 - LPVOID message; + TCHAR *message; DWORD error = GetLastError(); - FormatMessage( + DWORD length = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, @@ -2296,6 +2306,9 @@ SP_API char *sp_last_error_message(void) (LPTSTR) &message, 0, NULL ); + if (length >= 2 && message[length - 2] == '\r') + message[length - 2] = '\0'; + RETURN_STRING(message); #else RETURN_STRING(strerror(errno));