Добавить обработчик событий последовательных данных в считыватель последовательных портов f # - PullRequest
0 голосов
/ 13 ноября 2018

У меня есть простые инструкции чтения и записи в f # для связи между последовательными портами:

        async {
            do! port.AsyncWriteLineAsByte messange            
            let! response = port.AsyncReadLineAsByte() 

            return response
        }

Где ответ - байт [], а метод прост:

    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())

Isговорит, что ожидает Uint и получить bool

1 Ответ

0 голосов
/ 13 ноября 2018

Я не эксперт в том, как работают последовательные порты, но вы можете ждать события внутри 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 может инициироваться одновременно, пока вы обрабатываете полученные данные в теле цикла - и затемвы пропустите событие.Я не уверен, как работают последовательные порты и может ли это на самом деле произойти, но это может привести к проблемам.

Для решения этой проблемы вы можете использовать BlockingQueueAgent тип из F # Async.Дополнительно.Это позволит вам реализовать очередь уведомлений - поэтому обработчик 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 обработчик событий до записи любогоданные в порт.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...