简体   繁体   中英

How to store signed 16bit value in pymodbus register

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 (2 15 ) and subtract 2 16 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))

You could also simply calculate it manually:

if value < 0:
    value = 2**16 + value
context[0x00].setValues(4, 0x10, signed(value))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM