我在f#中有简单的读写指令以在串行端口之间进行通信:
async {
do! port.AsyncWriteLineAsByte messange
let! response = port.AsyncReadLineAsByte()
return response
}
其中响应是byte [],方法很简单:
member this.AsyncReadLineAsByte() : Async<byte[]> =
async {
let buffer_ref = ref (Array.zeroCreate<byte> this.ReadBufferSize)
let buffer = !buffer_ref
let! read_bytes = this.BaseStream.AsyncRead(buffer, 0, this.ReadBufferSize)
return buffer
}
它运行良好,可以发送和接收消息,但所有这些都只有一个。 阅读响应应该是某种事件。我是F#的新手,但是我尝试过类似的操作:
async {
let data_recived_event = port.AsyncReadLineAsByte()
do! port.AsyncWriteLineAsByte messange
port.DataReceived.AddHandler(data_recived_event) // it says SerialDataReciveHandler is what he expects
let! response = ???
return response
}
但是幸运的是,文档却是,对于f#,它仅指定原型和方法构造,而并非实际用途。我需要一个事件和一种返回该值的方法,有办法吗?
编辑:
我能够添加事件,因为串行端口名称空间具有DataReceived.AddHandler事件订阅。
现在看起来:
async {
let data_recived() =
async{
let! buffer = port.AsyncReadLineAsByte()
printfn "Response from event %A" buffer
// return buffer
} |> fun response -> Async.RunSynchronously(response)
port.DataReceived.AddHandler(fun _ _ -> data_recived())
do! port.AsyncWriteLineAsByte messange
let! response = port.AsyncReadLineAsByte()
return response
}
而且有效,问题仍然是如何从事件中返回这样的值,如果我执行以下操作:
let data_recived() =
async{
let! buffer = port.AsyncReadLineAsByte()
printfn "Response from event %A" buffer
return buffer
} |> fun response -> Async.RunSynchronously(response)
port.DataReceived.AddHandler(fun _ _ -> response = data_recived())
是说它期望uint并得到bool
答案 0 :(得分:2)
我不是串行端口如何工作的专家,但是您可以使用async
操作在Async.AwaitEvent
工作流程中等待事件。因此,您可以编写如下内容:
let writeAndRead () = async {
let port = new SerialPort("COM1")
port.Write("TEST")
let mutable finished = false
while not finished do
let! e = port.DataReceived |> Async.AwaitEvent
let data = port.ReadExisting()
printfn "GOT: %A" data
finished <- data.Contains("EOF") }
这里唯一需要注意的是,DataReceived
事件可能在您正在循环主体中处理接收到的数据时并发触发-然后您将错过该事件。我不确定串行端口如何工作以及这种情况是否会真正发生,但这可能会导致问题。
要解决此问题,您可以使用F#Async Extras中的BlockingQueueAgent
type。这将使您实现通知队列-因此DataReceived
处理程序会将通知添加到队列,然后在循环中从队列中读取它们。我还没有实际测试过,但是我认为这样应该可以工作:
let writeAndRead () = async {
let queue = BlockingQueueAgent<_>(Int32.MaxValue)
let port = new SerialPort("COM1")
port.DataReceived.Add(fun e -> queue.Add(e))
port.Write("TEST")
let mutable finished = false
while not finished do
let! e = queue.AsyncGet()
let data = port.ReadExisting()
finished <- data.Contains("EOF") }
编辑:在将任何数据写入端口之前,移动了queue
事件处理程序设置。