-
Notifications
You must be signed in to change notification settings - Fork 80
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
ModbusEndianness not working correctly #86
Comments
It looks like your server sends big endian data over the wire and thus you should use the BigEndian mode to get little endian data on your little endian machine. |
Maybe it should have been called ServerEndianness :-) |
The problem is that I try to read the same tags from the same machine via Kepware and via PLC Siemens using LittleEndian. So, I'm sure that Server send LittleEndian data. |
There is not much going on in this library regarding endiannes: First, find out if there is an endianness mismatch: FluentModbus/src/FluentModbus/Client/ModbusTcpClient.cs Lines 159 to 160 in 40b6a56
if true, swap bytes: FluentModbus/src/FluentModbus/Client/ModbusClient.cs Lines 127 to 128 in 40b6a56
I guess your machine is little endian, so if you then specify The source of confusion must lie elsewhere ... Maybe because our terms are not precise enough. The Modbus protocol spec defines that the data should be send as BigEndian over the wire. It does not specify how the data are being stored on the server side. Some servers are using little-endian for the wire format - against the specification - and that is why FluentModbus supports both ways. Maybe Kepware and Siemens PLC always convert the big-endian wire data transparently to little-endian on your machine. And when you specify the endianness this does not refer to the wire format but how the data is actually stored in the server. I.e. if you specify big-endian, your data get converted twice, which is equal to no conversion - while FluentModbus would convert it once, since it actually talks about the wire format (so ModbusEndianness should not be called ServerEndianness as stated above but I have no other explanation right now :-/ |
The current design is somewhat confusing to use.
|
Thank you @Apollo3zehn for clarification! |
@fabio622 you are welcome! @Mjollnirs thank your for sharing your workflow. I know the current API might be a bit confusing. It has been designed with maximum performance in mind. My use case is Modbus TCP with hundreds of float32 variables @25 Hz. For that the generic ReadXXX methods are ideal. Especially when the endiannes conversion is hardware accelerated using AVX/SSE2 (which is not yet the case but I did it for a different project already). I will leave this issue open as a reminder to think about how the API could be changed to make its usage clearer. |
i have a problem too with Endianness. my computer ist LittleEndian |
@Apollo3zehn It looks like the low-level API methods do not check SwapBytes. Is this intentional? The modbus server I am using sends registers in BE. Since I don't have access to ModbusUtils.SwitchEndianness(), I need to swap the bytes on my own. Is there any reason for not applying the endianness inside the method? |
so how to solve this problem? the data that read from the server in littleendianness mode is wrong |
how to solve this problem? |
@clee781 If you try to read data of type The endianness cannot be applied in the low level methods because the data may be e.g. of type The main confusion comes from the fact that Modbus defines 16-bit registers but actual data may be larger (e.g. 32 bit) and Modbus servers behave inconsistently in that case. Some do swap bytes at the 16-bit boundaries and some swap them at the 32 bit boundaries (or whatever the data type size is). In case you know that your server swaps data always at the 16-bit boundary, you could do the following to read e.g. long data: var registerData = client.ReadHoldingRegisters<ushort>(...);
var longData = MemoryMarshal.Cast<ushort, long>(registerData); This way If both of you, @clee781 and @Chuo1st, could answer the following, I may give you better advise
Thanks! |
谢谢(thanks), it works correctly after adding the snippets! |
Thank you for the suggestion. I'm using the read ushort workaround now. I understand that Modbus servers can be inconsistent about endianness of the 16-bit registers in a 32-bit word, but the spec is very clear about using big-endian for the register itself regardless of what the register order of the word is. Can't we safely swap the endianness at the 16-bit boundary? As it is now, I don't believe the low level methods are applicable in any scenario since the register endianness will always need to be swapped regardless of the word order .Virtually all Modbus slaves will send 16-bit registers in big-endian format. I think the default should be to assume this. Is there a device I don't know about that doesn't send the registers as big-endian over the wire? For my current application, I am reading in a couple dozen values of different datatypes. I prefer to do this in one transaction because it's faster. |
I try to connect with LittleEndian mode but reads result is in BigEndian mode.
If i try to connect with BigEndian mode the reads result is in LittleEndian mode.
The text was updated successfully, but these errors were encountered: