I am trying to implement a pymodbus server. I am using ModbusSparseDataBlocks in the ModbusSlaveContext. This works so far. The client can write and read vales from every register instantiated.
But I have problems with negative values. The client needs 16bit signed integer format and he can not interpret my negative values.
This is how I fill the register with values:
#write positive value (100) to IR[0x10] --> client interprets this correctly
context[0x00].setValues(4, 0x10, 100)
#write negative value (-100) to IR[0x10] --> client can't read this, throws failure
context[0x00].setValues(4, 0x10, -100)
How can I write a valid 16bit signed integer to the register?
(I am using python 2.7 and pymodbus version 1.2.0)
It looks like your library only understands unsigned 16-bit numbers. If you bitwise-AND the signed value with 0xFFFF (a 16-bit mask) in Python, you'll get the same result:
What you're doing:
>>> import struct
>>> struct.unpack('<H',struct.pack('<h',-100))[0]
65436
Bitwise-AND:
>>> -100 & 0xFFFF
65436
So you can do:
context[0x00].setValues(4, 0x10, -100 & 0xFFFF)
Positive values will be unaffected, and negative values result in the unsigned 16-bit 2's complement value.
To convert an unsigned 2's complement 16-bit value back to signed, test for the sign bit (215) and subtract 216 if present:
value = value-2**16 if value & 2**15 else value
or equivalently:
value = value-0x10000 if value & 0x8000 else value
I found out that following works for me, but I don't know if this is the correct and safe way.
import struct
def signed(value):
packval = struct.pack('<h',value)
return struct.unpack('<H',packval)[0]
#write positive value (100) to IR[0x10] --> client interprets this correctly
context[0x00].setValues(4, 0x10, signed(100))
#write negative value (-100) to IR[0x10] --> client interprets this correctly
context[0x00].setValues(4, 0x10, signed(-100))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With