Are Modbus Holding-Registers / Coils values supposed to be changed on both communication and application side?

I'm currently facing the problem of utilizing my self-written Modbus RTU Server Stack. The stack itself works fine, but integrating it with my application has led me to a fundamental question.

Should a value set by the client be allowed to be overwritten by the server application, and should that overwritten value be read back by the client?

Let's take the following example: The Modbus server manages a holding register table with a value called "target speed" in km/h. The target speed is written by the client to a value of 10 km/h. The application of the Modbus Server is limited to a target speed of 8 km/h and therefore alters the value referenced in the holding register table to 8 km/h. Should the server be allowed to alter the speed? A possible alternative would be to publish the actual speed in an entry in an input register. Or is it perfectly fine to alter a value in a R/W register?

From the specification provided by modbus.org, I couldn't really find the expected behavior. There are function calls, e.g., 0x16, that hint at working with values defined by the application, but I don't think that the existence of that function code fully clarifies the intention.
 
This question doesn't have anything to do with Modbus itself. It is an application-level problem, so of course you will not find any recommendations in any communication specification.

This is a question that every engineer creating a Modbus device must consider. There is not a single correct answer. The solution will depend on your specific application, requirements, and restrictions. It will also greatly depend on what specific problem, or problems, you're trying to solve. And of course, the goal is to choose the solution that will result in the least unexpected behavior from your user's perspective. You should consider whether the behavior is intuitive to a user when choosing an appropriate solution.

If you're trying to prevent a client from writing invalid values, then the most obvious approach is to perform range checking immediately when processing the received Modbus write request, and respond with an exception code (you'll probably want to use 03 ILLEGAL DATA VALUE) if the value is outside of the allowable range.

If you're unable to do the above, due perhaps to the restrictions involved in having a Modbus stack that is separate from the application, then either of the two methods you proposed should work (I've seen devices that use each). Here is a more complete description of the two methods.

  1. The client would be allowed to write any value to the register by your Modbus stack, but the application code would then check the validity of the value and either revert back to the previous value or range-limit the value to the maximum or minimum value. For example, using your target speed example, if the current target speed is 3 km/h and the client writes 10 km/h, your application code could either revert the value back to 3 km/h or cap the value at 8 km/h, which is the maximum allowed.
  2. Create a separate, read-only register (such as an input register) that shows the actual speed. The client would be allowed to write any value to the target speed register, but the actual speed would only be allowed to go to the maximum or minimum value if the client wrote a value that is out of range.

The best method to choose may depend on a variety of other factors. For example, is the allowable range configurable by a user? Are other methods available for commanding the speed (i.e. via a keypad, I/O, or other external source)? If this is the case, the second method may be preferred and the target speed register would be specific only to Modbus communications (the application may also need to have settings to control the command hierarchy when multiple command sources are available).
 
Top