c中windows中的异步串口通信

时间:2009-06-03 21:11:20

标签: c windows asynchronous serial-port

当我尝试运行一个对串行端口进行基本写操作的c文件时,我收到错误。我试图异步运行它,因为写入有时需要很长时间才能进行传输。我的原始版本让它与WriteFile()命令同步运行,这些命令运行正常。我是使用OVERLAPPED的新手,我会很感激和投入。

我得到的错误是:

Debug Assertion Failed! 
<path to dbgheap.c> 
Line: 1317 
Expression: _CrtIsValidHeapPointer(pUserData)

调用第二个写函数时。

主要:

    {
        //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\n");
    }


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,而不是常量。但系统(“暂停”)导致我的调试断言失败错误,并仔细查看我的代码后,当WriteFileEx()成功时,它从未在重叠结构中的事件上设置警报/超时,所以永远不会调用回调函数。我解决了这些问题。

我只需要帮助处理/访问一个结构中的单个BYTE,该结构在调用ReadFileEx()函数时分配(用于存储读取的BYTE以便可以处理)。我需要知道如何使用偏移量访问该BYTE存储,并使重叠结构为空。将重叠结构null设置为将其中的句柄设置为INVALID_HANDLE_VALUE这么简单吗?

2 个答案:

答案 0 :(得分:2)

我认为你有几个问题:


您正在传递一个整数作为指针(您的编译器应警告此情况,或者最好拒绝编译代码):

  

result = write_port(outPortHandle,128);

将其与write_port的定义进行比较:

  

int write_port(HANDLE hComm,BYTE * lpBuf){

以上陈述不符合。稍后,通过获取BYTE * - &gt;的地址,将指针传递给指向WriteFileEx函数的lpBuf指针。 “&安培; lpBuf”。这不会导致您认为它会做什么。


即使您解决了这个问题,只要写入成功排队,但在50毫秒超时内无法完成,您仍会遇到潜在的生命周期问题。

使用重叠I / O时,需要确保读/写缓冲区和重叠结构保持有效,直到I / O完成,取消或相关设备关闭为止。在上面的代码中,您使用指向写入WriteFileEx的堆栈中的OVERLAPPED结构的指针。如果WriteFileEx在50毫秒内没有完成,则挂起的I / O将引用一个不存在的OVERLAPPED结构,并且(希望)会有一个访问冲突(或者更糟糕的是,应用程序中某处的静默损坏的堆栈数据)。 / p>

处理这些生命周期问题的规范方法(如果性能不是一个大问题),是使用包含OVERLAPPED结构的自定义结构和一些用于读取/写入数据的存储。在发布写入时分配结构,并从I / O完成例程中释放结构。将包含的OVERLAPPED结构的地址传递给WriteFileEx,并使用例如offsetof从完成例程中的OVERLAPPED地址获取自定义结构的地址。

另请注意,WriteFileEx实际上并未使用hEvent成员IIRC。


编辑:添加了代码示例,请注意:

  1. 我实际上并没有尝试编译代码,代码可能存在拼写错误或其他问题。
  2. 这不是发送数据的最有效方式(为发送的每个字节分配/解除分配内存块)。不过,它应该很容易改进。
  3.     #include <stddef.h>
        #include <assert.h>
        #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\n", 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 :(得分:0)

    result = write_port(outPortHandle, 128);
    result = write_port(outPortHandle, 131);

lpBuf参数必须是指向缓冲区的指针,而不是常量。

e.g。

char buffer;
buffer = 128;
result = write_port(outPortHandle, &buffer);
buffer = 131;
result = write_port(outPortHandle, &buffer);

你真正想要做的是传递缓冲区长度。

e.g。

    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 )) {
   ...