improve windows serial

This commit is contained in:
lixianjing 2022-04-14 11:46:32 +08:00
parent 2ed6060b55
commit 613a248afb
4 changed files with 151 additions and 63 deletions

View File

@ -1,5 +1,8 @@
# 最新动态
2022/04/14
* 让 windows 的串口也支持 select 的形式(感谢智明提供补丁)。
2022/04/13
* 复切换主题时销毁style后由于控件need_update_style为false没有通知该控件style更新数据导致获取该控件样式属性时发生崩溃问题感谢兆坤提供补丁

View File

@ -41,19 +41,63 @@
#ifdef WIN32
#define prefix L"\\\\.\\"
#pragma comment(lib, "ws2_32")
static ret_t serial_wait_for_data_impl(serial_handle_t handle, uint32_t timeout_ms);
int serial_handle_get_fd(serial_handle_t handle) {
return 0;
return handle->client_fd;
}
serial_dev_t serial_handle_get_dev(serial_handle_t handle) {
return handle->dev;
}
static ret_t serial_cond_var_wait(serial_handle_t handle, uint32_t timeout_ms) {
ret_t ret = RET_OK;
tk_mutex_lock(handle->mutex);
if (!handle->has_signal) {
ret = tk_cond_wait_timeout(handle->cond, handle->mutex, timeout_ms);
}
handle->has_signal = FALSE;
tk_mutex_unlock(handle->mutex);
return ret;
}
static ret_t serial_cond_var_awake(serial_handle_t handle) {
return_value_if_fail(handle->cond != NULL && handle->mutex, RET_BAD_PARAMS);
tk_mutex_lock(handle->mutex);
handle->has_signal = TRUE;
tk_mutex_unlock(handle->mutex);
tk_cond_signal(handle->cond);
return RET_OK;
}
static void* serial_thread_entry(void* args) {
char buff[1] = {0};
serial_handle_t handle = (serial_handle_t)args;
int fd = handle->server_fd;
while (!handle->closed) {
if (serial_wait_for_data_impl(handle, 100) == RET_OK) {
while (send(fd, buff, sizeof(buff), 0) <= 0) {
log_warn("send fb buff fail \r\n");
}
serial_cond_var_wait(handle, 0xFFFFFFFF);
}
}
return NULL;
}
serial_handle_t serial_open(const char* port) {
wstr_t str;
serial_dev_t dev = 0;
int socks[2] = {0, 0};
serial_handle_t handle = NULL;
return_value_if_fail(port != NULL && *port != '\0', NULL);
@ -78,6 +122,19 @@ serial_handle_t serial_open(const char* port) {
handle->read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
handle->write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
handle->cond = tk_cond_create();
handle->mutex = tk_mutex_create();
handle->thread = tk_thread_create(serial_thread_entry, handle);
if (handle->cond == NULL || handle->mutex == NULL || handle->thread == NULL || tk_socketpair(socks) < 0 ) {
serial_close(handle);
return NULL;
}
handle->client_fd = socks[0];
handle->server_fd = socks[1];
tk_thread_start(handle->thread);
return handle;
}
@ -316,6 +373,11 @@ ret_t serial_config(serial_handle_t handle, uint32_t baudrate, bytesize_t bytesi
log_debug("Error setting timeouts.");
return RET_FAIL;
}
if (!SetCommMask(dev, EV_RXCHAR)) {
log_debug("Error setting RX event.");
return RET_FAIL;
}
return RET_OK;
}
@ -336,50 +398,71 @@ ret_t serial_oflush(serial_handle_t handle) {
}
int serial_close(serial_handle_t handle) {
serial_dev_t dev = serial_handle_get_dev(handle);
if (handle != NULL) {
serial_dev_t dev = serial_handle_get_dev(handle);
serial_iflush(handle);
serial_oflush(handle);
serial_iflush(handle);
serial_oflush(handle);
CancelIo(dev);
CloseHandle(dev);
CloseHandle(handle->read_overlapped.hEvent);
CloseHandle(handle->write_overlapped.hEvent);
if (dev != INVALID_HANDLE_VALUE) {
CancelIo(dev);
CloseHandle(dev);
}
if (handle->read_overlapped.hEvent != INVALID_HANDLE_VALUE) {
CloseHandle(handle->read_overlapped.hEvent);
}
if (handle->write_overlapped.hEvent != INVALID_HANDLE_VALUE) {
CloseHandle(handle->write_overlapped.hEvent);
}
TKMEM_FREE(handle);
handle->closed = TRUE;
serial_cond_var_awake(handle);
if (handle->thread != NULL) {
tk_thread_join(handle->thread);
tk_thread_destroy(handle->thread);
}
tk_socket_close(handle->client_fd);
tk_socket_close(handle->server_fd);
if (handle->mutex != NULL) {
tk_mutex_destroy(handle->mutex);
}
if (handle->cond != NULL) {
tk_cond_destroy(handle->cond);
}
TKMEM_FREE(handle);
}
return 0;
}
int32_t serial_read(serial_handle_t handle, uint8_t* buff, uint32_t max_size) {
DWORD err = 0;
DWORD bytes = 0;
char tmp_buff[1] = {0};
bool_t has_signal = FALSE;
serial_dev_t dev = serial_handle_get_dev(handle);
if (handle->buff_size == 0) {
if (!ReadFile(dev, buff, max_size, &bytes, &handle->read_overlapped)) {
err = GetLastError();
if (err == ERROR_IO_PENDING) {
GetOverlappedResult(dev, &handle->read_overlapped, &bytes, TRUE);
} else {
bytes = 0;
}
}
} else {
assert(handle->buff_index < sizeof(handle->buff));
bytes = tk_min(handle->buff_size, max_size);
memcpy(buff, &handle->buff[handle->buff_index], bytes);
handle->buff_size -= bytes;
handle->buff_index += bytes;
assert(handle->buff_size >= 0);
// buff size > handle->buff, try to read the rest data from driver fifo
int rest_size = max_size - bytes;
if (rest_size > 0) {
assert(handle->buff_size == 0);
int rest_bytes = serial_read(handle, buff + bytes, rest_size);
bytes += rest_bytes;
if (!ReadFile(dev, buff, max_size, &bytes, &handle->read_overlapped)) {
err = GetLastError();
if (err == ERROR_IO_PENDING) {
GetOverlappedResult(dev, &handle->read_overlapped, &bytes, TRUE);
} else {
bytes = 0;
}
}
tk_mutex_lock(handle->mutex);
if (bytes > 0 && !handle->has_signal) {
if (recv(handle->client_fd, tmp_buff, sizeof(tmp_buff), 0) > 0) {
handle->has_signal = has_signal = TRUE;
}
}
tk_mutex_unlock(handle->mutex);
if (has_signal) {
tk_cond_signal(handle->cond);
}
return bytes;
}
@ -399,39 +482,34 @@ int32_t serial_write(serial_handle_t handle, const uint8_t* buff, uint32_t max_s
return real_send;
}
ret_t serial_wait_for_data(serial_handle_t handle, uint32_t timeout_ms) {
static ret_t serial_wait_for_data_impl(serial_handle_t handle, uint32_t timeout_ms) {
DWORD err = 0;
ret_t ret = RET_FAIL;
DWORD mask = EV_RXCHAR;
serial_dev_t dev = serial_handle_get_dev(handle);
// handle->buff has data, direct return
if (handle->buff_size > 0) {
return RET_OK;
}
// GetOverlappedResult will exit if ReadTotalTimeoutConstant timeout
int t1 = time_now_ms();
while ((time_now_ms() - t1) < timeout_ms) {
handle->buff_size = 0;
handle->buff_index = 0;
if (!ReadFile(dev, handle->buff, sizeof(handle->buff), &handle->buff_size,
&handle->read_overlapped)) {
err = GetLastError();
if (err == ERROR_IO_PENDING) {
//GetOverlappedResultEx(dev, &handle->read_overlapped, &handle->buff_size, timeout_ms, TRUE);
GetOverlappedResult(dev, &handle->read_overlapped, &handle->buff_size, TRUE);
if (handle->buff_size > 0) {
break;
}
if (!WaitCommEvent(dev, &mask, &handle->read_overlapped)) {
err = GetLastError();
if (err == ERROR_IO_PENDING) {
err = WaitForSingleObject(handle->read_overlapped.hEvent, timeout_ms);
if (err == WAIT_OBJECT_0) {
ret = RET_OK;
} else if (err == WAIT_TIMEOUT) {
ret = RET_TIMEOUT;
} else {
ClearCommError(dev, &err, NULL);
return RET_FAIL;
ret = RET_FAIL;
}
} else {
break;
}
} else {
ret = RET_OK;
}
ClearCommError(dev, &err, NULL);
return handle->buff_size > 0 ? RET_OK : RET_TIMEOUT;
return ret;
}
ret_t serial_wait_for_data(serial_handle_t handle, uint32_t timeout_ms) {
int fd = serial_handle_get_fd(handle);
return tk_socket_wait_for_data(fd, timeout_ms);
}
#else

View File

@ -31,16 +31,22 @@ BEGIN_C_DECLS
#ifdef WIN32
#include "windows.h"
#include "tkc/mutex.h"
#include "tkc/cond_var.h"
typedef HANDLE serial_dev_t;
typedef struct _serial_info_t {
serial_dev_t dev;
int buff_size;
int buff_index;
char buff[1];
OVERLAPPED read_overlapped;
OVERLAPPED write_overlapped;
bool_t closed;
bool_t has_signal;
int client_fd;
int server_fd;
tk_cond_t* cond;
tk_mutex_t* mutex;
tk_thread_t* thread;
} serial_info_t;
#else

View File

@ -41,16 +41,17 @@ tk_cond_var_t* tk_cond_var_create(void) {
}
ret_t tk_cond_var_wait(tk_cond_var_t* cond_var, uint32_t timeout_ms) {
ret_t ret = RET_OK;
return_value_if_fail(cond_var != NULL && cond_var->inited, RET_BAD_PARAMS);
tk_mutex_lock(cond_var->mutex);
if (!cond_var->has_signal) {
tk_cond_wait_timeout(cond_var->cond, cond_var->mutex, timeout_ms);
ret = tk_cond_wait_timeout(cond_var->cond, cond_var->mutex, timeout_ms);
}
cond_var->has_signal = FALSE;
tk_mutex_unlock(cond_var->mutex);
return RET_OK;
return ret;
}
ret_t tk_cond_var_awake(tk_cond_var_t* cond_var) {