Декодирование порядковых (?) Данных с датчика - PullRequest
0 голосов
/ 30 мая 2019

Я не уверен, что даже понимаю, что здесь происходит с этими данными, но я пытаюсь воспроизвести такие функции, как здесь , здесь или здесь для декодирования данных, которые я получаю через UART, от моего датчика Plantower PMS5003 (см. таблица данных ) в Elixir.

Он ограничен 0x42 и 0x4d и начинается следующим образом:

iex(mygadget@nerves.local)4> {:ok, data} = Circuits.UART.read(pid, 60000)
{:ok,
 <<66, 77, 0, 28, 0, 23, 0, 32, 0, 32, 0, 22, 0, 31, 0, 32, 17, 124, 4, 211, 0,
   171, 0, 8, 0, 0, 0, 0, 151, 0, 4, 5, 66, 77, 0, 28, 0, 23, 0, 32, 0, 32, 0,
   22, 0, 31, 0, 32, ...>>}

Я тогда base16 кодирую это:

iex(mygadget@nerves.local)5> Base.encode16(data)
"424D001C0017002000200016001F0020117C04D300AB00080000000097000405424D001C0017002000200016001F0020117C04D300AB00080000000097000405424D001C0017001F001F0016001E001F115804BE0098000800
000000970003B5424D001C0018002000200016001F002011BB04D8009F0008000000009700043E424D001C0016001F001F0015001E001F11DC04C3009300080000000097000437424D001C0017001E001E0015001D001E11E20
4C300850008000000009700042C424D001C0016001E001E0015001D001E117304B70087000600000000970003B0424D001C0016001D001D0015001D001D111F049B007B00060000000097000331424D001C0017001E001E0016
001E001E10F5048D007D00060000000097000400424D001C0017001E001E0016001E001E10FB0496008B0004000000009700041B424D001C0016001E001E0015001E001E10B304810089000400000000970003BA424D001C001
5001C001C0014001C001C104A045E008000020000000097000319424D001C0016001C001

И разделить на 424D

