c中windows异步串口通信

发布于 2024-07-23 13:02:37 字数 1945 浏览 4 评论 0原文

当我尝试运行 ac 文件来对串行端口进行一些基本写入时,出现错误。 我尝试异步运行它,因为写入有时需要很长时间才能传输。 我的原始版本让它与 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
   }
}

抱歉,这不是完整的代码。 我也使用了字节数组,而不是常量。 但是系统(“暂停”)导致了我的调试断言失败错误,并且在仔细查看我的代码后,当 WriteFileEx() 成功时,它从未在重叠结构中的事件上设置警报/超时,所以回调函数永远不会被调用。 不过我解决了这些问题。

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

I am getting an error when I try to run a c file which does some basic writes to a serial port. I am trying to run it asynchronously because the writes sometimes take a long time to transfer. My original version had it running synchronously with WriteFile() commands which worked fine. I am new to using OVERLAPPED and would appreciate and input concerning it.

The error I am getting is:

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

when the second write function is called.

In main:

    {
        //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
   }
}

That was not the full code, sorry. I was using an array of BYTEs as well, not constants. But system("pause")'s were causing my debug assertion failed errors, and after carefully looking through my code, when the WriteFileEx() was successful, it was never setting an alert/timeout on the event in the overlapped structure, so the callback function would never get called. I fixed these problems though.

I just need help with the handling/accessing a single BYTE in a structure which is allocated when a ReadFileEx() function is called (for storing the BYTE that is read so it can be handled). I need to know how to access that BYTE storage using an offset and make the overlapped structure null. Would making the overlapped structure null be as simple as setting the handle in it to INVALID_HANDLE_VALUE?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萌逼全场 2024-07-30 13:02:37

我认为你有几个问题:


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

结果 = write_port(outPortHandle, 128);

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

int write_port(HANDLE hComm,BYTE* lpBuf) {

上面的语句不匹配。 稍后,您可以通过获取 BYTE* -> 的地址将指向 lpBuf 指针的指针传递给 WriteFileEx 函数。 “&lpBuf”。 这不会产生您认为会发生的结果。


即使您修复了此问题,每当写入成功排队但无法在 50 毫秒超时内完成时,您仍然会遇到潜在的生命周期问题。

使用重叠 I/O 时,需要确保读/写缓冲区和重叠结构保持有效,直到 I/O 完成、取消或关联设备关闭。 在上面的代码中,您使用了一个指向 OVERLAPPED 结构的指针,该结构位于对 WriteFileEx 的调用中的堆栈上。 如果 WriteFileEx 未在 50 毫秒内完成,待处理的 I/O 将引用不存在的 OVERLAPPED 结构,并且您将(希望)发生访问冲突(或更糟糕的是,应用程序中某处的堆栈数据被悄悄损坏)。

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

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


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

  1. 我实际上没有尝试编译代码,代码可能存在拼写错误或其他问题。
  2. 这不是发送数据的最有效方式(为发送的每个字节分配/释放内存块)。 不过,改进应该很容易。
    #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
       }
    }

I think you have a couple of issues:


You are passing an integer as a pointer (your compiler should warn against this or preferably refuse to compile the code):

result = write_port(outPortHandle, 128);

Compare this to the definition of write_port:

int write_port(HANDLE hComm,BYTE* lpBuf) {

The above statements doesn't match. Later on you then pass a pointer to the lpBuf pointer to the WriteFileEx function by taking the address of the BYTE* -> "&lpBuf". This will not result in what you think it will do.


Even if you fix this, you will still have potential lifetime issues whenever the write is successfully queued but won't complete within the 50 ms timeout.

When using overlapped I/O, you need to make sure that the read/write buffer and the overlapped structure remain valid until the I/O is completed, cancelled or the associated device is closed. In your code above you use a pointer to an OVERLAPPED struct that lives on the stack in your call to WriteFileEx. If WriteFileEx does not complete within 50 ms, the pending I/O will have a reference to a non-existing OVERLAPPED struct and you will (hopefully) have an access violation (or worse, silently corrupted stack data somewhere in your app).

The canonical way of handling these lifetime issues (if performance is not a big issue), is to use a custom struct that includes an OVERLAPPED struct and some storage for the data to be read/written. Allocate the struct when posting the write and deallocate the struct from the I/O completion routine. Pass the address of the included OVERLAPPED struct to WriteFileEx, and use e.g. offsetof to get the address to the custom struct from the OVERLAPPED address in the completion routine.

Also note that WriteFileEx does not actually use the hEvent member, IIRC.


EDIT: Added code sample, please note:

  1. I haven't actually tried to compile the code, there might be typos or other problems with the code.
  2. It's not the most efficient way of sending data (allocating/deallocating a memory block for each byte that is sent). It should be easy to improve, though.
    #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
       }
    }
酒解孤独 2024-07-30 13:02:37
 结果 = write_port(outPortHandle, 128); 
      结果 = write_port(outPortHandle, 131); 
  

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

例如,

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

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

例如

    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 )) {
   ...
    result = write_port(outPortHandle, 128);
    result = write_port(outPortHandle, 131);

The lpBuf argument have to be pointers to buffers, not constants.

e.g.

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

What you really want to do is also pass a buffer length.

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 )) {
   ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文