lorawan-server icon indicating copy to clipboard operation
lorawan-server copied to clipboard

2-byte float in parser (need help)

Open bennycyau opened this issue 4 years ago • 6 comments

I have a sensor uploading measurements in 2-byte float. Can someone tell me how to code this in the parser in Erlang. I tried to use <afloat:16/float> and got error, since I guess it requires larger storage.

bennycyau avatar Nov 12 '19 13:11 bennycyau

If you are parsing the data, please note that the "variables" need to start with uppercase. Hence: <<AFloat:16/float>>

gotthardp avatar Nov 12 '19 15:11 gotthardp

Thanks for the quick reply. Yes, I was actually used the uppercase letters.

Today I tried the online erlang compiler with <ACcX:16/float> and got "helloworld.erl:5: Warning: bad float bit size"

In fact, I tried 16, 24, 32 bits, only the 32/float does not give me an error on this compiler.

So, my question is: Can someone suggest a workaround to parse this type? Thanks.

bennycyau avatar Nov 13 '19 02:11 bennycyau

The https://github.com/yjh0502/cbor-erlang (BSD license) uses the following code to parse half-precision floats:

decode_hf(<<0:1, 0:5, 0:10>>) -> 0.0;
decode_hf(<<1:1, 0:5, 0:10>>) -> -0.0;
decode_hf(<<Sign:1, 0:5, Frac:10>>) ->
    {Frac2, Count} = hf_norm(Frac, 0),
    <<Value:32/float>> = <<Sign:1, (-14-Count+127):8, Frac2:10, 0:13>>, Value;
decode_hf(<<0:1, 31:5, 0:10>>) -> inf;
decode_hf(<<1:1, 31:5, 0:10>>) -> neginf;
decode_hf(<<_:1, 31:5, _:10>>) -> nan;
decode_hf(<<Sign:1, Exp:5, Frac:10>>) ->
    Exp32 = Exp - 15 + 127,
    <<Value:32/float>> = <<Sign:1, Exp32:8, Frac:10, 0:13>>, Value.

gotthardp avatar Nov 13 '19 09:11 gotthardp

To define a fun inside a fun you need a little trick, so the entire workaround looks like this:


    HFNorm = fun
        (Frac, Count, HN) when Frac < 1024 -> HN(Frac * 2, Count+1, HN);
        (Frac, Count, _) -> {Frac, Count}
        end,

    Decode = fun
        (<<0:1, 0:5, 0:10>>, _) -> 0.0;
        (<<1:1, 0:5, 0:10>>, _) -> -0.0;
        (<<Sign:1, 0:5, Frac:10>>, HN) ->
            {Frac2, Count} = HN(Frac, 0),
            <<Value:32/float>> = <<Sign:1, (-14-Count+127):8, Frac2:10, 0:13>>, Value;
        (<<0:1, 31:5, 0:10>>, _) -> inf;
        (<<1:1, 31:5, 0:10>>, _) -> neginf;
        (<<_:1, 31:5, _:10>>, _) -> nan;
        (<<Sign:1, Exp:5, Frac:10>>, _) ->
            Exp32 = Exp - 15 + 127,
            <<Value:32/float>> = <<Sign:1, Exp32:8, Frac:10, 0:13>>, Value
        end,

    A = Decode(<<0,0>>, HFNorm),

gotthardp avatar Nov 13 '19 09:11 gotthardp

Thanks again for the fast reply. I shall try them out later.

bennycyau avatar Nov 14 '19 08:11 bennycyau

Hi Did you succeed with the code? I need to implement same for my sensor which sends data in float16 format. The sensor sends the following HEX message 20000041fc. I tried to parse it as following without success: fun(Fields, <<A, B:16, C:16/float>>) -> Fields#{'object' => #{data_type=> A, data_status=> B==0, temp=> C}} end.

How should I embed the functions HFNorm and Decode into my code in order to present correct temp value? Thanks in advance

yurgen1975 avatar Sep 01 '21 07:09 yurgen1975