Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Safe code to convert byte[4] to float


  • Please log in to reply
3 replies to this topic

#1 wendo

wendo

    Advanced Member

  • Members
  • PipPipPip
  • 85 posts

Posted 03 September 2014 - 09:22 PM

Hi Everyone

 

Let me give you some background. I'm building a wireless weather station using a variety of sensors, an adruino mini and an nRF24L01+ radio. All this works properly and fine. I've been prototyping with the receiver also running an arduino just for simplicity however the end goal was always to have my Netduino 2 Plus acting as the receiver due to the easy network integration.

 

Last night I spent a lot of time getting the radios talking and that is now working however I'm getting a byte packed array from the arduino (it uses the RF24 library) that contains floating point numbers. Endian issues aside I can't now get that byte packed array back to the floating point numbers I sent using any safe code as far as I can tell.

 

There are some posts scattered around using unsafe code to do this with varying levels of success but I need this to a) not eat my netduino, and B) be rock solid.

 

Without a bitconverter class available there is no "easy" way to do this, but I'd settle for hard at this point as long as the code was safe. I'm struggling to believe something seemingly as simple as this hasn't been solved in a more complete way but if I can't do this then it's back to my arduino receiver and buying an ethernet shield to get the job done.

 

This isn't the first time I've run into difficulties converting data types and it's probably the primary reason I have been spending less time with my netduino hardware, but that there seems to be no way to go from a byte array to a float just beggars belief.

 

Am I missing something somewhere?

 

Thanks



#2 baxter

baxter

    Advanced Member

  • Members
  • PipPipPip
  • 415 posts

Posted 04 September 2014 - 01:06 AM

Here is some VB code to go from an IEEE 754 single to 4 bytes and back to a single. It is indeed the hard way to do it. I wrote this before the "unsafe" bitconverter appeared on the scene, but now use the unsafe BC and have never had problems with it.

Imports Microsoft.SPOT
Imports Microsoft.SPOT.Hardware
Imports SecretLabs.NETMF.Hardware
'Imports SecretLabs.NETMF.Hardware.NetduinoPlus
Imports SecretLabs.NETMF.Hardware.Netduino
Imports System.IO
Imports System.Text
Imports System.Collections
Imports System.Diagnostics
Imports System.Text.RegularExpressions
Imports System.Math

Module Module1

    Sub Main()  
        Dim buf() As Byte
        Dim sing As Single
        Dim svalue As Single = 44411.5625
        buf = SingleToFourByte(svalue)
        sing = FourByteToSingle(buf)
        Debug.Print("value - sing = " & (svalue - sing).ToString) '--> 0
    End Sub
