float from reordered bytes

Context: communicating with programmable logic controllers using Modbus or derivatives of Modbus protocol. When float data is stored on these devices the byte ordering is not prescribed, and seemingly every possible variant is used by different manufacturers. Having reassembled 4 bytes into the 'correct' order, how should one turn those bytes into a variable? I found two solutions, each of them a bit of a kluge. If you know a better way to do this, please show me how!

first solution was to write the bytes to a binary file and read them as float (the snippet here does the reverse, but you get my drift)
function float2bytes(var)
    variable var
    make /O/B/U/n=4 w_bytes
    variable refnum
    open /Z=1/P=home refNum as "ieee.bin"
    fbinwrite /F=4 refnum, var
    FSetPos refnum, 0
    FBinRead /U/F=1 refnum, w_bytes
    close refnum   
end


And a programmatic solution:

// get number value of binary32 stored as 4 bytes in an 8 bit unsigned integer wave
function IEEE(w_bytes)
    wave w_bytes // four bytes
    // bytes should be ordered low word first, low byte first
    // i.e. first byte LSB is bit 0 and 4th byte MSB is bit 31 of IEEE 754 single-precision binary floating-point format.
   
    make /free/b/u/n=32 w_binary // seems wasteful, but keeps things organised
    w_binary=(w_bytes[3-floor(p/8)]&2^(7-mod(p,8)))>0
   
    // the 32 points of w_binary now contain contain the 32 bits of an IEEE float, starting from bit 32 (the sign bit) 
   
    variable v_sign, v_exponent, v_fraction, i
   
    v_sign=w_binary[0]
    // next 8 bits hold the exponent
    v_exponent=0
    for (i=0; i<8; i+=1)
        v_exponent+=w_binary[8-i]*2^i
    endfor
    // last 23 bits hold the fraction
    v_fraction=1
    for (i=0; i<23; i+=1)
        v_fraction+=w_binary[9+i]*2^-(i+1)
    endfor
   
    if (v_exponent==0)
        if (v_fraction>1)
            return (-1)^v_sign*(v_fraction-1)*2^-126
        else
            return (-1)^v_sign*0
        endif
    elseif(v_exponent==0xFF)
        return nan
    endif  
   
    return (-1)^v_sign*v_fraction*2^(v_exponent-127)
end
I learned from Howard Rodstein's follow up to a question on the mailing list that Redimension /E=1 provides a much more straightforward way to do this.

It's the /E flag that I was missing: "Force reshape without converting or moving data."

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More