Apollo3zehn / FluentModbus

Lightweight and fast client and server implementation of the Modbus protocol (TCP/RTU).
MIT License
189 stars 71 forks source link

Data reversed #27

Closed Zonciu closed 3 years ago

Zonciu commented 4 years ago

I use Modbus Slave to simulate slave, but I get reverse data. image Slave Log

000070-Rx:00 00 00 00 00 06 01 03 00 00 00 0A 
000071-Tx:00 00 00 00 00 17 01 03 14 01 09 01 83 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
000072-Rx:00 01 00 00 00 06 01 03 00 00 00 0A 
000073-Tx:00 01 00 00 00 17 01 03 14 01 09 01 83 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

Master code

        static void Fluent()
        {
            var client = new ModbusTcpClient();
            client.Connect(IPEndPoint.Parse("127.0.0.1:502"));
            var d1 = client.ReadHoldingRegisters<ushort>(1, 0, 10);
            Console.WriteLine(string.Join(";", d1.ToArray().Select(BitConverter.GetBytes).Select(c => BitConverter.ToString(c)).ToArray()));
            Console.WriteLine(string.Join(";", d1.ToArray()));

            var d2 = client.ReadHoldingRegisters(1, 0, 10);
            Console.WriteLine(BitConverter.ToString(d2.ToArray()));
            Console.WriteLine(string.Join(";", d2.ToArray()));

            client.Disconnect();
        }

Master output

01-09;01-83;00-00;00-00;00-00;00-00;00-00;00-00;00-00;00-00
2305;33537;0;0;0;0;0;0;0;0
01-09-01-83-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
1;9;1;131;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0
Slave send Master output
265(0x0109) 2305(0x0901)
387(0x0183) 33537(0x8301)

I tested it in NModbus, it works correct. NModbus code

        static void NModbus()
        {
            using var tcpClient = new TcpClient();
            tcpClient.Connect(IPEndPoint.Parse("127.0.0.1:502"));
            using var client = new ModbusFactory().CreateMaster(tcpClient);
            var d = client.ReadHoldingRegisters(1, 0, 10);
            Console.WriteLine(string.Join(";", d.Select(BitConverter.GetBytes).Select(c => BitConverter.ToString(c)).ToArray()));
            Console.WriteLine(string.Join(";", d));
        }

NModbus output

09-01;83-01;00-00;00-00;00-00;00-00;00-00;00-00;00-00;00-00
265;387;0;0;0;0;0;0;0;0
Apollo3zehn commented 4 years ago

Hi, thanks for the Report. I can reproduce the behavior with 'Modbus slave'. For larger data types like INT32 the slave lets you choose between different byte layouts. But short/INT16 data are always sent with the big-endian layout.

Currently, FluentModbus does not support different byte layouts (only little endian). Unfortunately the Modbus specs are not very specific about byte layouts for data types larger than 2 bytes. Thats why I did not yet implement anything in that direction.

I already thought about how to solve this on client side. I think I will provide an overload method for each client Modbus function which then allows to specify the byte layout in the server which you need to get from the server's documentation. I will provide Little-Endian, Big-Endian, Little-Endian byte swap and Big-Endian byte swap. I will also add a default option so that the layout does not have to be specified in every single call. The only question left is what should be the default value.

On the master side of FluentModbus there could be similar method overloads, so the user can decide how to handle the data in the registers. Here also the question is what is a meaningful default? The best performance would bei simple Little-Endian layout but then you run into the issues you posted here. So I probably will use one of the Big-Endian layouts to better confirm with the spec. This means a breaking change and a major version bump. I hope to finish this by end of this week.

Zonciu commented 4 years ago

How about using the same byte order as the PLC as the default? Such as Siemens PLC.

dschoorisse commented 4 years ago

I'm also experiencing the same problem with a Phoenix Contact PLC over here.

Apollo3zehn commented 4 years ago

Thanks for your feedback. Unfortunately I don't have much time right now, but I`ll try to fix it next week.

Apollo3zehn commented 3 years ago

Sorry for my late reply. I have released a new version that allows to specify the data layout (big-endian vs little-endian).

Example:

var client = new ModbusTcpClient(..., ModbusEndianness.BigEndian);

When you specify this layout, all data will be reversed automatically.

I´ll close this issue for now as it should be resolved. If you have further issues, feel free to reopen it.