Thursday, November 15, 2007

Parsing take #1

Erlang is not famous for its string representation, strings are just lists of characters and as such take up considerable memory, on 32 bit machines typically 64bit per character 32 for the characters value and 32 for the pointer to the next character (on 64bit machines that is doubled to 128 bit per character), ouch (for more details of Erlangs built in types see this).
Fortunately Erlang comes with a very compact binary type, which I will use. Last time we saw that the output was of the form "..." which indicates strings, Erlang uses a notation of <<...>> to indicate binaries.
Now to get the Port to send binaries to us instead of strings you simply pass, [binary] to sl:start/1 like this sl:start([binary])..

This is normal Erlang behavior for ports and looking at the sl you will see that the start/1 simply calls open_port like this:


start(OpenOpts) ->
%%...
open_port({spawn, "sl_drv"}, OpenOpts).

Now running the previous code with this change results in:

<<"$GPGSV,3,1,12,20,89,000,00,17,45,000,27,11,45,000,33,23,43,000,00*7E\r\n">>
...


So even after specifying that you want to receive binaries, the undocumented mode=line option still breaks messages on linefeed boundaries, nice.

GPS receivers typically uses NMEA messages when reporting position and other information. I use this as my NMEA documentation.

I will start with parsing the GPGSA message and modifies my loop/1 into this:



loop(Port) ->
receive
{Port, {data, Data}} ->
case Data of
<<"$GPGSA,", Rest/binary>> ->
getparams(Rest);
_ ->
io:format("~p~n", [Data])
end,
loop(Port);
stop ->
exit(normal);
{'EXIT', Port, Reason} ->
exit({port_terminated, Reason})
end.



The data received from the Port is matched against the pattern <<"$GPGSA,", Rest/binary>> for these messages so I simply call getParams with the rest of the parameters in this case. Next time I will look at getParams and a record representation of the received data.

No comments: