Skip to content

Commit

Permalink
Add mixed endian writing support
Browse files Browse the repository at this point in the history
  • Loading branch information
dequis committed Nov 22, 2021
1 parent 64a4c1b commit 9497699
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 9 deletions.
10 changes: 9 additions & 1 deletion modbus_cli/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ def write_registers_send(self, modbus):
else:
words = []

if self.byte_order == 'mixed':
register_fmt = '<H'
else:
register_fmt = '>H'

for pack_type, value in zip(self.pack_types, self.values_to_write):
n_bytes = struct.calcsize(pack_type)
assert n_bytes % 2 == 0
Expand All @@ -186,7 +191,10 @@ def write_registers_send(self, modbus):
else:
value = int(value, 0)

words.extend([h << 8 | l for h, l in grouper(struct.pack(pack_type, value), 2)])
words.extend([
struct.unpack(register_fmt, bytes(byte_pair))[0]
for byte_pair in grouper(struct.pack(pack_type, value), 2)
])

if len(words) == 1:
message = modbus.protocol.write_single_register(modbus.slave_id, self.address(), words[0])
Expand Down
42 changes: 34 additions & 8 deletions tests/test_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,28 +121,54 @@ def test_write_coils(self):
def test_presenter(self):
pass

def test_endianness(self):
def test_endianness_read(self):
modbus = mocked_modbus()

# given these two 16 bit registers, what do we interpret?
modbus.receive = Mock(return_value=[0x1122, 0x3344])

def perform(byte_order, *fields):
def perform(byte_order, fields):
addresses = list(range(len(fields)))
access = Access('h', addresses, fields, byte_order=byte_order)
access.perform(modbus)
return access.values

# big endian 16/32 bit fields
self.assertEqual(perform('be', '>H', '>H'), [(0x1122, ), (0x3344, )])
self.assertEqual(perform('be', '>I'), [(0x11223344, )])
self.assertEqual(perform('be', ['>H', '>H']), [(0x1122, ), (0x3344, )])
self.assertEqual(perform('be', ['>I']), [(0x11223344, )])

# little endian 16/32 bit fields
self.assertEqual(perform('le', '<H', '<H'), [(0x2211, ), (0x4433, )])
self.assertEqual(perform('le', '<I'), [(0x44332211, )])
self.assertEqual(perform('le', ['<H', '<H']), [(0x2211, ), (0x4433, )])
self.assertEqual(perform('le', ['<I']), [(0x44332211, )])

# mixed endian 16/32 bit fields
self.assertEqual(perform('mixed', '<H', '<H'), [(0x1122, ), (0x3344, )])
self.assertEqual(perform('mixed', '<I'), [(0x33441122, )])
self.assertEqual(perform('mixed', ['<H', '<H']), [(0x1122, ), (0x3344, )])
self.assertEqual(perform('mixed', ['<I']), [(0x33441122, )])

def test_endianness_write(self):
modbus = mocked_modbus()

# given these user inputs, what 16 bit registers are actually committed?
values16 = ["0x1122", "0x3344"]
values32 = ["0x11223344"]

def perform(byte_order, fields, values):
addresses = list(range(len(fields)))
access = Access('h', addresses, fields, values=values, byte_order=byte_order)
access.perform(modbus)
return modbus.protocol.write_multiple_registers.call_args.args[2]

# big endian 16/32 bit fields
self.assertEqual(perform('be', ['>H', '>H'], values16), [0x1122, 0x3344])
self.assertEqual(perform('be', ['>I'], values32), [0x1122, 0x3344])

# little endian 16/32 bit fields
self.assertEqual(perform('le', ['<H', '<H'], values16), [0x2211, 0x4433])
self.assertEqual(perform('le', ['<I'], values32), [0x4433, 0x2211])

# mixed endian 16/32 bit fields
self.assertEqual(perform('mixed', ['<H', '<H'], values16), [0x1122, 0x3344])
self.assertEqual(perform('mixed', ['<I'], values32), [0x3344, 0x1122])


if __name__ == '__main__':
Expand Down

0 comments on commit 9497699

Please sign in to comment.