X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=serialport.c;h=07a0aaa54b915fac58053e83c7541c55de925c89;hb=573feabc63340ef853108762682dce8aa4644cb5;hp=49cba74a2b2d8a6081ccb8b5825eaafbea2eb878;hpb=6bd6a8b5203633baf5593eae72438a180c77b489;p=libserialport.git diff --git a/serialport.c b/serialport.c index 49cba74..07a0aaa 100644 --- a/serialport.c +++ b/serialport.c @@ -49,12 +49,19 @@ static const struct std_baudrate std_baudrates[] = { void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler; +static void get_time(struct timeval *time); + static enum sp_return get_config(struct sp_port *port, struct port_data *data, struct sp_port_config *config); static enum sp_return set_config(struct sp_port *port, struct port_data *data, const struct sp_port_config *config); +static void get_time(struct timeval *time) +{ + gettimeofday(time, NULL); +} + SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) { struct sp_port *port; @@ -104,6 +111,8 @@ SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port * #ifdef _WIN32 port->usb_path = NULL; port->hdl = INVALID_HANDLE_VALUE; + port->write_buf = NULL; + port->write_buf_size = 0; #else port->fd = -1; #endif @@ -310,6 +319,8 @@ SP_API void sp_free_port(struct sp_port *port) #ifdef _WIN32 if (port->usb_path) free(port->usb_path); + if (port->write_buf) + free(port->write_buf); #endif free(port); @@ -643,6 +654,10 @@ SP_API enum sp_return sp_close(struct sp_port *port) CLOSE_OVERLAPPED(write_ovl); CLOSE_OVERLAPPED(wait_ovl); + if (port->write_buf) { + free(port->write_buf); + port->write_buf = NULL; + } #else /* Returns 0 upon success, -1 upon failure. */ if (close(port->fd) == -1) @@ -785,6 +800,10 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, RETURN_FAIL("SetCommTimeouts() failed"); } + /* Reduce count if it exceeds the WriteFile limit. */ + if (count > WRITEFILE_MAX_SIZE) + count = WRITEFILE_MAX_SIZE; + /* Start write. */ if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl)) { DEBUG("Write completed immediately"); @@ -814,7 +833,7 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, if (timeout_ms) { /* Get time at start of operation. */ - gettimeofday(&start, NULL); + get_time(&start); /* Define duration of timeout. */ delta.tv_sec = timeout_ms / 1000; delta.tv_usec = (timeout_ms % 1000) * 1000; @@ -833,7 +852,7 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, * select() is even run. */ if (timeout_ms && started) { - gettimeofday(&now, NULL); + get_time(&now); if (timercmp(&now, &end, >)) /* Timeout has expired. */ break; @@ -892,8 +911,7 @@ SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, RETURN_INT(0); #ifdef _WIN32 - DWORD written = 0; - BYTE *ptr = (BYTE *) buf; + DWORD buf_bytes; /* Check whether previous write is complete. */ if (port->writing) { @@ -914,40 +932,30 @@ SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, RETURN_FAIL("SetCommTimeouts() failed"); } - /* - * Keep writing data until the OS has to actually start an async IO - * for it. At that point we know the buffer is full. - */ - while (written < count) { - /* Copy first byte of user buffer. */ - port->pending_byte = *ptr++; - - /* Start asynchronous write. */ - if (WriteFile(port->hdl, &port->pending_byte, 1, NULL, &port->write_ovl) == 0) { - if (GetLastError() == ERROR_IO_PENDING) { - if (HasOverlappedIoCompleted(&port->write_ovl)) { - DEBUG("Asynchronous write completed immediately"); - port->writing = 0; - written++; - continue; - } else { - DEBUG("Asynchronous write running"); - port->writing = 1; - RETURN_INT(++written); - } - } else { - /* Actual failure of some kind. */ - RETURN_FAIL("WriteFile() failed"); - } + /* Reduce count if it exceeds the WriteFile limit. */ + if (count > WRITEFILE_MAX_SIZE) + count = WRITEFILE_MAX_SIZE; + + /* Copy data to our write buffer. */ + buf_bytes = min(port->write_buf_size, count); + memcpy(port->write_buf, buf, buf_bytes); + + /* Start asynchronous write. */ + if (WriteFile(port->hdl, port->write_buf, buf_bytes, NULL, &port->write_ovl) == 0) { + if (GetLastError() == ERROR_IO_PENDING) { + if ((port->writing = !HasOverlappedIoCompleted(&port->write_ovl))) + DEBUG("Asynchronous write completed immediately"); + else + DEBUG("Asynchronous write running"); } else { - DEBUG("Single byte written immediately"); - written++; + /* Actual failure of some kind. */ + RETURN_FAIL("WriteFile() failed"); } } DEBUG("All bytes written immediately"); - RETURN_INT(written); + RETURN_INT(buf_bytes); #else /* Returns the number of bytes written, or -1 upon failure. */ ssize_t written = write(port->fd, buf, count); @@ -1045,7 +1053,7 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, if (timeout_ms) { /* Get time at start of operation. */ - gettimeofday(&start, NULL); + get_time(&start); /* Define duration of timeout. */ delta.tv_sec = timeout_ms / 1000; delta.tv_usec = (timeout_ms % 1000) * 1000; @@ -1064,7 +1072,7 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, * select() is even run. */ if (timeout_ms && started) { - gettimeofday(&now, NULL); + get_time(&now); if (timercmp(&now, &end, >)) /* Timeout has expired. */ break; @@ -1182,7 +1190,7 @@ SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf, if (timeout_ms) { /* Get time at start of operation. */ - gettimeofday(&start, NULL); + get_time(&start); /* Define duration of timeout. */ delta.tv_sec = timeout_ms / 1000; delta.tv_usec = (timeout_ms % 1000) * 1000; @@ -1201,7 +1209,7 @@ SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf, * select() is even run. */ if (timeout_ms && started) { - gettimeofday(&now, NULL); + get_time(&now); if (timercmp(&now, &end, >)) /* Timeout has expired. */ break; @@ -1484,7 +1492,7 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set, if (timeout_ms) { /* Get time at start of operation. */ - gettimeofday(&start, NULL); + get_time(&start); /* Define duration of timeout. */ delta.tv_sec = timeout_ms / 1000; delta.tv_usec = (timeout_ms % 1000) * 1000; @@ -1505,7 +1513,7 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set, timeout_overflow = (timeout_ms > INT_MAX); timeout_remaining_ms = timeout_overflow ? INT_MAX : timeout_ms; } else { - gettimeofday(&now, NULL); + get_time(&now); if (timercmp(&now, &end, >)) { DEBUG("Wait timed out"); break; @@ -1894,6 +1902,14 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data, if (i == NUM_STD_BAUDRATES) data->dcb.BaudRate = config->baudrate; + + /* Allocate write buffer for 50ms of data at baud rate. */ + port->write_buf_size = max(config->baudrate / (8 * 20), 1); + port->write_buf = realloc(port->write_buf, + port->write_buf_size); + + if (!port->write_buf) + RETURN_ERROR(SP_ERR_MEM, "Allocating write buffer failed"); } if (config->bits >= 0)