c# - 我可以使用 Reactive Extensions 来控制仪器测试周期的时间吗?

标签 c# system.reactive

<分区>

这是我要解决的问题...

我正在编写一个程序来控制一台测试设备。程序每秒通过串口轮询仪器,返回一串测试数据。

连接速度为 9600 波特,仪器一次仅发送约 100 个字符,因此性能不是问题。

要求之一是“循环”模式,其工作方式如下:

  1. 用户设置三个计时器间隔 - 预测试时间、测试时间和测试间时间 - 然后单击 UI 上的“开始”按钮。

  2. 程序命令仪器开始测试周期,并显示仪器接收到的数据,直到预测试时间结束。

  3. 程序然后显示并记录数据,直到测试时间到期。

  4. 然后程序会显示数据,直到测试时间结束。

  5. 重复步骤 2 - 4,直到用户点击 UI 上的“停止”按钮。

过去,我曾为此类问题编写过简单的状态机。但是对于这个项目,(在 SO Rx 专家的帮助下),我已经能够使用 Rx 来解析串行数据,并且对生成的代码非常满意。

我的直觉告诉我,这个问题也可以由 Rx 很好地处理,但完全不清楚如何进行。

那么,我的直觉是否正确,或者您会建议采用不同的方法吗?

如果 Rx 很合适,有人可以提供一些快速而粗略的示例代码来演示解决方案吗?

根据 Enigmativity 编辑...:

这是读取串行数据的代码。简而言之,它将串行数据流转换为单独的数据包字符串,例如“A0”、“C00004”、“H0501100”等。这些被传递给 ProcessPacket 方法,该方法将数据包解释为仪器状态、压力等。

    /// <summary>
    /// Create a Reactive Extensions subscription to the selected serial port
    /// </summary>
    private IDisposable SetupSerialDataSubscription()
    {
        // Create Observable stream of chars from serial port's DataRecieved event
        var serialData = Observable
                .FromEventPattern<SerialDataReceivedEventArgs>(_serialPort, "DataReceived")

                // Collapse groups of chars into stream of individual chars
                .SelectMany(_ =>
                {
                    int bytesToRead = _serialPort.BytesToRead;
                    byte[] bytes = new byte[bytesToRead];
                    int nbrBytesRead = _serialPort.Read(bytes, 0, bytesToRead);

                    // Empty array if no bytes were actually read
                    if (nbrBytesRead == 0)
                        return new char[0];

                    var chars = Encoding.ASCII.GetChars(bytes);

                    return chars;
                })

                // Strip out null chars, which can cause trouble elsewhere (e.g. Console.WriteLine)
               .SkipWhile(c => c == '\0');

        // Emits packets, one string per packet, e.g. "A0", "C00004", "H0501100", etc
        var packets = serialData
            .Scan(string.Empty, (prev, cur) => char.IsLetter(cur) ? cur.ToString() : prev + cur)
            .Where(IsCompletePacket);

        // Process each packet, on the UI thread
        var packetsSubscription = packets
            .ObserveOn(this)
            .Subscribe(packet => ProcessPacket(packet) );

        return packetsSubscription;
    }

最佳答案

你可以做到这一点。使用辅助方法发出无限的 IEnumerable,它提供记录信号(真/假)和时间跨度:

public IEnumerable<Tuple<TimeSpan, bool>> GetTestPeriods()
{
    TimeSpan preTestTime = TimeSpan.FromSeconds(5);
    TimeSpan testTime = TimeSpan.FromSeconds(3);
    TimeSpan interTestTime = TimeSpan.FromSeconds(2);

    yield return Tuple.Create(preTestTime, false);
    while(true)
    {
        yield return Tuple.Create(testTime, true);
        yield return Tuple.Create(interTestTime, false);
    }
}

这可用于创建在适当时间输出记录信号的循环流:

// cycle outputs true at start of recording period
// false at start of a display period
var cycle = GetTestPeriods()
    .Select(s => Observable.Return(s.Item2)
        .Concat(Observable.Empty<bool>().Delay(s.Item1)))
    .Concat();

现在我们可以制作一些随机数据:

// make some random data
var random = new Random();
var dummyData = Observable.Interval(TimeSpan.FromSeconds(1))
                          .Select(_ => random.Next(10));

设置一个发出停止信号的主题(您可以使用 FromEventPattern Hook 按钮点击此处):

var stop = new Subject<Unit>();

然后将数据与记录信号结合起来,直到发出停止信号。这会将每个数据点与一个 bool 值配对,指示它是要显示还是记录:

var output = cycle.CombineLatest(dummyData, (c,d) => Tuple.Create(c,d))
    .TakeUntil(stop);

您可以使用 Where 过滤器发布和订阅此流,以获取要记录的数据和要显示的数据。这是一个为流添加时间戳并将数据转储出来的测试:

// timestamp data and "record" or "display" it.
output.Timestamp()
    .Subscribe(x => {
        if(x.Value.Item1)
            Console.WriteLine(x.Timestamp + ": Recording " + x.Value.Item2);
        else
            Console.WriteLine(x.Timestamp + ": Displaying " + x.Value.Item2);
    },
    () => Console.WriteLine("Stopped")); 

最后是一些发出停止信号的代码:

Console.ReadLine();
stop.OnNext(Unit.Default);

关于c# - 我可以使用 Reactive Extensions 来控制仪器测试周期的时间吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26854373/

相关文章:

c# - 发送给最终用户的报告的文档布局

c# observable interval 跳过滴答

c# - IDisposable 对象的可观察 : How to dispose previous value onNext and onComplete?

c# - 如何在 IntelliSense 中对 Visual Studio 中的函数进行注释?

c# - Windows Phone 7 的 Protocol Buffer 网络

c# - .Net RX : tracking progress of parallel execution

c# - 为什么这个 Observable 会阻塞 WPF GUI 线程 (C#)?

c# - Action<Action> 是什么意思?

c# - 从 Controller 运行种子方法

c# - C++ dll 和 C# 调用