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 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More