favalex / modbus-cli

Command line tool to access Modbus devices
Mozilla Public License 2.0
158 stars 30 forks source link

Add --byte-order=mixed for mixed endian encoding #13

Closed dequis closed 2 years ago

dequis commented 2 years ago

Took me a while but finally got around to implement this https://github.com/favalex/modbus-cli/issues/1

This takes advantage of the fact that umodbus gives us big-endian-unpacked words already. So implementing mixed endian reuses the step that repacked those to bytes, but instead of repacking as big endian again, it uses little endian, effectively byte swapping each register.

Then, a few lines below, it unpacks the bytes as little endian again, which means that 16 bit registers become exactly the same as what we got from umodbus at first, but 32/64 bit registers look very different.

self.values.append(struct.unpack(pack, packed[:size]))

That line is outside of the diff because it didn't require changes. The "pack" variable is little endian thanks to this part of the code in parse_access:

    if pack_type[0] not in '@=<>!':
        if byte_order in ('le', 'mixed'):
            pack_type = '<' + pack_type
        elif byte_order == 'be':
            pack_type = '!' + pack_type

This implies that the user can still do per-register endianness overrides, so you can theoretically do the inverse type of mixed endian if you really want to. But the main point of that is to still keep the old way of specifying endianness working. Personally I think it's more convenient to specify endianness as globally as a commandline option does, and not encode it in every register specification.

From my manual testing this also works with 64 bit fields, doubles in my case:

$ modbus -B mixed 10.69.42.108:503 'i@0/4d' 'i@0/12H'
Parsed 0 registers definitions from 1 files
0: (0.6900000000000001, 560.0, 560.0, -25.991)
0: (44565, 57671, 5242, 16358, 0, 0, 32768, 16513, 0, 0, 32768, 16513)
favalex commented 2 years ago

Thanks! Looks good, merging it.