pyhys / minimalmodbus

Easy-to-use Modbus RTU and Modbus ASCII implementation for Python.
Apache License 2.0
306 stars 146 forks source link

minimalmodbus._unpack, why value = struct.unpack(formatstring, packed_bytes)[0] ? #84

Closed patfrench closed 1 year ago

patfrench commented 2 years ago

Hi I have to try :

minimalmodbus._unpack('>hhh', '\x07\x0f\x00\x00\x00\x16')
Out[69]: 1807

struct.unpack('>hhh',b'\x07\x0f\x00\x00\x00\x16')
Out[70]: (1807, 0, 22)

Why there is in source code, line 2605, index 0 ?

value = struct.unpack(formatstring, packed_bytes)[0]

Thank you

j123b567 commented 2 years ago

It is internal helper function to unpack one value. What are you trying to do and why are you using it directly?

patfrench commented 2 years ago

I need to do a read_registers but with the signed option. then i do

minimalmodbus._unpack('>hhh', minimalmodbus._valuelist_to_bytestring(tete_ngt.read_registers(100,3,3), 3)

I need read a multiple registers int16, I hope I am clear ?

j123b567 commented 2 years ago

You have several possibilities

Update source code of minimalmodbus

It should be easy to add support for parameter signed also for multiple registers read/write. It seems for me, that it is rather artifical decision and everything is there to support it properly. Then send a pull request.

So you can later do

res = tete_ngt.read_registers(100, 3, 3, signed=True)  # not supported in current version

Use two's complement

It is easy to implement two's complement function and convert value for only registers you really want.

def twos_comp(val, bits):
    if val & (1 << (bits - 1)):
        val = val - (1 << bits)
    return val

# one register
res = tete_ngt.read_registers(100, 3, 3)
res[2] = twos_comp(res[2], 16)

# all registers
res = [twos_comp(r, 16) for r in tete_ngt.read_registers(100, 3, 3)]

Use standard methods

Instead of using private functions, just use standard ones

import struct

def signed_registers(registers):
    repack = struct.pack("H"*len(registers), *registers)
    return struct.unpack("h"*len(registers), repack)

res = signed_registers(tete_ngt.read_registers(100, 3, 3))
patfrench commented 2 years ago

Thanks for the examples. My skills in python are limited but I will try to submit a code. then I will do the "pull request"