-
Notifications
You must be signed in to change notification settings - Fork 1k
Return 0x02 Illegal Data Address instead of 0x04 Server Device Failure #2717
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
Conversation
pymodbus/server/requesthandler.py
Outdated
| if self.server.ignore_missing_devices: | ||
| return # the client will simply timeout waiting for a response | ||
| response = ExceptionResponse(self.last_pdu.function_code, ExceptionResponse.GATEWAY_NO_RESPONSE) | ||
| except KeyError: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not generic, problems in the sparse datastore, should be solved at that level.
keyError can probably mean different things in the different datastores.
Look at simulator.py around line 587, to see how it is handled there (apart from the ugly constant 2).
janiversen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I am very mistaken, you make a lot of changes for something that is already implemented in the general datastore and used in the simulator datastore
However I might be wrong....but important is that datastore should handle all datastore problems and not pass the handling to the upper layer.
| message = f"[No Such id] {string}" | ||
| ModbusException.__init__(self, message) | ||
|
|
||
| class NoSuchAddressException(ModbusException): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?? That it something normal, that the library should handle gracefully (and it does in the simulator datastore).
Exception like e.g. NotImplementedException are there to signal the developers forgot to implement something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How else, besides bubbling an Exception up, is the response handler supposed to know what the underlying error was?
| try: | ||
| return [self.values[i] for i in range(address, address + count)] | ||
| except KeyError as e: | ||
| raise NoSuchAddressException(str(e)) from e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why raise an exception, that is not the pattern we normally use....exceptions are raised when the library encounters a problem that was not covered by code.
You can just return ExceptionResponse.ILLEGAL_ADDRESS, that should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getValues (in the happy case) returns a list of values, not a full ModbusResponse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Look in simulator.py line 588, it returns a list of values or an integer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!! Returning a magic value is strange, undocumented, and causing confusing types.
Arguably self.validate() itself should throw the Exception.
| if self.server.ignore_missing_devices: | ||
| return # the client will simply timeout waiting for a response | ||
| response = ExceptionResponse(self.last_pdu.function_code, ExceptionResponse.GATEWAY_NO_RESPONSE) | ||
| except NoSuchAddressException: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The request handler should really not know about the datastore...it handles requests and returns a response.
At least for the sparse datastore, there is an uncaught pymodbus/pymodbus/server/requesthandler.py Lines 108 to 114 in b9731ec
This exception handler is overly generic. (Indeed, even |
|
First of all sparse data block is an old relic, that is going to be removed as soon as possible...but anyhow the key error should be caught in the datastore not passed along. The overly generic exception handler is quite correct, that was made like this to ensure that the server return a valid frame when it encounters a programming problem....you are trying to add a perfectly valid scenario (illegalAddress) to that. Datastore problems should be handled in the datastore module. |
The entire purpose of this PR is to close #2716. Any solution which replies with |
Noted, I'm expecting to have to refactor my downstream code again for |
The solution is to do as the datastore simulator does, I even gave you the line number. |
Jan, I very much appreciate your suggestions for better code, and I'm not trying to argue for its own sake. I urge you to reconsider. pymodbus/pymodbus/datastore/context.py Lines 32 to 40 in 9e22049
pymodbus/pymodbus/datastore/simulator.py Lines 582 to 589 in 9e22049
With all due respect, this code is bad.
|
|
You are, as usual right, in a lot of your rant.....BUT at the end of the day there are a couple of design goals which are final:
Simulator.py do return IllegalAddress, but might break afterwards (at least one user is satisfied with the current solution)....however the datastore are moving in the direction of returning a list is ok and an integer if not ok == modbus exception. Sequential and sparse data block are being changed to convert internally to the simulator module (which is not the simulator datastore). It means in the future it is not recommended to inherit the datastore and make your own version, but instead define a dict to run with the simulator. FYI, in the future we will have a server with a relative fixed setup and thus easier to use, and a simulator with a lot more flexibility (including a http interface if activated). |
No, it does not, or at least not to modbus requests. See my test code - it returns DeviceFailure. Perhaps you're thinking of the HTTP / webpage frontend? Anyways, to summarize the options I see: |
|
The new datastore goes in direction of 1), but of course you are welcome to suggest other routes, as long as datastore handling stays within the datastore module. |
|
Closing in favor of #2733 (which went with option 4) |


Closes #2716