无法使用SerialDevice.Windows 10 IoT中的ReadTimeout

本文关键字:IoT 中的 ReadTimeout Windows SerialDevice | 更新日期: 2023-09-27 18:09:20

我正在尝试在Raspberry Pi 2上实现Windows 10 IoT上的ModBus master。我使用外部USB到RS-232适配器,因为内部串行端口是为内核调试保留的。

串口正常。我的问题主要是关于读取时的超时。

下面是我的代码:
// Initialization
serialDevice.ReadTimeout = new TimeSpan(0, 0, 0, allowedTimeBetweenBytes);
serialDataReader.InputStreamOptions = InputStreamOptions.Partial;
// Reading
uint bytesRead = await serialDataReader.LoadAsync(MaxBufferSize); // 256
// Now use ReadBytes to get actual bytes

在串行端口RX输入处没有可用的字节,我期望LoadAsync方法在等待后返回0。不幸的是,它永远不会返回。(好吧,它确实在收到256字节后返回,但这不是我想要的)

由于ModBus密集使用超时,我不确定如何实现它。我甚至不确定我是否能做到……

是否有人已经在Windows 10物联网串口上使用超时?

无法使用SerialDevice.Windows 10 IoT中的ReadTimeout

是啊,我也不能让这个工作。我不确定ReadTimeout实际上是由SerialDevice类内部使用的。但是我最终通过将超时复制到CancellationTokenSource来获得一些工作。

您可以在下面的示例中看到它的使用,我为旧的串行梅特勒托莱多PS 60运输秤编写了一个示例,其中deviceSerialDevice的实例。至少在我的情况下似乎有效。

using (var writer = new DataWriter(device.OutputStream))
{
    writer.WriteString("W'r'n");
    using (var cts = new CancellationTokenSource(device.WriteTimeout))
    {
        await writer.StoreAsync().AsTask(cts.Token);
    }
    writer.DetachStream();
}
using (var reader = new DataReader(device.InputStream))
{
    using (var cts = new CancellationTokenSource(device.ReadTimeout))
    {
        var read = await reader.LoadAsync(12).AsTask(cts.Token);
        if (read >= 12)
        {
            var data = reader.ReadString(12);
            reader.DetachStream();
            return ExtractWeightChangedEventArgs(data);
        }
    }
}

我花了几个星期的时间来解决这个问题,并进行了测试。

  1. ReadTimeout对读调用的第一个字节没有影响。Read调用总是永远等待第一个字节

  2. ReadTimeout = 0ms导致读调用永远等待多字节读调用请求的所有后续字节。

  3. ReadTimeout =大于0ms导致读调用在等待第一个字节之后的任何后续字节时超时。

  4. ReadTimeout是一个TimeSpan,这意味着调用者可以指定一个分辨率大于毫秒的超时值。然而,底层的Windows调用只有毫秒级的分辨率。

  5. 我使用带有超时值的CancellationTokenSource的实验似乎导致SerialDevice对象在超时取消后变得不稳定。

我最终创建了一个派生自SerialDevice的类。派生类启动了一个后台任务,该任务简单地向基本SerialDevice类发出读请求,并将返回的数据存储在队列中。我将ReadTimeout设置为1ms,这样我的后台任务就可以发出大的读请求,但是在数据可用时接收数据并将其存储到队列中,而不必等待整个请求。

我创建了一个循环队列来提高内存效率。net没有提供这样的标准。在处理高波特率时,将读取的数据复制到队列将需要非常高效。意思是复制数据块。不要一个字节一个字节地乱搞数据

派生类提供了从队列中返回数据的备选读方法,如果队列中没有数据,则可以立即返回。

由于SerialDevice读取发生在后台任务中,因此永远不需要取消读取请求并冒破坏SerialDevice稳定的风险。只有当后台任务因为派生类正在关闭SerialDevice并处理而被信号终止时,读取才有CancellationToken。