-
Notifications
You must be signed in to change notification settings - Fork 121
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
Floating point support #131
Comments
If anyone thinks that this belongs to the API please make a proposal. Otherwise encoding/decoding of non-standard types could always be implemented in the application layer. I do not consider that as mandatory or even desirable feature for the library. |
@cblackd7r - being able to encode and decode various data types as data stored in Modbus registers is a very important aspect of a Modbus server or client application. However, it is complex and there are many ways to could be done. Suppose you have some float values (f32) to send via Modbus. One decision is whether the data is ultimately stored as two u16 values in memory, and then convert to/from f32 on demand; or else you could store the data as f32 in memory and then convert to u16 when building a Modbus request or response. Another decision is what endianness to use in the Modbus register encoding for 32-bit or 64-bit values. As @uklotzde noted, Modbus register (u16 values only) conversion to other data types is more appropriately done in a distinct layer. It is orthogonal the core Modbus API like tokio-modbus provides. Probably the most helpful path would be to start with some example client and server programs that demonstrate how one might implement data format encoding/decoding. This would provide several benefits:
|
While I was playing around with tokio-modbus I noticed that there isn't an interface to get the raw response data. Everything seemed to be Generally speaking adding a "read_f32()" feature into this crate will probably create a mess since multi-register values in Modbus are a constant annoyance, and a better alternative IMO would be to inject the decoding logic somehow (preferably derived from a struct definition) when reading the response. |
It is tricky or at least error-prone to say "give the raw u8 values" for Modbus register data, because then you have a byte-ordering issue to clarify. So, when interpreting something as a f32 value for instance, it's best if you use the u16 values directly to form it, then you eliminate the u8 <-> u16 byte ordering question E.g. here is one way to do it: pub fn get_f32(registers: &[u16]) -> f32 {
assert!(
registers.len() == 2,
"wrong size for get_f32, {}",
registers.len()
);
let bits = ((registers[0] as u32) << 16) | (registers[1] as u32);
f32::from_bits(bits)
}
pub fn get_u32(registers: &[u16]) -> u32 {
assert!(
registers.len() == 2,
"wrong size for get_u32, {}",
registers.len()
);
((registers[0] as u32) << 16) | (registers[1] as u32)
} The area of interpreting Modbus register values, would at least belong to its own crate for sure, because there are so many ways you might want to do it. |
The basic issue is that Modbus register values are 16-bit. Always. However, applications may interpret these in different ways, such as two registers being taken as a 32-bit value. But that is not precisely speaking, a "32-bit Modbus register". Since the Modbus standard defines only 16-bit registers. It's much clearer if we use different terminology for those 32-bit values, i.e. "variable" or "value" or "entity", but not "register". Even though some product documentation will use that imprecise term. It is important that tokio-modbus hides the details of how the |
Yes I know the nuances and problems of Modbus when used to relay values that don't fit in a register. Libmodbus has API functions called What I ended up doing with I know how my sensor represents floats and such and it was possible to do the transformation from
I almost agree. I mean the spec does specify register byte ordering after all. However, I feel that the ordering should be invisible unless you choose to look at it. Having 16bit registers probably was all the rage back in the 80s and you couldn't possibly need anything with more precision, but just reflecting that example from I think ideally the floating point problem would happen behind the scenes and in an utopia even the Modbus transfer mechanism would be just a data transfer mechanism and you'd have something like #[modbus_device(floats = "float-abcd")]
struct MySensor {
#[modbus(address=0x00)]
temperature: f32,
#[modbus(address=0x200)]
pressure: f32,
}
...
let mut s = MySensor::new(serial_device);
s.update() or something like that. |
I think we can all agree there should be a way to make it easier to interact with non-u16 register values. But, instead of putting in the core tokio-modbus crate, it seems like this might be better developed (at least at first) in a separate crate to do the kind of encoding/decoding you suggest. Just because there are so many possible ways to do it, and it's an area of many API options and preferences and trade-offs. I've been trying to figure out a good way to define Modbus registers and data types myself recently, and implement a clean way to encode/decode and abstract away the gory details too. I look forward to seeing, or even contributing to, improvements in this area. |
Hi, is it possible to pass a f32 float with quantity 2 via two u16 registers and only get 2 buffer values? When I pass 2 u16's into the input register vector, it returns 4 buffer values in my modbus client.
The text was updated successfully, but these errors were encountered: