/** * @file qdx_port_win32.c * @brief Windows (WinSock2 + WinAPI) 平台移植层 * * 目的:将 qdx_port.h 声明的 HAL 接口映射到 Windows API, * 使 QDXnetworkStack 库能够在 PC 端运行。 * * 注意:本文件仅用于 PC 端 Demo 模拟,不适用于 MCU 移植。 */ #include "qdx_port.h" #include /* _beginthreadex */ #include #include #include #include /* ============================================================ * 时间与延迟 * ============================================================ */ /* 获取系统启动以来的毫秒数 */ uint32_t qdx_port_get_tick_ms(void) { return (uint32_t)GetTickCount(); } /* 阻塞延迟指定毫秒 */ void qdx_port_delay_ms(uint32_t ms) { Sleep(ms); } /* ============================================================ * TCP 网络操作 (基于 WinSock2) * ============================================================ */ /** * @brief 创建 TCP 套接字并连接到远端 * * 连接成功后设置 500ms 接收超时,防止接收线程永久阻塞。 */ qdx_socket_t qdx_port_tcp_connect(const char *ip, uint16_t port) { SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { return NULL; } struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) { closesocket(sock); return NULL; } /* 设置接收超时 500ms,使 recv 线程可定期检查连接状态 */ DWORD timeout_ms = 500; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout_ms, sizeof(timeout_ms)); printf("[Port] TCP 已连接: %s:%d\n", ip, port); /* 将 SOCKET 转为不透明指针(SOCKET 本身是 unsigned int 类型) */ return (qdx_socket_t)(intptr_t)sock; } /* 关闭 TCP 套接字 */ void qdx_port_tcp_close(qdx_socket_t sock) { if (sock) { closesocket((SOCKET)(intptr_t)sock); } } /* TCP 发送 */ int32_t qdx_port_tcp_send(qdx_socket_t sock, const uint8_t *data, uint32_t len) { if (!sock) return -1; int ret = send((SOCKET)(intptr_t)sock, (const char *)data, (int)len, 0); if (ret == SOCKET_ERROR) { return -1; } return (int32_t)ret; } /** * @brief TCP 接收(非阻塞/短超时) * * 返回值约定: * > 0 : 实际收到的字节数 * = 0 : 超时无数据 * < 0 : 连接断开或错误 */ int32_t qdx_port_tcp_recv(qdx_socket_t sock, uint8_t *buf, uint32_t max_len) { if (!sock) return -1; int ret = recv((SOCKET)(intptr_t)sock, (char *)buf, (int)max_len, 0); if (ret == SOCKET_ERROR) { int err = WSAGetLastError(); /* WSAETIMEDOUT / WSAEWOULDBLOCK 表示超时,视为无数据可读 */ if (err == WSAETIMEDOUT || err == WSAEWOULDBLOCK) { return 0; } return -1; /* 真实错误 */ } if (ret == 0) { return -1; /* 服务端主动关闭连接 */ } return (int32_t)ret; } /* ============================================================ * 互斥锁 (基于 CRITICAL_SECTION) * ============================================================ */ /* 创建互斥锁 */ qdx_mutex_t qdx_port_mutex_create(void) { CRITICAL_SECTION *cs = (CRITICAL_SECTION *)malloc(sizeof(CRITICAL_SECTION)); if (!cs) return NULL; InitializeCriticalSection(cs); return (qdx_mutex_t)cs; } /* 加锁 */ void qdx_port_mutex_lock(qdx_mutex_t mutex) { if (mutex) { EnterCriticalSection((CRITICAL_SECTION *)mutex); } } /* 解锁 */ void qdx_port_mutex_unlock(qdx_mutex_t mutex) { if (mutex) { LeaveCriticalSection((CRITICAL_SECTION *)mutex); } } /* 销毁互斥锁 */ void qdx_port_mutex_delete(qdx_mutex_t mutex) { if (mutex) { DeleteCriticalSection((CRITICAL_SECTION *)mutex); free(mutex); } } /* ============================================================ * 线程 (基于 _beginthreadex) * ============================================================ */ /** * @brief 线程启动包装器 * * 目的:_beginthreadex 要求 unsigned __stdcall 签名, * 而 qdx_thread_entry_t 是 void(*)(void*), * 需要通过此包装器做签名适配。 */ typedef struct { qdx_thread_entry_t entry; void *arg; } ThreadWrapper_t; static unsigned __stdcall thread_wrapper(void *param) { ThreadWrapper_t *tw = (ThreadWrapper_t *)param; qdx_thread_entry_t entry = tw->entry; void *arg = tw->arg; free(tw); /* 释放包装结构,生命周期结束 */ entry(arg); return 0; } /* 创建后台线程 */ int8_t qdx_port_thread_create(const char *name, qdx_thread_entry_t entry, void *arg, uint32_t stack_size, uint8_t priority) { (void)name; /* Windows 线程不直接支持命名 */ (void)priority; /* 简化 Demo 不设线程优先级 */ ThreadWrapper_t *tw = (ThreadWrapper_t *)malloc(sizeof(ThreadWrapper_t)); if (!tw) return -1; tw->entry = entry; tw->arg = arg; HANDLE h = (HANDLE)_beginthreadex(NULL, stack_size, thread_wrapper, tw, 0, NULL); if (h == NULL) { free(tw); return -1; } /* 分离线程句柄,后台自动运行 */ CloseHandle(h); return 0; }