asynchronous serial port communication in windows in c
当我尝试运行对串行端口进行一些基本写入的c文件时,出现错误。我尝试异步运行它,因为写入有时需要很长时间才能传输。我的原始版本使它与WriteFile()命令同步运行,效果很好。我是使用OVERLAPPED的新手,希望能对此有所感激和投入。
我得到的错误是:
1 2 3 4 | Debug Assertion Failed! <path to dbgheap.c> Line: 1317 Expression: _CrtIsValidHeapPointer(pUserData) |
当第二个写函数被调用时。
在主要方面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | { //initialized port (with overlapped), DBC, and timeouts result = write_port(outPortHandle, 128); result = write_port(outPortHandle, 131); } static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) { //write completed. check for errors? if so throw an exception maybe? printf("write completed--and made it to callback function\ "); } int write_port(HANDLE hComm,BYTE* lpBuf) { OVERLAPPED osWrite = {0}; // Create this write operation's OVERLAPPED structure's hEvent. osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (osWrite.hEvent == NULL) // error creating overlapped event handle return 0; // Issue write. if (!WriteFileEx(hComm, &lpBuf, 1, &osWrite, &write_compl )) { if (GetLastError() != ERROR_IO_PENDING) { // WriteFile failed, but isn't delayed. Report error and abort. printf("last error: %ld",GetLastError()); return 0; //failed, return false; } else { // Write is pending. WaitForSingleObjectEx(osWrite.hEvent, 50, TRUE); //50 ms timeout return -1; //pending } } else { return 1; //finished } } |
抱歉,那不是完整的代码。我也使用了一组BYTE,而不是常量。但是system(" pause")导致我的调试断言失败错误,并且仔细查看我的代码后,当WriteFileEx()成功时,它从未为重叠结构中的事件设置警报/超时,因此回调函数将永远不会被调用。我解决了这些问题。
我只需要帮助处理/访问在调用ReadFileEx()函数时分配的结构中的单个BYTE(用于存储读取的BYTE,以便可以对其进行处理)。我需要知道如何使用偏移量访问BYTE存储并使重叠的结构为null。将重叠结构设为null就像将其中的句柄设置为INVALID_HANDLE_VALUE一样简单吗?
我认为您有几个问题:
您正在传递一个整数作为指针(您的编译器应对此发出警告,或者最好拒绝编译代码):
result = write_port(outPortHandle, 128);
将此与write_port的定义进行比较:
int write_port(HANDLE hComm,BYTE* lpBuf) {
上面的陈述不符。稍后,您通过获取BYTE *->"&lpBuf"的地址,将指向lpBuf的指针传递给WriteFileEx函数。这不会导致您认为的结果。
即使已解决此问题,只要写入成功排队但仍无法在50毫秒的超时时间内完成,您仍然会遇到潜在的生命周期问题。
使用重叠的I / O时,需要确保读/写缓冲区和重叠的结构保持有效,直到I / O完成,取消或关联的设备关闭为止。在上面的代码中,您使用指向OVERLAPPED结构的指针,该结构位于对WriteFileEx的调用中的堆栈中。如果WriteFileEx在50毫秒内未完成,则挂起的I / O将引用不存在的OVERLAPPED结构,并且(希望)发生访问冲突(或更糟糕的是,在应用程序中的某个位置静默损坏了堆栈数据)。
处理这些生命周期问题(如果性能不是大问题)的规范方法是使用自定义结构,该结构包括OVERLAPPED结构和一些用于读取/写入数据的存储。发布写操作时分配结构,并从I / O完成例程中取消分配结构。将包含的OVERLAPPED结构的地址传递给WriteFileEx,并使用例如offsetof以从完成例程中的OVERLAPPED地址获取自定义结构的地址。
还要注意,WriteFileEx实际上并不使用hEvent成员IIRC。
编辑:添加了代码示例,请注意:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #include <stddef.h> #include #include <windows.h> // ... typedef struct _MYOVERLAPPED { OVERLAPPED ol; BYTE buffer; } MYOVERLAPPED, *LPMYOVERLAPPED; // ... static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) { if (NULL == lpOverlapped) { assert(!"Should never happen"); return; } LPBYTE pOlAsBytes = (LPBYTE)lpOverlapped; LPBYTE pMyOlAsBytes = pOlAsBytes - offsetof(MYOVERLAPPED, ol); LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)pOlAsBytes; if ((ERROR_SUCCESS == dwErrorCode) && (sizeof(BYTE) == dwNumberOfBytesTransfered)) { printf("written %uc\ ", pMyOl->buffer); } else { // handle error } free(pMyOl); } int write_port(HANDLE hComm, BYTE byte) { LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)malloc(sizeof(MYOVERLAPPED)); ZeroMemory(pMyOl, sizeof(MYOVERLAPPED)); pMyOl->buffer = byte; // Issue write. if (!WriteFileEx(hComm, &pMyOl->buffer, sizeof(BYTE), pMyOl, &write_compl )) { if (GetLastError() != ERROR_IO_PENDING) { // WriteFile failed, but isn't delayed. Report error and abort. free(pMyOl); printf("last error: %ld",GetLastError()); return 0; //failed, return false; } else { return -1; //pending } } else { free(pMyOl); return 1; //finished } } |
1
2 result = write_port(outPortHandle, 128);
result = write_port(outPortHandle, 131);
lpBuf参数必须是指向缓冲区的指针,而不是常量。
例如
1 2 3 4 5 | char buffer; buffer = 128; result = write_port(outPortHandle, &buffer); buffer = 131; result = write_port(outPortHandle, &buffer); |
您真正想要做的是还传递缓冲区长度。
例如
1 2 3 4 5 6 7 8 9 10 | char buffer[] = { 128, 131 }; result = write_port(outPortHandle, &buffer, sizeof(buffer)); int write_port(HANDLE hComm,BYTE* lpBuf, size_t length) { ... // Issue write. if (!WriteFileEx(hComm, &lpBuf, length, &osWrite, &write_compl )) { ... |