pyhys / minimalmodbus

Easy-to-use Modbus RTU and Modbus ASCII implementation for Python.
Apache License 2.0
306 stars 146 forks source link

serial close doesn't close because its reference dictionary remains #132

Closed schaefer01 closed 4 months ago

schaefer01 commented 5 months ago

when I do a close and reopen in the same program, the port reference remains so the closed port is treated as it is still open, and I get an exception because an action is attempted on a closed port.

I think at least one other issue has this problem as its root cause

solution: any close reference needs to be followed by setting the dictionary element to None

side effect: that means, if an external caller references x.serial.close(), the minimal modbus library remains unaware of the close so the close function needs to be a wrapper

the port reference is here: _serialports: Dict[str, serial.Serial] = {}

the reference dictionalry element remains after close here: isinstance(port, str): self._print_debug("Serial port {} already exists".format(port)) self.serial = _serialports[port] if (self.serial.port is None) or (not self.serial.is_open):

j123b567 commented 5 months ago

This is probably XY problem

Can you describe the real problem you are trying to solve? What are you really doing and why?

solution: any close reference needs to be followed by setting the dictionary element to None

Is definitely not a solution.

So unless you are doing really bad things or unless you are touching minimalmodbus internals which you are not suppose to touch, it should just work.

schaefer01 commented 5 months ago

XY? maybe

I get good messages 5 to 8 times out of 10 tries. The failure error message indicates no response timeout.

If I disconnect/reconnect by re-instantiation after a failed message and remain inside the program while doing the re-instantiation, the command instead continues to timeout,, ie. once failed the program continues to fail, 0 successes after many, many retries.

However, if I exit the program and retry, for each exit and re-enter retry, I get 5 to 8 out of 10 messages across successfully. Exiting the program and re-entering appears to do some sort of cleanup.

I'm trying to isolate the bad behavior, which seems to be coming from inside the program. As noted in my initial problem report, the code underneath appears to not really disconnect because the library sees the port remains active by the first instantiation.

I'm going to verify this (re-instantiation doesn't really re-instantiate) by instrumenting your code and if I can correct this and it works,I'll let you know what I did.

If it doesn't work (i.e. XY remains XY) this points to the ubuntu OS and how it treats the underlying uart driver, and I remain screwed.

j123b567 commented 5 months ago

Try to prolonge instrument.serial.timeout.

If you are running Ubuntu, try stopping all system services that use uarts. I'm not on Ubuntu so I don't have the exact names, but there are some services for braille accessability devices, some services for modems, etc. Do your research. Try lsof or fuser commands, ...

Try looking at dmesg to see if there is anything suspicious.

You can try close_port_after_each_call configuration of the instrument.

See also https://minimalmodbus.readthedocs.io/en/stable/troubleshooting.html and https://minimalmodbus.readthedocs.io/en/stable/serialcommunication.html#controlling-the-rs485-transmitter and check if you have supported hardware.

You have something broken in your setup (HW or SW) and it is probably not related to this library. Random manipulation with _serialports will do more harm than good.

schaefer01 commented 5 months ago

Extending serial timeout does nothing except wait longer before the error message is returned.

I'm guessing the receiving controlled thingy (solarshed solar to battery charger) has its own issues, and hacking the software because I can't fix the hardware.

We're using the ubuntu box in a small form factor as an embedded controller (processes on need to stay on) but its not anytihing like the Therac-25 or Boeing max. there are no human-safety concerns.

There is a long history of hacking software and I'm just following precedent.

j123b567 commented 5 months ago

If you need to hack serial port then better way is to subclass/spoof Serial, do your hacks here, instantiate your serial port before any Instrument and store the instance in _serialports to propper place. Any subsequent instance of instrument will use your instance of serial port. You can do many kinds of hacks later, but minimalmodbus will be happy because the outer instance will be still the same.

But still, double check your setup first, because people are reading solarshed without many problems you mention.

schaefer01 commented 5 months ago

got it, I still need to instrument the code first to better understand what is going on. obviously my assertion of a problem is just a guess.

schaefer01 commented 4 months ago

Simple solution to the ambiguity behind a seemingly software caused problem: The hardware engineer assigned to the project physically moved the usb connector on the modbus device from one physical port on the embedded computer to another and the "software" problem went away. The XY principle wins again. And for those in systems integration who are keeping tabs on who is at fault in the eternal battle of s/w engineers versus h/w engineers, the s/w engineer wins another point, yea!

On a different topic, do PC manufacturers (embedded or not) actually test their USB ports before sale?