Closed FourLeafTec closed 1 day ago
I knew somewhere in time such a request would come :)
Most commonly Modbus Endianness is about the WORD swap and then there is the BYTE Swap. Referring to your example, if you have this number: 0A0B0C0D (32 bits -> 4 Bytes, 2 Words) then in my understanding (maybe I'm wrong) the "common" Modbus Endianness (i.e. Word wise) you would have: Big-Endian: 0A0B 0C0D Little-Endian: 0C0D 0A0B
My "big" question/doubt is how does this translates with the endianness of the host/client architecture. Let's suppose the host/client CPU architecture is Little-Endian and the Modbus device is Big-Endian, what should the library swap: bytes, words or both?
What I'm trying to say/understand is how we best set parameters so that it would be clear what will be the final result. I'm asking you for suggestions, should we add two parameters like:
Yes, this issue is about the the WORD swap and the BYTE Swap. It's about numeric record int16
,uint16
,int32
,uint32
,float
and double
.
I think we should be CPU-agnostic when handling this issue, and only concerned with the byte order in Modbus.
Such as the 32bit number 123456798
(hex:075BCD15) in address [0x0000,0x0001]:
Addr Data
0x0000 07 5B
0x0001 CD 15
Addr Data
0x0000 15 CD
0x0001 5B 07
Addr Data
0x0000 5B 07
0x0001 15 CD
Addr Data
0x0000 CD 15
0x0001 07 5B
The Register
should have a parameter to indicate the endianness of the data within this Modbus address. This will allow the data to be organized into an endianness that Dart's ByteData
can easily handle, based on the known endianness. This can be done either by specifying the endianness or by reformatting it to Endian.host or Endian.little.
Then, ByteData.getUint32(0, Endian)
can be called to transform Dart number.
The parameter could be only one parameter with
Enum {
ABCD,
DCBA,
BACD,
CDAB
}
Word swap of the double should be AB CD EF GH -> GH EF CD AB First step AB CD -> CD AB, EF GH -> GH EF Then [CD AB] [GH EF] -> [GH EF] [CD AB]
I'm implementing this new feature but it will take a bit longer since I want to modify a bit the way package is currently handling requests to make it more flexible. I will publish it asap since I'm making it during my private spare time.
I've pushed a new 'endianness' branch. This is far from be a release candidate but you can give a try and make suggestions and eventually fixes. Take a look to the 'write_request_example'
It's great work and works fine on write.
I've create some test for this. It seems run endianness.getEndianBytes twice on read.
Maybe my test function is wrong.
I've used read.internalSetElementData
to emulate read data.
var num = 4159429653
var bytes = Uint8List.fromList([0xDC, 0x15, 0xF7, 0xEB]);
var reg = ModbusUint32Register(
name: "int32",
address: 14,
type: ModbusElementType.holdingRegister,
endianness: ModbusEndianness.CDAB);
var read = reg.getReadRequest();
read.internalSetElementData(Uint8List.fromList(bytes));
expect(read.element.value, 4159429653);
The test fork: modbus_endianness_test
Your call to internalSetElementData in not needed. It is called internally once the request gets the data from device and will swap them. You need to send the request and wait the response.
How can I create tests without using a real client? It's really inconvenient to have to use a real client every time.
Is there a way to create a mock?
I've fixed the double call to endianness byte adjustment. Please give a try. For testing I'm using client simulators, not real devices.
Works fine, and i create a pr with all test used.
In modbus, the data maybe have 4 formats:
big-endian: AB CD little-endian: DC BA big-endian byte swap: BA CD little-endian byte swap: CD AB
It seems should have an option to support.