decoded |> String.split("424D")
["", "001C0017002000200016001F0020117C04D300AB00080000000097000405",
 "001C0017002000200016001F0020117C04D300AB00080000000097000405",
 "001C0017001F001F0016001E001F115804BE0098000800000000970003B5",
 "001C0018002000200016001F002011BB04D8009F0008000000009700043E",

Затем разбить его на куски по 2

iex(mygadget@nerves.local)10> "001C0017002000200016001F0020117C04D300AB00080000000097000405" |> String.codepoints |> Enum.chunk(2) |> Enum.map(&Enum.join/1)
["00", "1C", "00", "17", "00", "20", "00", "20", "00", "16", "00", "1F", "00",
 "20", "11", "7C", "04", "D3", "00", "AB", "00", "08", "00", "00", "00", "00",
 "97", "00", "04", "05"]

Я совершенно не знаю, куда идти отсюда. Я нашел это обсуждение о том, как сделать это в Java , но я не совсем понимаю, что там происходит с кадровыми буферами.

Любое понимание приветствуется

РЕДАКТИРОВАТЬ: теги

1 Ответ

3 голосов
/ 30 мая 2019

Итак, erlang / elixir - отличные языки для деконструкции необработанных пакетов в двоичном формате - это то, что возвращает Circuits.UART.read().Вы деконструируете двоичный файл <<...>> с совпадением двоичного шаблона , и ваша таблица данных содержит спецификацию для шаблона, который вы будете использовать.Нет необходимости в кодировании base16, делении на 424D или разбиении на куски 2:

defmodule My do

  def match(<<     
                66, 77, 
                _fr_len::big-integer-size(16),
                data1::big-integer-size(16),
                data2::big-integer-size(16),
                data3::big-integer-size(16),
                data4::big-integer-size(16),
                data5::big-integer-size(16),
                data6::big-integer-size(16),
                data7::big-integer-size(16),
                data8::big-integer-size(16),
                data9::big-integer-size(16),
                data10::big-integer-size(16),
                data11::big-integer-size(16),
                data12::big-integer-size(16),
                _reserved::big-integer-size(16),
                _check_code::big-integer-size(16),
                rest::binary
           >>) do

    IO.puts "pm 1.0 cf: #{data1} ug/m^3"
    IO.puts "pm 2.5 atmospheric: #{data5} ug/m^3"
    match(rest)
  end

  def match(partial_frame) do
    IO.puts "partial_frame:"
    IO.inspect partial_frame 
  end

  def go() do
    match(<<66, 77, 0, 28, 0, 23, 0, 32, 0, 32, 0, 22, 0, 31, 0, 32,  
           17, 124, 4, 211, 0, 171, 0, 8, 0, 0, 0, 0, 151, 0, 4, 5,  
           66, 77, 0, 28, 0, 23, 0, 32, 0, 32, 0, 22, 0, 31, 0, 32>>)

    :ok
  end


end

В iex:

iex(1)> My.go
pm 1.0 cf: 23 ug/m^3
pm 2.5 atmospheric: 31 ug/m^3
partial_frame:
<<66, 77, 0, 28, 0, 23, 0, 32, 0, 32, 0, 22, 0, 31, 0, 32>>
:ok

Вы можете написать 0x42, 0x4D внутри шаблоначтобы точно соответствовать спецификации таблицы данных, однако я думаю, что более ясно использовать десятичные эквиваленты, 66, 77, потому что elixir не выводит шестнадцатеричные коды при выводе двоичного файла, а elixir выводит десятичные дроби - как это видно в вашем data(Или, иногда, elixir выводит строку в двойных кавычках для двоичного файла, что действительно сбивает с толку и глупо.) Имея в шаблоне 66, 77, вы можете легко посмотреть на данные и увидеть, где они совпадают.

Примечаниечто последний сегмент rest::binary подобен записи .* в регулярном выражении.

Прежде чем доверять любым данным, назначенным переменным, вам, вероятно, следует проверить, что длина кадра равна 28, и проверить код проверки.К сожалению, я не могу понять, что представляет код проверки.Я получаю 1029 за код проверки.

========= *

Можете ли вы опубликовать пример того, как вы ожидаете, что данные будут выглядеть?

Шестнадцатеричная строка, такая как "1C", эквивалентна десятичной 28.Вы можете получить все десятичные эквиваленты, как это:

data = [ "00", "1C", "00", "17", "00", "20", "00", "20", "00", "16", "00",   
        "1F", "00", "20", "11", "7C", "04", "D3", "00", "AB", "00", "08",  
        "00", "00", "00", "00", "97", "00", "04", "05"]

for str <- data do
  Integer.parse(str, 16)
end
|> IO.inspect
|> Enum.map(fn {a, _} -> a end)

Integer.parse () возвращает кортеж, где первый элемент является целым числом, а второй элемент является "остатком"строки ", то есть все, что не может быть интерпретировано как целое число.

Вывод:

[
  {0, ""},
  {28, ""},
  {0, ""},
  {23, ""},
  {0, ""},
  {32, ""},
  {0, ""},
  {32, ""},
  {0, ""},
  {22, ""},
  {0, ""},
  {31, ""},
  {0, ""},
  {32, ""},
  {17, ""},
  {124, ""},
  {4, ""},
  {211, ""},
  {0, ""},
  {171, ""},
  {0, ""},
  {8, ""},
  {0, ""},
  {0, ""},
  {0, ""},
  {0, ""},
  {151, ""},
  {0, ""},
  {4, ""},
  {5, ""}
]
[0, 28, 0, 23, 0, 32, 0, 32, 0, 22, 0, 31, 0, 32, 17, 124,  
 4, 211, 0, 171, 0, 8, 0, 0, 0, 0, 151, 0, 4, 5]

Это то, что ваши данные должны выглядеть?

Это похоже на код java:

...forEach[b | bts.append(Integer.toHexString(b)]

немного изменяет оператор битового оператора java : |, что не имеет смысла для меня в этом фрагменте кода,Но в эликсире вы бы сделали это с Bitwise.bor (a, b) .Я действительно думаю, что код Java должен выглядеть следующим образом:

...forEach(b -> bts.append(Integer.toHexString(b))

Другими словами, forEach () принимает лямбду в качестве аргумента.Черт возьми, это так любопытно, что я собираюсь спросить парня, что это значит.

Редактировать:

Хорошо, парень ответил мне, и это не Java--это синтаксис лямбды, хотя - на некотором языке DSL.

...