[erlang-questions] Binaries

Bob Cowdery bob@REDACTED
Wed Jun 20 12:07:40 CEST 2018


I seem to have arrived at something that works. This is only a hack for 
testing. I picked hexstr_to_bin up to do the conversion. I had trouble 
with some of the other methods on offer but that's probably me.

The target docs I have say nothing about flow control so I set it to all 
available options but gen_serial:bsend/2 was more often than not hanging 
although the command was executed. I have used gen_serial:asend/2 which 
seems to work reliably so don't know what the issue is. I'm sure the 
code can be reduced quite a lot.

hexstr_to_bin(S) ->
   hexstr_to_bin(S, []).
hexstr_to_bin([], Acc) ->
   list_to_binary(lists:reverse(Acc));
hexstr_to_bin([X,Y|T], Acc) ->
   {ok, [V], []} = io_lib:fread("~16u", [X,Y]),
   hexstr_to_bin(T, [V | Acc]);
hexstr_to_bin([X|T], Acc) ->
   {ok, [V], []} = io_lib:fread("~16u", lists:flatten([X,"0"])),
hexstr_to_bin(T, [V | Acc]).

I ended up with this code:
open(Device) ->
     case gen_serial:open(Device, [{baud, 9600},{stop_bits, 
2},{flow_control, none}]) of
         {ok, Port} ->
             Port;
         {error, Reason} ->
             io:format("Error opening serial port ~w~n", Reason),
             {error, Reason}
     end.

set_freq(Port, Freq) ->
     % The command is 4 hex freq bytes followed by 0x01 (set_freq command)
     SFreq = integer_to_list(floor(Freq*100000)),
     io:format("~w~n", [SFreq]),
     SPadded = string:right(SFreq, 8, $0),
     io:format("~w~n", [SPadded]),
     BinFreq = hex:hexstr_to_bin(SPadded),
     BinCmd = <<16#01>>,
     Bin = << BinFreq/binary, BinCmd/binary >>,
     io:format("~w~n", [Bin]),
     gen_serial:asend(Port, Bin),
     io:format("Done send~n"),
     gen_serial:recv(Port, 5, 2000),
     io:format("Done response~n").

C:\Users\User>erl
Running .erlang
Eshell V9.3  (abort with ^G)
1> Port = cat_client:open(3).
{gen_serial,<0.59.0>,#Port<0.519>}
2> cat_client:set_freq(Port, 3.8).
[51,56,48,48,48,48]
[48,48,51,56,48,48,48,48]
<<0,56,0,0,1>>
Done send
Done response
ok


On 6/20/2018 2:21 AM, zxq9 wrote:
> On 2018年6月19日 火曜日 16:32:49 Bob Cowdery wrote:
>> If I have a number, say 1450000001 and I want to represent that as a
>> binary in the form
>>
>>    <<16#14,16#50,16#00,16#00,16#01>> what's the best way.
>>
>> I'm not sure what list_to_binary(integer_to_list(1450000001)) which
>> prints as <<"1450000001">> produces but I guess its 10 bytes not 5.
> Binary syntax can be a bit of a wonderland at first.
>
> The form you present above works just fine. Keep in mind that it yields the following:
>
>    1> <<16#14,16#50,16#00,16#00,16#01>>.
>    <<20,80,0,0,1>>
>
> If we want to encode it using your original decimal representation (or as an integer programatically generated as a variable), and pack it into the same 40-bit space (5 8-bit bytes):
>
>    2> <<1450000001:40>>.
>    <<0,86,109,62,129>>
>
> What, what? These aren't the same!
>
> There are two reasons:
>   - The hexadecimal modifier 16# means 10#14 =/= 16#14
>   - Your version splits this integer value up into decimal-determined fields
>
> It appears that you don't actually want to encode the number 1450000001, but rather want five 8-bit fields carrying the values 14, 50, 00, 00, and 01, in that order. Is this correct?
>
> If you're starting with an integer that is *actually* 1,450,000,001 and you want to break it up by its decimal value then you'll want to div/rem it down by 100s to break it into chunks and then encode each chunk:
>
>    1> Split = fun
>    1>   Chunk(0, Parts) -> Parts;
>    1>   Chunk(Z, Parts) -> Chunk(Z div 100, [Z rem 100 | Parts])
>    1> end.
>    #Fun<erl_eval.36.99386804>
>    2> Pack = fun
>    2>   Stuff([], Bin)      -> Bin;
>    2>   Stuff([H | T], Bin) -> Stuff(T, <<Bin/binary, H:8>>)
>    2> end.
>    #Fun<erl_eval.36.99386804>
>    3> N = 1450000001.
>    1450000001
>    4> Splitted = Split(N, []).
>    [14,50,0,0,1]
>    5> Packed = Pack(Splitted, <<>>).
>    <<14,50,0,0,1>>
>
> BUT THAT IS A LITTLE BIT RIDICULOUS.
>
> On your sensor side you should have this "number" as a byte array of some sort. Figure out what the field sizes are in bits or bytes and interpret it accordingly. That's a much more sane way to do business.
>
> -Craig
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions




More information about the erlang-questions mailing list