在Win32中等待串行传输完成

问题描述 投票:1回答:1

我似乎在等待完成串行数据传输时遇到了一些麻烦。

我对相关MSDN article的解释是EV_TXEMPTY事件是正确的信号,它表明:

EV_TXEMPTY - 发送输出缓冲区中的最后一个字符。

但是在我的测试中,只要数据已经提交到缓冲区并且在最终实际到达线路之前很久就会立即触发事件。请参阅下面的重复代码,其中周期始终为零。

我是否在实施中犯了错误,我误解了旗帜的用途,还是现代司机根本不支持这个功能?在后一种情况下是否存在可行的解决方法,比如某种形式的同步线路状态请求?

为了记录,测试是在Windows 10系统中使用FTDI USB-RS485和TTL-232R设备,在Windows 7系统上使用USB-SERIAL CH340接口,以及使用2005年份Windows的板载串行接口进行的。 XP机器。在FTDI情况下,嗅探USB总线只显示批量输出事务,并且没有明显的完成中断通知。

#include <stdio.h>
#include <windows.h>

static int fatal(void) {
    fprintf(stderr, "Error: I/O error\n");
    return 1;
}

int main(int argc, const char *argv[]) {
    static const char payload[] = "Hello, World!";
    // Use a suitably low bitrate to maximize the delay
    enum { BAUDRATE = 300 };
    // Ask for the port name on the command line
    if(argc != 2) {
        fprintf(stderr, "Syntax: %s {COMx}\n", argv[0]);
        return 1;
    }
    char path[MAX_PATH];
    snprintf(path, sizeof path, "\\\\.\\%s", argv[1]);
    // Open and configure the serial device
    HANDLE handle = CreateFileA(path, GENERIC_WRITE, 0, NULL,
        OPEN_EXISTING, 0, NULL);
    if(handle == INVALID_HANDLE_VALUE)
        return fatal();
    DCB dcb = {
        .DCBlength = sizeof dcb,
        .BaudRate = BAUDRATE,
        .fBinary = TRUE,
        .ByteSize = DATABITS_8,
        .Parity = NOPARITY,
        .StopBits = ONESTOPBIT
    };
    if(!SetCommState(handle, &dcb))
        return fatal();
    if(!SetCommMask(handle, EV_TXEMPTY))
        return fatal();
    // Fire off a write request
    DWORD written;
    unsigned int elapsed = GetTickCount();
    if(!WriteFile(handle, payload, sizeof payload, &written, NULL) ||
        written != sizeof payload)
        return fatal();
    // Wait for transmit completion and measure time elapsed
    DWORD event;
    if(!WaitCommEvent(handle, &event, NULL))
        return fatal();
    if(!(event & EV_TXEMPTY))
        return fatal();
    elapsed = GetTickCount() - elapsed;
    // Display the final result
    const unsigned int expected_time =
        (sizeof payload * 1000 /* ms */ * 10 /* bits/char */) / BAUDRATE;
    printf("Completed in %ums, expected %ums\n", elapsed, expected_time);
    return 0;
}

背景是,这是Modbus RTU协议测试套件的一部分,我试图在线路上的字符之间注入> 3.5个字符的空闲延迟,以验证设备响应。不可否认,嵌入式实时系统本来就更适合这项任务,但出于各种原因,我宁愿坚持使用Windows环境,同时尽可能地控制时序。

c winapi serial-port ftdi
1个回答
0
投票

根据@Hans Passant和@RbMm的评论,EV_TXEMPTY documentation中引用的输出缓冲区是一个中间缓冲区,事件表明数据已转发给驱动程序。没有定义等效通知事件,它包含完整链到最终设备缓冲区。

目前没有一般的解决方法是基于比特率的手动延迟,并且为要遍历的任何剩余缓冲层,字符间间隙,时钟偏差等添加了显着的最坏情况余量。

因此,我非常感谢更好的替代解决方案的答案。


尽管如此,对于我的具体应用,我已经实施了可行的解决方法。

目标硬件是带有FTDI RS485接口的半双工总线。该特定设备提供可选的本地回波模式,其中主动发送到总线的数据不会从接收中主动过滤。

因此,在每次传输之后,我能够等待预期的回声出现为往返确认。此外,这用于检测某些故障,例如短路总线。

© www.soinside.com 2019 - 2024. All rights reserved.