Alternative to BinEnc to return a float?

Hi,

I am testing Ignition, looks great, but I am now stuck.
We have to read Modbus datas, bit order is not standard,
I reorder everything in expression with getBit and then binEnc and works perfect.
For Integers…

Now, how can I get the same for a Float ?
I checked that the bits are ordered correctly, but binEnc makes those 32 bits an INT
and if I ask a toFloat(binEnc*), it just return the INT value
(The Tag datatype is set to Float.)

So how can I get a Float from the 32 bits ?
The same binEnc does but returning a Float and not an Int ?

Thanx for your help.

Before going down this rabbit hole, have you tried the various “Swap” settings in the driver to accommodate the device’s bit order?

(Floats aren’t defined in the Modbus Spec, so there’s no actual “standard”. Just popular choices.)

have you tried the various “Swap” settings in the driver

Yes :frowning:

bit order is
24,25,26,27,28,29,30,31,
16,17,18,19,20,21,22,23,
8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7

Can you supply an example of the type and incoming value of the tag, and what the expected output should be?

EDIT: Also, is this supposed to be like an IEEE754 float?

source read is (dec) 608045383 = (hex) 243E 0947
00100100001111100000100101000111

when bits reordered it is (dec) 1191788068 = (hex) 4709 3E24
01000111000010010011111000100100
which gives in float 35134.14063 (this is the expected value)

Ignition Modbus setting:
Reverse Word order: unchecked
ZeroBased: checked (if disabled, only get 243E)
ReverseStringByte order: checked (but I came to conclusion it is only for strings, not Int/Float ?)
adress config: one

For Kepware, which can read the float, settings:
Modbus RTU Serial, Eth Encapsulated, ID format Decimal, ID 1
Modbus Byte Order Disable
First Word Low Enable
First DWord low disable
Modicon bit order disable
Treat long as Decimals Disable
ZeroBased Addressing: seems to be managed by KW, always revert to Disable
ZeroBased Bit Addressing: seems to be managed by KW, always revert to Disable

I think it is called ‘Intel’ format
Adress is read as Int32, as float gives 4.120754e-17

Unless I’m missing something It looks like the Ignition driver can swap words, but not bytes on non-strings. You can use a script to change the endianness of the incoming integer. and write it to a float tag. Not reversing the word order helps in this case.

def toFloat32(valIn):
	import struct
	
	# Swap endianness 
	valIn = struct.unpack("<I", struct.pack(">I", valIn))[0]

	# Return IEEE 754 float.
	return struct.unpack('f', struct.pack('I', valIn))[0]



x = 608045383
print toFloat32(x)

Output:

35134.140625
2 Likes

Thanks,

while I understand what the function would do,
I have trouble figuring where to define it in Ignition…
Should this be a Gateway event script, on Tag change ?
Should I assign the result to the tag itself or to another tag or ?

You would have to write it back to a different tag.

I would put the script in the global scripting project, modified slightly so you can write to a target tag, then call it from a tag event script on the the raw value tag.

def toFloat32(valIn, target):
	import struct
	
	# Swap endianness 
	valIn = struct.unpack("<I", struct.pack(">I", valIn))[0]

	# Return IEEE 754 float.
	floatOut = struct.unpack('f', struct.pack('I', valIn))[0]
	system.tag.writeBlocking([target], [floatOut])

In my example, I added a script to my global project called convert. The function resides in that script.

I made two tags in my test tag provider: RawValue and FloatValue. RawValue has the event script. in it.

	value = currentValue.value
	convert.toFloat32(value, '[Test]FloatValue')

2 Likes

Thanks.

After many trials, got it to work.
Main points were:
save script at each modif, displayed is not what is run (run= last saved)
in Settings (through browser/gateway setting, set gateway scripting project = name of the project)
(not global, not empty,… (import name or import project.scriptname also not OK))

I learned quite a bit :wink: