Repository: pymodbus-dev/pymodbus

Issue:
Not possible to decode then encode a DiagnosticStatusResponse
### Versions

- Python: 3.8.6
- OS: Win10
- Pymodbus: 3.2.2
- Modbus Hardware (if used):

### Pymodbus Specific

- Client: tcp

### Description

It is not possible to decode, then encode a DiagnosticStatusResponse since self.message becomes a tuple in decode and in encode a tuple isn't handled (only list). That means the message will not be processed in encode.

### Code and Logs

import pymodbus.diag_message

a = pymodbus.diag_message.DiagnosticStatusResponse()
a.decode(b"\x00\x01\x02\x03")
packet = a.encode()
print(packet)

Output: b'\x00\x01'



Discussion:
Our test "test_diagnostic_requests_decode" does not seem to have any problems. 

Why do you do both encode() and decode(), our classes are not prepared, or at least tested for that. You normally only do either decode() or encode() depending whether you want to send or receive a message.

But pull requests are welcome.
Hi Jan,
Thank you for your quick response. 
It was only to visualize the problem that I did encode/decode like that. The problem I have is that in a response I get (response = master.execute(request)) the message attribute is a tuple so when I encode the message it isn't handled correct (is skipped) since the encode method doesn't handle tuples. However, I think a decode/encode should give you back the the same as your input like in my example above?
There doesn't seem to be any test for response_encode (only requests_encode). It also seems like only the function code is verified, not the message, in test_diagnostic_response_decode (line 152).
Also, self.responses doesn't seem to be used anywhere in the test and line 102 and 103, that specifies DiagnosticStatusResponse and DiagnosticStatusSimpleResponse is commented out.
Best regards Jesper

Resolving patch:
diff --git a/pymodbus/diag_message.py b/pymodbus/diag_message.py
--- a/pymodbus/diag_message.py
+++ b/pymodbus/diag_message.py
@@ -146,7 +146,7 @@ def encode(self):
                 packet += self.message.encode()
             elif isinstance(self.message, bytes):
                 packet += self.message
-            elif isinstance(self.message, list):
+            elif isinstance(self.message, (list, tuple)):
                 for piece in self.message:
                     packet += struct.pack(">H", piece)
             elif isinstance(self.message, int):


Test patch:
diff --git a/test/test_diag_messages.py b/test/test_diag_messages.py
--- a/test/test_diag_messages.py
+++ b/test/test_diag_messages.py
@@ -119,12 +119,23 @@ class TestDataStore:
         (GetClearModbusPlusResponse, b"\x00\x15\x00\x04" + b"\x00\x00" * 55),
     ]
 
+    def test_diagnostic_encode_decode(self):
+        """Testing diagnostic request/response can be decoded and encoded."""
+        for msg in (DiagnosticStatusRequest, DiagnosticStatusResponse):
+            msg_obj = msg()
+            data = b"\x00\x01\x02\x03"
+            msg_obj.decode(data)
+            result = msg_obj.encode()
+            assert data == result
+
     def test_diagnostic_requests_decode(self):
         """Testing diagnostic request messages encoding"""
         for msg, enc, _ in self.requests:
             handle = DiagnosticStatusRequest()
             handle.decode(enc)
             assert handle.sub_function_code == msg.sub_function_code
+            encoded = handle.encode()
+            assert enc == encoded
 
     def test_diagnostic_simple_requests(self):
         """Testing diagnostic request messages encoding"""