Skip to content

Commit 24ed776

Browse files
floitschjaniversen
andauthored
Fix mask write register (#961)
* Fix mask write register. According to the spec the "Mask Write Register" function ands the or-mask with ~and-mask. See section 6.16 of the specification (v1.1b3): Result = (Current Contents AND And_Mask) OR (Or_Mask AND (NOT And_Mask)) Co-authored-by: jan iversen <jancasacondor@gmail.com>
1 parent 02a9417 commit 24ed776

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

pymodbus/register_write_message.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ def execute(self, context):
313313
if not context.validate(self.function_code, self.address, 1):
314314
return self.doException(merror.IllegalAddress)
315315
values = context.getValues(self.function_code, self.address, 1)[0]
316-
values = (values & self.and_mask) | self.or_mask
316+
values = (values & self.and_mask) | (self.or_mask & ~self.and_mask)
317317
context.setValues(self.function_code, self.address, [values])
318318
return MaskWriteRegisterResponse(self.address, self.and_mask, self.or_mask)
319319

test/modbus_mocks.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,28 @@ def setValues(self, fx, address, values):
3030
"""Set values."""
3131

3232

33+
class MockLastValuesContext(IModbusSlaveContext):
34+
"""Mock context."""
35+
36+
def __init__(self, valid=False, default=True):
37+
"""Initialize."""
38+
self.valid = valid
39+
self.default = default
40+
self.last_values = []
41+
42+
def validate(self, fx, address, count=0):
43+
"""Validate values."""
44+
return self.valid
45+
46+
def getValues(self, fx, address, count=0):
47+
"""Get values."""
48+
return [self.default] * count
49+
50+
def setValues(self, fx, address, values):
51+
"""Set values."""
52+
self.last_values = values
53+
54+
3355
class FakeList:
3456
"""Todo, replace with magic mock."""
3557

test/test_register_write_messages.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
WriteSingleRegisterResponse,
1414
)
1515

16-
from .modbus_mocks import MockContext
16+
from .modbus_mocks import MockContext, MockLastValuesContext
1717

1818
# ---------------------------------------------------------------------------#
1919
# Fixture
@@ -138,10 +138,17 @@ def test_mask_write_register_request_decode(self):
138138

139139
def test_mask_write_register_request_execute(self):
140140
"""Test write register request valid execution"""
141-
context = MockContext(valid=True, default=0x0000)
142-
handle = MaskWriteRegisterRequest(0x0000, 0x0101, 0x1010)
141+
# The test uses the 4 nibbles of the 16-bit values to test
142+
# the combinations:
143+
# and_mask=0, or_mask=0
144+
# and_mask=F, or_mask=0
145+
# and_mask=0, or_mask=F
146+
# and_mask=F, or_mask=F
147+
context = MockLastValuesContext(valid=True, default=0xAA55)
148+
handle = MaskWriteRegisterRequest(0x0000, 0x0F0F, 0x00FF)
143149
result = handle.execute(context)
144150
self.assertTrue(isinstance(result, MaskWriteRegisterResponse))
151+
self.assertEqual([0x0AF5], context.last_values)
145152

146153
def test_mask_write_register_request_invalid_execute(self):
147154
"""Test write register request execute with invalid data"""

0 commit comments

Comments
 (0)