Binaries

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Binaries

Bob Cowdery-4
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.

BobC

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

Pierre Fenoll-2
The integer-unit bit syntax should help you.

On Tue, 19 Jun 2018 at 17:33, Bob Cowdery <[hidden email]> 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.

BobC

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

Hugo Mills-2
In reply to this post by Bob Cowdery-4
On Tue, Jun 19, 2018 at 04:32:49PM +0100, 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.

   This is basically just binary coded decimal, isn't it?

   You should be able to do this with a binary comprehension:

1> << <<(C-$0):4>> || C <- "12345678">>.
<<18,52,86,120>>

   Hugo.

--
Hugo Mills             | Great oxymorons of the world, no. 7:
hugo@... carfax.org.uk | The Simple Truth
http://carfax.org.uk/  |
PGP: E2AB1DE4          |

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

signature.asc (853 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

Sverker Eriksson-4
In reply to this post by Bob Cowdery-4
If you mean 16#1450000001, then

<<16#1450000001:40/big>>

will give you a 5 byte (40 bits) big endian format

<<16#14,16#50,16#00,16#00,16#01>>


If you mean 1450000001 as a decimal integer, then my guess is you do not
actually want that.


integer_to_list produces ASCII characters.


/Sverker

On tis, 2018-06-19 at 16:32 +0100, 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.
>
> BobC
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

Bob Cowdery-4
In reply to this post by Bob Cowdery-4
Thanks for all the suggestions. Still a little confused. The number is
an integer, actually a frequency in Hz plus a command byte at the end
which is being sent over a serial connection in hex format using
gen_serial.

This command works: gen_serial:bsend(P,
<<16#14,16#50,16#00,16#00,16#01>>). where P is the open Port.

However, when I use any of the methods to create a hex version they all
end up with <<20,80,0,0,1>> which to my mind is the decimal equiv of above.

If I fire that I get:

5> gen_serial:bsend(P,<<20,80,0,0,1>>).
** exception error: bad argument
      in function  port_command/2
         called as port_command(#Port<0.470>,[<<"d">>|<<20,80,0,0,1>>])
      in call from gen_serial:send/2 (gen_serial.erl, line 624)
      in call from gen_serial:bsend/3 (gen_serial.erl, line 706)

What is <<"d">> doing in there?


On 6/19/2018 4:32 PM, 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.
>
> BobC
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

Bob Cowdery-4
I think something got messed up. It's not failing now but just does
nothing. So the encoding on the wire is different for the two versions
that are numerically the same.


On 6/19/2018 5:22 PM, Bob Cowdery wrote:

> Thanks for all the suggestions. Still a little confused. The number is
> an integer, actually a frequency in Hz plus a command byte at the end
> which is being sent over a serial connection in hex format using
> gen_serial.
>
> This command works: gen_serial:bsend(P,
> <<16#14,16#50,16#00,16#00,16#01>>). where P is the open Port.
>
> However, when I use any of the methods to create a hex version they
> all end up with <<20,80,0,0,1>> which to my mind is the decimal equiv
> of above.
>
> If I fire that I get:
>
> 5> gen_serial:bsend(P,<<20,80,0,0,1>>).
> ** exception error: bad argument
>      in function  port_command/2
>         called as port_command(#Port<0.470>,[<<"d">>|<<20,80,0,0,1>>])
>      in call from gen_serial:send/2 (gen_serial.erl, line 624)
>      in call from gen_serial:bsend/3 (gen_serial.erl, line 706)
>
> What is <<"d">> doing in there?
>
>
> On 6/19/2018 4:32 PM, 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.
>>
>> BobC
>>
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

Danil Zagoskin-2
In reply to this post by Bob Cowdery-4
That's how erlang part communicates with C part.

-define(PACKET_DATA, $d).

send(#gen_serial{port = Port}, Data) ->
  true = port_command(Port, [<<?PACKET_DATA:8>> | Data]),
  ok.


Maybe port_command does not expect an improper list — try one of these:
* gen_serial:bsend(P,[<<20,80,0,0,1>>]) % Your binary wrapped in a list
* gen_serial:bsend(P,[20,80,0,0,1]) % data as list instead of binary

On Tue, Jun 19, 2018 at 7:22 PM Bob Cowdery <[hidden email]> wrote:
Thanks for all the suggestions. Still a little confused. The number is
an integer, actually a frequency in Hz plus a command byte at the end
which is being sent over a serial connection in hex format using
gen_serial.

This command works: gen_serial:bsend(P,
<<16#14,16#50,16#00,16#00,16#01>>). where P is the open Port.

However, when I use any of the methods to create a hex version they all
end up with <<20,80,0,0,1>> which to my mind is the decimal equiv of above.

If I fire that I get:

5> gen_serial:bsend(P,<<20,80,0,0,1>>).
** exception error: bad argument
      in function  port_command/2
         called as port_command(#Port<0.470>,[<<"d">>|<<20,80,0,0,1>>])
      in call from gen_serial:send/2 (gen_serial.erl, line 624)
      in call from gen_serial:bsend/3 (gen_serial.erl, line 706)

What is <<"d">> doing in there?


On 6/19/2018 4:32 PM, 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.
>
> BobC
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


--
Danil Zagoskin | [hidden email]

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

Bob Cowdery-4

The first does nothing and the second hangs. It's not gen-serial that's having a problem with it. It's sending it and giving ok but when decoded in the radio which obviously I can't look at it isn't a valid command. The encoding of <<16#14,16#50,16#00,16#00,16#01>> and <<20,80,0,0,1>> is somehow different.


On 6/19/2018 5:37 PM, Danil Zagoskin wrote:
That's how erlang part communicates with C part.
-define(PACKET_DATA, $d).

send(#gen_serial{port = Port}, Data) ->
  true = port_command(Port, [<<?PACKET_DATA:8>> | Data]),
  ok.


Maybe port_command does not expect an improper list — try one of these:
* gen_serial:bsend(P,[<<20,80,0,0,1>>]) % Your binary wrapped in a list
* gen_serial:bsend(P,[20,80,0,0,1]) % data as list instead of binary

On Tue, Jun 19, 2018 at 7:22 PM Bob Cowdery <[hidden email]> wrote:
Thanks for all the suggestions. Still a little confused. The number is
an integer, actually a frequency in Hz plus a command byte at the end
which is being sent over a serial connection in hex format using
gen_serial.

This command works: gen_serial:bsend(P,
<<16#14,16#50,16#00,16#00,16#01>>). where P is the open Port.

However, when I use any of the methods to create a hex version they all
end up with <<20,80,0,0,1>> which to my mind is the decimal equiv of above.

If I fire that I get:

5> gen_serial:bsend(P,<<20,80,0,0,1>>).
** exception error: bad argument
      in function  port_command/2
         called as port_command(#Port<0.470>,[<<"d">>|<<20,80,0,0,1>>])
      in call from gen_serial:send/2 (gen_serial.erl, line 624)
      in call from gen_serial:bsend/3 (gen_serial.erl, line 706)

What is <<"d">> doing in there?


On 6/19/2018 4:32 PM, 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.
>
> BobC
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


--
Danil Zagoskin | [hidden email]


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

Bob Ippolito
<<16#14,16#50,16#00,16#00,16#01>> and <<20,80,0,0,1>> are identical. If you're experiencing any difference in behavior when using those expressions, your problem is really somewhere else. Perhaps the device is stateful and not getting properly reset from one call to the next, or the port P was closed because the process died with an exception.


On Tue, Jun 19, 2018 at 9:53 AM Bob Cowdery <[hidden email]> wrote:

The first does nothing and the second hangs. It's not gen-serial that's having a problem with it. It's sending it and giving ok but when decoded in the radio which obviously I can't look at it isn't a valid command. The encoding of <<16#14,16#50,16#00,16#00,16#01>> and <<20,80,0,0,1>> is somehow different.


On 6/19/2018 5:37 PM, Danil Zagoskin wrote:
That's how erlang part communicates with C part.
-define(PACKET_DATA, $d).

send(#gen_serial{port = Port}, Data) ->
  true = port_command(Port, [<<?PACKET_DATA:8>> | Data]),
  ok.


Maybe port_command does not expect an improper list — try one of these:
* gen_serial:bsend(P,[<<20,80,0,0,1>>]) % Your binary wrapped in a list
* gen_serial:bsend(P,[20,80,0,0,1]) % data as list instead of binary

On Tue, Jun 19, 2018 at 7:22 PM Bob Cowdery <[hidden email]> wrote:
Thanks for all the suggestions. Still a little confused. The number is
an integer, actually a frequency in Hz plus a command byte at the end
which is being sent over a serial connection in hex format using
gen_serial.

This command works: gen_serial:bsend(P,
<<16#14,16#50,16#00,16#00,16#01>>). where P is the open Port.

However, when I use any of the methods to create a hex version they all
end up with <<20,80,0,0,1>> which to my mind is the decimal equiv of above.

If I fire that I get:

5> gen_serial:bsend(P,<<20,80,0,0,1>>).
** exception error: bad argument
      in function  port_command/2
         called as port_command(#Port<0.470>,[<<"d">>|<<20,80,0,0,1>>])
      in call from gen_serial:send/2 (gen_serial.erl, line 624)
      in call from gen_serial:bsend/3 (gen_serial.erl, line 706)

What is <<"d">> doing in there?


On 6/19/2018 4:32 PM, 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.
>
> BobC
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


--
Danil Zagoskin | [hidden email]

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

zxq9-2
In reply to this post by Bob Cowdery-4
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
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Binaries

Bob Cowdery-4
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
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions