2015-05-12 3 views
3

Я использую knewter/erlang-serial с Elixir и попытаться прочитать JSON-строку (например, {"temperature":20.40,"humidity":30.10} поступающий с Arduino через последовательный вход после того, как принимает управляющий-сигнал:Читать последовательный ввод до управления символ указывает конец сообщения

defmodule MyApp.SerialInput do 
    require Logger 


    def start_link do 
    serial_pid = :serial.start [{:open, "/dev/cu.usbmodem1431"}, {:speed, 115200}] 

    control_signal = "1" 
    :timer.send_interval 5000, serial_pid, {:send, control_signal} 

    wait_for_new_values serial_pid 
    end 


    defp wait_for_new_values(serial_pid) do 
    receive do 
     {:data, jsonString} when is_binary(jsonString) -> 
     Logger.debug "received :data #{inspect jsonString}" 

    wait_for_new_values serial_pid 
    end 
end 

Моя проблема теперь в том, что я получаю последовательный ввод распались так (иногда она проходит через сразу):

[debug] received :data "{\"t" 
[debug] received :data "emperature\":19.00,\"humidity\":42.00}\r\n" 

[debug] received :data "{\"temperature\":19.60,\"humidity\":41" 
[debug] received :data ".00}\r\n" 

[debug] received :data "{\"temperature\":19.50,\"humidity\":40.90}\r\n" 

[debug] received :data "{\"temperature\":19.50,\"humi" 
[debug] received :data "dity\":40.90}\r\n" 

[debug] received :data "{\"temperat" 
[debug] received :data "ure\":19.50,\"humidity\":41.30}\r\n" 

есть ли способ сказать приемный блок не ждать до \r\n появляется в конце строки или фиксированное количество символов или что-то в этом роде? Если нет, то как лучше всего удерживать состояние за пределами wait_for_new_values, пока \r\n не появится?

ответ

5

Блок receive является довольно низким уровнем, поэтому он не сможет выполнить такую ​​специализированную вещь.

Состояние в Эликсире является явным и может быть реализовано посредством необязательного аргумента, аккумулятора (acc в этом случае). Вы можете позже передать накопленное значение в рекурсивный вызов и только распечатать его, когда он заканчивается "\r\n".

defp wait_for_new_values(serial_pid, acc \\ "") do 
    receive do 
    {:data, chunk} when is_binary(chunk) -> 
     acc = acc + chunk 
    end 

    if String.ends_with? acc, "\r\n" 
    Logger.debug "received :data #{inspect acc}" 
    acc = "" 
    end 

    wait_for_new_values serial_pid, acc 
end 
+0

Просто боковое оповещение для OP: используя этот алгоритм, вы можете получить более одной пары температурной влажности. Если вы хотите получить ровно одну запись, вы должны отсканировать буфер для «\ r \ n» с самого начала. –

+0

Хорошая точка, но кажется, что управляющий сигнал запускает одно чтение. Это может быть или не быть проблемой, в зависимости от реализации. –

+0

Кажется, это не проблема, моя маленькая малина Pi работает плавно со вчерашнего дня и собирает измерения каждые 30 секунд, как шарм. @MiroslavPrymek Arduino отправляет только пару значений, получая сигнал управления от моего первого процесса Elixir (': timer.send_interval 5000, serial_pid, {: send, control_signal}'), поэтому не должно быть больше чем одна пара за раз. – optikfluffel

Смежные вопросы