End Module

    Public Function FourByteToSingle(ByVal ByteArray() As Byte) As Single

        Dim bin As String = String.Empty
        Dim denormalized As Boolean = False
        Dim exp, start, coeff As Integer
        Dim mantissa As String
        Dim sum As Double
        Dim TwoPow As Integer = 1
        Dim mult As Double = 1

        'Convert 4 byte array to binary in reverse order 
        '(assumes  given array came from a 32bit little-endian integer)
        '--------------------------------------------------------------
        For i As Integer = ByteArray.Length - 1 To 0 Step -1
            bin &= IntToBin(ByteArray(i))
        Next

        'Split apart the binary string. Assumes IEEE 754 single format
        '-------------------------------------------------------------
        Dim sign As Integer = If(bin.Chars(0) = "1", -1, 1) 'leading bit
        Dim expt As Integer = CInt(BinToInt(bin.Substring(1, 8))) 'biased exponent
        Dim fraction As String = bin.Substring(9)           'fractional part
        Dim TempFraction As Integer = CInt(BinToInt(fraction))    'integer for testing

        'Test for special cases (zero, denormalized, +/-infinity, NaN)
        'a good reference for thes cases: http://steve.hollasch.net/cgindex/coding/ieeefloat.html
        '----------------------------------------------------------------------------------------
        If (expt = 0 And TempFraction = 0) Then Return 0
        If (expt = 0 And TempFraction <> 0) Then denormalized = True
        If (expt = 255 And TempFraction = 0) Then Return CSng(If(sign = 1, 1 / 0, -1 / 0))
        If (expt = 255 And TempFraction <> 0) Then Return 0 / 0

        If (denormalized) Then
            exp = -126
            mantissa = fraction
            start = 0
            sum = 0
        Else
            exp = expt - 127
            mantissa = "1" & fraction
            start = 1
            sum = 1 'implied bit
        End If

        'Convert mantissa to single using double arithmetic to keep full precision
        '-------------------------------------------------------------------------
        For i As Integer = start To mantissa.Length - 1
            TwoPow = 2 * TwoPow
            coeff = If(mantissa.Chars(i) = "0", 0, 1)
            If (coeff = 0) Then Continue For
            sum = sum + 1.0 / TwoPow
        Next

        'scale the power of 2: 2^exp --> [(2^exp)*(10^-pow10)]*(10^pow10)
        '----------------------------------------------------------------
        'Constant to scale away exponent power of 2
        'log(2)/log(10) = 0.30102999566398119521373889472449
        'reqd power of 10 = (power of 2)*(log(2)/log(10))
        Dim ReqPowerOf10Const As Double = 0.3010299956639812

        Dim Pow10 As Integer = CInt(exp * ReqPowerOf10Const)
        Dim Pow2 As Integer = exp - Pow10 'reduce the power of 2 exponent [10^pow10 = (2^pow10)*(5^pow10)]
        mult = (2 ^ Pow2 / 5 ^ Pow10) * 10 ^ Pow10

        Return CSng(sign * sum * mult)
    End Function

    Public Function SingleToFourByte(ByVal singl As Single) As Byte()
        Dim byts(3) As Byte
        Dim test As UInt32 = CUInt(singl)
        Dim SingnOf As Integer = Sign(singl)                ' = -1 if negative
        Dim FracPart As Single
        Dim IntPart As UInt32 = CUInt(Floor(Abs(singl)))    'integer part
        FracPart = CSng(Abs(singl) - CSng(IntPart))         ' fractional part
        Dim FracPartBin As String = String.Empty
        Dim IntPartBin As String = String.Empty
        FracPartBin = DecFracToBin(FracPart)
        IntPartBin = DecIntToBin(IntPart)

        'Normalize
        Dim BinExpt As Integer = IntPartBin.Length - 1  'Highest bit set -1
        Dim Exponent As UInteger = CUInt(BinExpt + 127) ' Biased exponent
        Dim BiasedExpt As String = DecIntToBin(Exponent)

        'Remove most significant bit
        IntPartBin = IntPartBin.TrimStart({"1"c})
        'concatenate the mantissa and pad to 23 bits if necesary
        Dim Mantissa As String = IntPartBin & FracPartBin
        Dim LenMant As Integer = Mantissa.Length
        Dim Pad As String = String.Empty
        Do Until (LenMant = 23)
            Mantissa = Mantissa & "0"
            LenMant = Mantissa.Length
        Loop
        Dim IEEE754 As String = If((SingnOf = -1), "1", "0") & BiasedExpt & Mantissa
        Dim LenIEEE As Integer = IEEE754.Length
        Utility.InsertValueIntoArray(byts, 0, 4, BinToInt(IEEE754))
        Dim k As Integer
        Dim substr As String = String.Empty

        Return byts

    End Function

Function IntToBin(ByVal byt As Byte) As String
        'Convert a byte to a binary string 
        Dim temp As Byte = byt
        Dim binval As String = String.Empty
        Dim count As Integer = 0
        Do
            binval = CStr(temp Mod 2) & binval
            temp = CByte(temp \ 2)
            count += 1
        Loop Until count = 8 'pad leading zeros

        Return binval

    End Function

Public Function BinToInt(bin As String) As UInteger
        'Horner's method to evaluate polynomial
        '01110110 msb, msb-1, ... 0 (e.g. msb to lsb, left to right)
        Dim len As Integer = bin.Length
        Dim temp As UInteger = CUInt(If(bin.Chars(0) = "0", 0, 1))
        For i As Integer = 1 To len - 1
            temp = CUInt(temp * 2 + If(bin.Chars(i) = "0", 0, 1))
        Next
        Return temp
    End Function

Public Function DecFracToBin(frac As Single) As String
        Dim BinFrac As String = String.Empty
        Dim temp As Single
        Dim carry As Integer
        While frac <> 0
            temp = frac * 2
            carry = CInt(Floor(temp))
            BinFrac = CStr(carry) & BinFrac
            frac = temp - carry
        End While
        Return BinFrac
    End Function

    Function DecIntToBin(ByVal Intgr As UInteger) As String
 
        Dim temp As UInteger = Intgr
        Dim binval As String = String.Empty
        Dim count As Integer = 0
        Do
            binval = CStr(temp Mod 2) & binval
            temp = CUInt(temp \ 2)
            count += 1
        Loop Until (temp = 0)

        Return binval

    End Function



#3 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 04 September 2014 - 06:19 AM

The BitConverter class was added in .NET Micro Framework 4.3.



#4 wendo

wendo

    Advanced Member

  • Members
  • PipPipPip
  • 85 posts

Posted 04 September 2014 - 09:13 AM

Oh wow, I'm on 4.3 but had missed that piece of information.... that'll make life EASY!

 

Thanks

 

And Baxter.... that's crazy, and awesome :)






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.