[erlang-questions] decoding nmea messages

Hynek Vychodil <>
Fri Aug 13 00:00:51 CEST 2010


Basic message parsing is very simple

-module(nmea0183).

-export([parse_msg/1, split/1]).

split(Bin) ->
  [ X || <<$$,_/binary>> = X <- binary:split(Bin, <<"\r\n">>)].

parse_msg(Bin) ->
  [<<$$, Msg/binary>>, Crc] = binary:split(Bin, <<$*>>),
  IsCrc = checkcrc(Msg, Crc),
  <<Sender:2/binary, Type:3/binary, Rest/binary>> = Msg,
  Values = case Rest of
    <<>> -> [];
    _ -> tl(binary:split(Rest, <<$,>>, [global]))
  end,
  {Sender, Type, Values, IsCrc}.

checkcrc(_, <<>>) -> nocrc;
checkcrc(Msg, <<H,L>>) ->
  Crc = hdv(H)*16 + hdv(L),
  Crc = crc(Msg),
  crc.

crc(Msg) ->
  lists:foldl(fun(X, A) -> X bxor A end, 0, binary_to_list(Msg)).

hdv(X) when X >= $0, X =< $9 -> X band 15;
hdv(X) -> 9 + (X band 15).

43> nmea0183:parse_msg(<<"$GPGSV,2,1,08,11,74,137,45,20,58,248,43,07,27,309,00,14,23,044,36*7A">>).
{<<"GP">>,<<"GSV">>,
 [<<"2">>,<<"1">>,<<"08">>,<<"11">>,<<"74">>,<<"137">>,
  <<"45">>,<<"20">>,<<"58">>,<<"248">>,<<"43">>,<<"07">>,
  <<"27">>,<<"309">>,<<"00">>,<<"14">>,<<"23">>,<<"044">>,
  <<"36">>],
 crc}
44> nmea0183:parse_msg(<<"$GPGSA,A,3,20,11,25,01,14,31,,,,,,,2.6,1.7,1.9*3B">>).
{<<"GP">>,<<"GSA">>,
 [<<"A">>,<<"3">>,<<"20">>,<<"11">>,<<"25">>,<<"01">>,
  <<"14">>,<<"31">>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<"2.6">>,
  <<"1.7">>,<<"1.9">>],
 crc}
45> nmea0183:parse_msg(<<"$GPAAM,A,A,0.10,N,WPTNME*32">>)).
{<<"GP">>,<<"AAM">>,
 [<<"A">>,<<"A">>,<<"0.10">>,<<"N">>,<<"WPTNME">>],
 crc}

But if you want parse value of each field you have to do more work.

On Thu, Aug 12, 2010 at 4:19 PM, info <> wrote:
> Hi Richard,
> The fields don't contain commas but sometimes they are empty. Therefore the size of the messages is not a constant.
> And what about the syntax analysis if each field is considered as a binary ?
> Someone suggest to use regexp ...
> John
> On Aug 12, 2010, at 5:44 AM, info wrote:
>
>> Hi All,
>> According to your experience, what is the best method for decoding an NMEA 0183 message ? I mean:
>> - extract each field,
>> - detect those which are missing,
>> - check syntax
>
> You mean things like the example in the Wikipedia?
>
> $GPAAM,A,A,0.10,N,WPTNME*32
>
> Binary matching will let you
>  - check for $
>  - extract GP (talker)
>  - extract AAM (type)
>  - extract the rest (because you know how long the binary is)
>  - check for *
>  - extract the two hex digits
>  - check for "\r\n"
> As for "the rest", I haven't read the standard, so I don't know
> whether the fields can contain commas or not.  If not, you can
> break "the rest" up using binary:split/[2,3].  Where you go from
> there depends on what the kind of message at hand expects to find.
>



-- 
--Hynek (Pichi) Vychodil

Analyze your data in minutes. Share your insights instantly. Thrill
your boss.  Be a data hero!
Try GoodData now for free: www.gooddata.com


More information about the erlang-questions mailing list