Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sync RTU client timeout not functioning properly in _recv #380

Closed
muhlbaier opened this issue Jan 25, 2019 · 7 comments
Closed

sync RTU client timeout not functioning properly in _recv #380

muhlbaier opened this issue Jan 25, 2019 · 7 comments

Comments

@muhlbaier
Copy link

Versions

  • Python: 3.6
  • OS: Windows
  • Pymodbus: 2.2.0rc1
  • Modbus Hardware (if used): Custom

Pymodbus Specific

  • Server: Custom
  • Client: rtu - sync @ 115200 buad

Description

Every few transactions _recv(self, size) in ModbusSerialClient:sync.py returns with no or partial data when elf.socket.read(size) is called and no attempt is made to read more data if there is a timeout set > 0. The scenario generates a warning like this:

WARNING:hublog:Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response

Then, since data is received by the serial port after _recv is called on the next transaction you get a warning about the data being dumped:

WARNING:pymodbus.client.sync:Cleanup recv buffer before send: 0x2 0x7 0x0 0x16 0x1 0x45 0x0 0xa 0x0 0x1f 0x0 0x0 0x2a 0xf8 0x2e 0xe0 0x0 0x1b 0x71 0x7d 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x5b 0x19

The fix is pretty simple, if not enough bytes are received and timeout is > 0 then keep trying to received until the timeout is up. I made the following fix in _recv in the ModbusSerialClient class of client\sync.py and I went from dropping 43% of my responses to 0%.

The same fix could be applied to recvPacket in framer\rtu_framer.py or in _transact or _recv in transaction.py.

Please let me know if the fix should be left in _recv of ModbusSerialClient or if it would be better to move it elsewhere and then I can make a PR.

Code and Logs

    def _recv(self, size):
        """ Reads data from the underlying descriptor

        :param size: The number of bytes to read
        :return: The bytes read
        """
        start = time.time()
        if not self.socket:
            raise ConnectionException(self.__str__())
        if size is None:
            size = self._wait_for_data()
        result = self.socket.read(size)
        if self.timeout is not None and self.timeout != 0:
            while self.timeout > time.time() - start and len(result) < size:
                result += self.socket.read(size - len(result))
        return result
@dhoomakethu
Copy link
Contributor

@muhlbaier What is the read timeout in your client and corresponding read/write timeouts in your custom server.

@muhlbaier
Copy link
Author

@dhoomakethu 1.0s on the client and the server is embedded and has exclusive control of the port so there is no timeout. I have used a logic analyzer to make sure the data on the bus is as expected and it is. There is a 2-5ms delay from the end of the request from the client to the start of the response from the server which is well within the timing requirements @ 115200 baud.

@dhoomakethu
Copy link
Contributor

@muhlbaier Would it help if you increase the read timeout of the client (>1sec)?

@muhlbaier
Copy link
Author

@dhoomakethu I can test but I would be shocked if it helped. All the data is received within 10ms of the request, I'm not sure why the OS (tested on Windows and Linux) returns from self.socket.read(size) so quickly. The code posted above fixes the problem by retrying self.socket.read() until the number of bytes is what we want or we actually hit the timeout.

@muhlbaier
Copy link
Author

@dhoomakethu I don't think the bug is in pymodbus, I think pyserial isn't properly respecting the timeout that is set when pymodbus opens the port. My fix will ensure we at least try reading bytes until we have them or until the timeout has really been reached.

@dhoomakethu
Copy link
Contributor

@muhlbaier I think you are hitting the issue #353, please refer for the solution there.All you need to do is create your client with kwarg strict=False. Let me know if that helps.

@muhlbaier
Copy link
Author

@dhoomakethu strict=False also fixes the issue. Thank you!

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants