aldas / modbus-tcp-client

PHP client for Modbus TCP and Modbus RTU over TCP (can be used for serial)
Apache License 2.0
194 stars 56 forks source link

Exception: packet byte count does not match bytes in packet! count: 4, actual: 3 #61

Closed gutschein closed 4 years ago

gutschein commented 4 years ago

Hi, coming from an other library I tried to move to your modern solution. Unfortunately my first step wasn't successfull. Probaly I just used something wrong and appreciate your support:. Device is an SMA power inverter.

$slaveID = 3;      // SMA WR always 3
$connection = BinaryStreamConnection::getBuilder()
    ->setPort(502)
    ->setHost('192.168.xx.yy')
    ->build();

$result = [];
$requests = [
    ['address' => 30845, 'quantity' => 2],
];

try {
    $connection->connect();

    foreach ($requests as $request) {
        $address = $request['address'];
        $quantity = $request['quantity'];

        $binaryData = $connection->sendAndReceive(new ReadHoldingRegistersRequest($address, $quantity, $slaveID));

        $response = ResponseFactory::parseResponseOrThrow($binaryData);
        logging($id, 'Parsed packet (in hex):     ' . $response->toHex());    // just another echo...
        $result[$address . '_' . $quantity] = $response->getData();
    }

    logging($id, '',$result);
} catch (Exception $exception) {
    logging($id, 'An exception occurred');
    logging($id, $exception->getMessage());
    logging($id, $exception->getTraceAsString());
} finally {
    $connection->close();
}

I get this exception:

An exception occurred (150)
packet byte count does not match bytes in packet! count: 4, actual: 3 (150)
#0 /usr/local/include/php/modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Packet/ModbusFunction/ReadHoldingRegistersResponse.php(32): ModbusTcpClient\Packet\ByteCountResponse->__construct('\x04\x00\x00\x00', 3, 52197)[LF]
#1 /usr/local/include/php/modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Packet/ResponseFactory.php(49): ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersResponse->__construct('\x04\x00\x00\x00', 3, 52197)[LF]
#2 /usr/local/include/php/modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Packet/ResponseFactory.php(83): ModbusTcpClient\Packet\ResponseFactory::parseResponse('\xCB\xE5\x00\x00\x00\x07\x03\x03\x04\x00\x00\x00')[LF]

I would expect an value for that register: 27

aldas commented 4 years ago

so. this PLC response is $binaryData = "\xCB\xE5\x00\x00\x00\x07\x03\x03\x04\x00\x00\x00";

If we decode this into modbus packet fields it would be

'register data' field should be 4 bytes not 3. 'quantity' => 2 means that response should contain 2 registers data and each register is 16 bit, 2 bytes length.

does request fail for all addresses or only for 30845?

just to be sure.

gutschein commented 4 years ago

Wow, you're fast! :) Thankx...

Just to be shure that we didn't hunt a ghost: There is a binary data respone, therefore it can't be anything else e.g. network, firewall, etc., righ? It's just unexpected/too short.

I tried many different addresses, for the example I've choosen one with simple result data.

Unfortunately the part with "Parsed packet (in hex):" isn't reached reproducable, the exception comes earlier...

I tried it with the cool qmodmaster - was a good hint, I didn't know this helpfull tool. It provides data for IP / ID / Address /Quantity:

Busmonitor qmodmaster: [TCP]>Tx > 09:24:18:551 - 00 20 00 00 00 06 03 03 78 7D 00 02
[TCP]>Rx > 09:24:18:560 - 00 20 00 00 00 07 03 03 04 00 00 00 3E

aldas commented 4 years ago

use this block to get what is sent with PHP

    $packet = new ReadHoldingRegistersRequest($address, $quantity, $slaveID);
    echo 'Packet to be sent (in hex): ' . $packet->toHex() . PHP_EOL;
    $binaryData = $connection->connect()->sendAndReceive($packet);
    echo 'Binary received (in hex):   ' . unpack('H*', $binaryData)[1] . PHP_EOL;
    $response = ResponseFactory::parseResponseOrThrow($binaryData);
    echo 'Parsed packet (in hex):     ' . $response->toHex() . PHP_EOL;

looking at the busmonitor example

[TCP]>Tx > 09:24:18:551 - 00 20 00 00 00 06 03 03 78 7D 00 02

is Request for 2 registers (last 2 bytes is quantity 00 02) and address is 30845 (78 7D)

[TCP]>Rx > 09:24:18:560 - 00 20 00 00 00 07 03 03 04 00 00 00 3E

and response is 2 registers (4 bytes 00 00 00 3E)

gutschein commented 4 years ago

I tried it with code from public static function parseResponse($binaryString): ModbusResponse

Binary data length: 12
Binary data fc: 3
Binary data transactionid: 44732
Binary data unitid: 3

The 5th line $rawData = substr($binaryData, 8); doesn't provide anything

And with your code snippet:

Packet to be sent (in hex): b02600000006030378370002
Binary received (in hex): b02600000007030304fffff4

The 3rd line provides no echo anymore as it throws the exception

aldas commented 4 years ago

So response is b0 26 00 00 00 07 03 03 04 ff ff f4

transaction id = b0 26 protocol id = 00 00 length of packet = 00 07 unit/slave id = 03 function code = 03 length of function data = 04 data = ff ff f4 <-- should be 4 according to 'length of function data'

What version of this library are you using? Could you add one logging statement to library code in file vendor/aldas/modbus-tcp-client/src/Network/StreamHandler.php (assuming you are using composer in your project)

add echo/or logging just after this line https://github.com/aldas/modbus-tcp-client/blob/0930a98bb22ea65f3c6e9debdf56da70f485800d/src/Network/StreamHandler.php#L62

                    $data = fread($stream, 256); // read max 256 bytes
                    echo 'DATA received (in hex):   ' . unpack('H*', $data)[1] . PHP_EOL;

have you ever used Wireshark (https://www.wireshark.org/) for packet inspection?

gutschein commented 4 years ago

I installed it yesterday with composer. Where do I see the Version. UPDATE: In modbus-tcp-client/CHANGELOG.md I see: ## [2.0.1] - 2020-04-12

The library code adjustment I'm going to do...

aldas commented 4 years ago

composer holds library versions in <project root>/composer.lock file. Search libary name in there. there is version field in json telling version

gutschein commented 4 years ago

composer.lock:

    "packages": [
        {
            "name": "aldas/modbus-tcp-client",
            "version": "2.0.1",
gutschein commented 4 years ago

I tried your code change...

$data = fread($stream, 256); // read max 256 bytes --> DATA received (in hex): c87400000007030304000000

$data = fread($stream, 1024); // read max 1024 bytes --> DATA received (in hex): 326c00000007030304000000

Wireshark: I know, what it is, but I never used it. Sorry. But shouldn't be the output of QModMaster sufficent?

aldas commented 4 years ago

This is really strange. even for lowest level of PHP only 3 bytes are returned 00 00 00 but if says 04 as length.

I really have no idea what is going on. Could you tell me what OS and PHP version you are using? I'll try to replicate with mock modbus server.

aldas commented 4 years ago

just to single out if PHP is the problematic part maybe you would run modbus slave simulator on your workstation an https://www.modbustools.com/download.html download Modbus Slave Modbus slave simulator from there and set PHP to request from simulator.

not that it would fix your problem, but it would be useful to diagnose where problem lies

gutschein commented 4 years ago

CentOS 7:

  Operating System: CentOS Linux 7 (Core)
       CPE OS Name: cpe:/o:centos:centos:7
            Kernel: Linux 5.4.44-2-pve
      Architecture: x86-64

PHP PHP 7.2.33 (cli) (built: Aug 4 2020 09:54:49) ( NTS )

Of course, I will try the simulator. I'd really like to understand what's the reason for this problem...

aldas commented 4 years ago

ok, seems you are on Linux. This maybe is better simulator for Linux https://www.modbusdriver.com/diagslave.html

downloadit, unpack and run (on port 1502. binding to port 502 need sudo/root access)

./diagslave/linux_x86-64/diagslave -m tcp -p 1502
gutschein commented 4 years ago

Linux-Server-Park, but Windows on Workstations... :)

I allready installed the Simulator on windows: Set to ID3, same Adress, Value 52. Test QModMaster: OK, Value readable from Windows-Maschine with Simulator. Value change in simulator is reflected in QModMaster => OK

Test your library with coding above:

Binary data length: 13
Binary data fc: 3
Binary data transactionid: 36467
Binary data unitid: 3
Binary data raw: 4 
Packet to be sent (in hex): 652d000000060303787d0002
Binary received (in hex): 652d0000000703030400000034
Parsed packet (in hex): 652d0000000703030400000034
================ ARRAY/OBJECT START ================
{"30845_2":[0,0,0,52]}
================= ARRAY/OBJECT END ================

Value Change in Simulator to 50

Packet to be sent (in hex): 1fdc000000060303787d0002
Binary received (in hex): 1fdc0000000703030400000032
Parsed packet (in hex): 1fdc0000000703030400000032
================ ARRAY/OBJECT START ================
{"30845_2":[0,0,0,50]}
================= ARRAY/OBJECT END ================

=> OK

My conclusion by now:

Do we want to investigate what it is? Maybe it worth, as SMA sells a lot power inverter for photovoltaics. May be it's only my installation, I don't know. Or not and it is just bad luck for me and I stay with my old library.

aldas commented 4 years ago

If you have time and patience it would be nice to see what is actually send on ethernet level with packet inspection.

On linux maybe using TCPDUMP yum install tcpdump would be easier way. See https://danielmiessler.com/study/tcpdump/ for examples and guide

sudo tcpdump -i enp7s0 -X host 192.168.1.100 and port 502

enp7s0 is my ethernet interface

gutschein commented 4 years ago

No problem...ok, tcdump now... :) Checked with QModMaster: The current value for this address is 0000 0063 (=Dec: 99)

Sys > 16:33:37:084 - Connecting to IP : 192.168.020.064:502 OK
[TCP]>Tx > 16:33:40:102 - 00  01  00  00  00  06  03  03  78  7D  00  02  
[TCP]>Rx > 16:33:40:112 - 00  01  00  00  00  07  03  03  04  00  00  00  63 

last request and output with PHP

Packet to be sent (in hex): 500a000000060303787d0002
Binary received (in hex): 500a00000007030304000000
An exception occurred
packet byte count does not match bytes in packet! count: 4, actual: 3

and tcdump of the same request - it seems to me that the request was sent twice, the 2nd comes to the output

HAL-edomi-dev:/usr/local/edomi/main# tcpdump -i eth0 -X host 192.168.20.64 and port 502
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:16:36.409643 IP HAL-edomi-dev.59194 > 192.168.20.64.asa-appl-proto: Flags [S], seq 904504207, win 64240, options [mss 1460,sackOK,TS val 3202848445 ecr 0,n
nop,wscale 7], length 0
        0x0000:  4500 003c ee20 4000 4006 a223 c0a8 14e7  E..<..@.@..#....
        0x0010:  c0a8 1440 e73a 01f6 35e9 a38f 0000 0000  ...@.:..5.......
        0x0020:  a002 faf0 aaa6 0000 0204 05b4 0402 080a  ................
        0x0030:  bee7 96bd 0000 0000 0103 0307            ............
16:16:36.410897 IP 192.168.20.64.asa-appl-proto > HAL-edomi-dev.59194: Flags [S.], seq 0, ack 904504208, win 1472, options [mss 1452], length 0
        0x0000:  4500 002c 0000 0000 4006 d054 c0a8 1440  E..,....@..T...@
        0x0010:  c0a8 14e7 01f6 e73a 0000 0000 35e9 a390  .......:....5...
        0x0020:  6012 05c0 253c 0000 0204 05ac 0000       `...%<........
16:16:36.410912 IP HAL-edomi-dev.59194 > 192.168.20.64.asa-appl-proto: Flags [.], ack 1, win 64240, length 0
        0x0000:  4500 0028 ee21 4000 4006 a236 c0a8 14e7  E..(.!@.@..6....
        0x0010:  c0a8 1440 e73a 01f6 35e9 a390 0000 0001  ...@.:..5.......
        0x0020:  5010 faf0 aa92 0000                      P.......
16:16:36.412084 IP HAL-edomi-dev.59194 > 192.168.20.64.asa-appl-proto: Flags [P.], seq 1:13, ack 1, win 64240, length 12
        0x0000:  4500 0034 ee22 4000 4006 a229 c0a8 14e7  E..4."@.@..)....
        0x0010:  c0a8 1440 e73a 01f6 35e9 a390 0000 0001  ...@.:..5.......
        0x0020:  5018 faf0 aa9e 0000 32b0 0000 0006 0303  P.......2.......  <<<<<<<<<< HERE we are , but just almost matching the request (differs in first bytes)
        0x0030:  787d 0002                                x}..
16:16:36.412933 IP 192.168.20.64.asa-appl-proto > HAL-edomi-dev.59194: Flags [.], ack 13, win 1472, length 0
        0x0000:  4500 0028 0000 0000 4006 d058 c0a8 1440  E..(....@..X...@
        0x0010:  c0a8 14e7 01f6 e73a 0000 0001 35e9 a39c  .......:....5...
        0x0020:  5010 05c0 3ce5 0000 0000 0000 0000       P...<.........
16:16:36.422997 IP 192.168.20.64.asa-appl-proto > HAL-edomi-dev.59194: Flags [.], seq 1:13, ack 13, win 1472, length 12
        0x0000:  4500 0034 0000 0000 4006 d04c c0a8 1440  E..4....@..L...@
        0x0010:  c0a8 14e7 01f6 e73a 0000 0001 35e9 a39c  .......:....5...
        0x0020:  5010 05c0 031f 0000 32b0 0000 0007 0303  P.......2.......  <<<<<<<<<< HERE we are , but just almost matching the result (differs in first bytes)
        0x0030:  0400 0000                                ....
16:16:36.423030 IP HAL-edomi-dev.59194 > 192.168.20.64.asa-appl-proto: Flags [.], ack 13, win 64228, length 0
        0x0000:  4500 0028 ee23 4000 4006 a234 c0a8 14e7  E..(.#@.@..4....
        0x0010:  c0a8 1440 e73a 01f6 35e9 a39c 0000 000d  ...@.:..5.......
        0x0020:  5010 fae4 aa92 0000                      P.......
16:16:36.423899 IP 192.168.20.64.asa-appl-proto > HAL-edomi-dev.59194: Flags [P.], seq 13:14, ack 13, win 1472, length 1
        0x0000:  4500 0029 0000 0000 4006 d057 c0a8 1440  E..)....@..W...@
        0x0010:  c0a8 14e7 01f6 e73a 0000 000d 35e9 a39c  .......:....5...
        0x0020:  5018 05c0 d9cf 0000 6300 0000 0000       P.......c.....
16:16:36.423923 IP HAL-edomi-dev.59194 > 192.168.20.64.asa-appl-proto: Flags [.], ack 14, win 64227, length 0
        0x0000:  4500 0028 ee24 4000 4006 a233 c0a8 14e7  E..(.$@.@..3....
        0x0010:  c0a8 1440 e73a 01f6 35e9 a39c 0000 000e  ...@.:..5.......
        0x0020:  5010 fae3 aa92 0000                      P.......
16:16:36.426245 IP HAL-edomi-dev.59196 > 192.168.20.64.asa-appl-proto: Flags [S], seq 1067670793, win 64240, options [mss 1460,sackOK,TS val 3202848461 ecr 0,nop,wscale 7], length 0
        0x0000:  4500 003c c08d 4000 4006 cfb6 c0a8 14e7  E..<..@.@.......
        0x0010:  c0a8 1440 e73c 01f6 3fa3 5d09 0000 0000  ...@.<..?.].....
        0x0020:  a002 faf0 aaa6 0000 0204 05b4 0402 080a  ................
        0x0030:  bee7 96cd 0000 0000 0103 0307            ............
16:16:36.426984 IP 192.168.20.64.asa-appl-proto > HAL-edomi-dev.59196: Flags [S.], seq 0, ack 1067670794, win 1472, options [mss 1452], length 0
        0x0000:  4500 002c 0000 0000 4006 d054 c0a8 1440  E..,....@..T...@
        0x0010:  c0a8 14e7 01f6 e73c 0000 0000 3fa3 5d0a  .......<....?.].
        0x0020:  6012 05c0 6206 0000 0204 05ac 0000       `...b.........
16:16:36.427003 IP HAL-edomi-dev.59196 > 192.168.20.64.asa-appl-proto: Flags [.], ack 1, win 64240, length 0
        0x0000:  4500 0028 c08e 4000 4006 cfc9 c0a8 14e7  E..(..@.@.......
        0x0010:  c0a8 1440 e73c 01f6 3fa3 5d0a 0000 0001  ...@.<..?.].....
        0x0020:  5010 faf0 aa92 0000                      P.......
16:16:36.427141 IP HAL-edomi-dev.59194 > 192.168.20.64.asa-appl-proto: Flags [R.], seq 13, ack 14, win 64227, length 0
        0x0000:  4500 0028 ee25 4000 4006 a232 c0a8 14e7  E..(.%@.@..2....
        0x0010:  c0a8 1440 e73a 01f6 35e9 a39c 0000 000e  ...@.:..5.......
        0x0020:  5014 fae3 aa92 0000                      P.......
16:16:36.427179 IP HAL-edomi-dev.59196 > 192.168.20.64.asa-appl-proto: Flags [P.], seq 1:13, ack 1, win 64240, length 12
        0x0000:  4500 0034 c08f 4000 4006 cfbc c0a8 14e7  E..4..@.@.......
        0x0010:  c0a8 1440 e73c 01f6 3fa3 5d0a 0000 0001  ...@.<..?.].....
        0x0020:  5018 faf0 aa9e 0000 500a 0000 0006 0303  P.......P.......  <<<<<<<<<< HERE we are with the request
        0x0030:  787d 0002                                x}..
16:16:36.430015 IP 192.168.20.64.asa-appl-proto > HAL-edomi-dev.59196: Flags [.], ack 13, win 1472, length 0
        0x0000:  4500 0028 0000 0000 4006 d058 c0a8 1440  E..(....@..X...@
        0x0010:  c0a8 14e7 01f6 e73c 0000 0001 3fa3 5d16  .......<....?.].
        0x0020:  5010 05c0 79af 0000 0000 0000 0000       P...y.........
16:16:36.432952 IP 192.168.20.64.asa-appl-proto > HAL-edomi-dev.59196: Flags [.], seq 1:13, ack 13, win 1472, length 12
        0x0000:  4500 0034 0000 0000 4006 d04c c0a8 1440  E..4....@..L...@
        0x0010:  c0a8 14e7 01f6 e73c 0000 0001 3fa3 5d16  .......<....?.].
        0x0020:  5010 05c0 228f 0000 500a 0000 0007 0303  P..."...P.......  <<<<<<<<<< HERE we are with the result
        0x0030:  0400 0000                                ....
16:16:36.432983 IP HAL-edomi-dev.59196 > 192.168.20.64.asa-appl-proto: Flags [.], ack 13, win 64228, length 0
        0x0000:  4500 0028 c090 4000 4006 cfc7 c0a8 14e7  E..(..@.@.......
        0x0010:  c0a8 1440 e73c 01f6 3fa3 5d16 0000 000d  ...@.<..?.].....
        0x0020:  5010 fae4 aa92 0000                      P.......
16:16:36.433899 IP 192.168.20.64.asa-appl-proto > HAL-edomi-dev.59196: Flags [P.], seq 13:14, ack 13, win 1472, length 1
        0x0000:  4500 0029 0000 0000 4006 d057 c0a8 1440  E..)....@..W...@
        0x0010:  c0a8 14e7 01f6 e73c 0000 000d 3fa3 5d16  .......<....?.].
        0x0020:  5018 05c0 169a 0000 6300 0000 0000       P.......c.....
16:16:36.433929 IP HAL-edomi-dev.59196 > 192.168.20.64.asa-appl-proto: Flags [.], ack 14, win 64227, length 0
        0x0000:  4500 0028 c091 4000 4006 cfc6 c0a8 14e7  E..(..@.@.......
        0x0010:  c0a8 1440 e73c 01f6 3fa3 5d16 0000 000e  ...@.<..?.].....
        0x0020:  5010 fae3 aa92 0000                      P.......
16:16:36.436003 IP HAL-edomi-dev.59196 > 192.168.20.64.asa-appl-proto: Flags [R.], seq 13, ack 14, win 64227, length 0
        0x0000:  4500 0028 c092 4000 4006 cfc5 c0a8 14e7  E..(..@.@.......
        0x0010:  c0a8 1440 e73c 01f6 3fa3 5d16 0000 000e  ...@.<..?.].....
        0x0020:  5014 fae3 aa92 0000                      P.......

Maybe a wrong endian? SMA docs says, they use "big-endian".

gutschein commented 4 years ago

Just to be sure that it is not an Issue with my network, server or device: I just installed my old solution with another/old library on the same server in the same context in parallel. For the same address I get data; therefore it is really an issue of the your library requestig the data from SMA power inverter devices.

I would really be glad to switch over to your library; I will try to support the investigation. By now I've no idea how to find the reason and I hope my tcdump-data helps to give you an idea. In the best case it's just an endian or codepage issue.

aldas commented 4 years ago

I can not be endian problem. Request bytes are valid (500a 0000 0006 0303 787d 0002 is perfectly ok packet).

        0x0020:  5018 faf0 aa9e 0000 500a 0000 0006 0303  P.......P.......  <<<<<<<<<< HERE we are with the request
        0x0030:  787d 0002      

but response arrives with missing last 1 byte as TCPDUMP shows

        0x0020:  5010 05c0 228f 0000 500a 0000 0007 0303  P..."...P.......  <<<<<<<<<< HERE we are with the result
        0x0030:  0400 0000    

maybe it is PHP version specific problem with php's streams TCP implementation. I assume that your older library is using PHP ext_sockets extension?

  1. Have you tried with never PHP version? - maybe that certain php version/binary is buggy?
  2. What happens when $quantity is different 1 and 3? - is this tied to certain amount of bytes
  3. What happens when address is changed to 30844 and 30846 (quantity stays 2)? - is this related to addressing offset being 1-off and we are reading half of register
  4. What happens when you use ReadInputRegistersRequest packet instead of ReadHoldingRegistersRequest? - when googling SMA inverter modbus stuff then there is some home assistant examples with 'input' registers with 3xxxx address range
  5. can you post tcpdump output for old solution request. - to see how come same packet receives that missing 1 byte.
gutschein commented 4 years ago

I don't know how the other library works, sorry.

  1. PHP 7.2.33 is already the latest 7.2-Version. An upgrade to 7.3 is no option for me by now
  2. I tried 1 or 3:
    An exception occurred
    Response null or data length too short to be valid packet!
  3. Same withRegister 30844 and 30846
  4. I will try... UPDATE 08.08.2020: Yes, true, I'm interested in 3xxxx only. In future there are 2-3 in 4xxxx I'd like to have the possibility to write. Results - now with the proper SlaveID=3
    
    ReadInputRegistersRequest: Packet to be sent (in hex): 8c32000000060304787d0002
    Binary received (in hex): 8c3200000007030404000000
    An exception occurred
    packet byte count does not match bytes in packet! count: 4, actual: 3
    #0 /usr/local/edomi/main/include/php/modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Packet/ModbusFunction/ReadHoldingRegistersResponse.php(32): ModbusTcpClient\Packet\ByteCountResponse->__construct('\x04\x00\x00\x00', 3, 35890)[LF]
    #1 /usr/local/edomi/main/include/php/modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Packet/ResponseFactory.php(52): ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersResponse->__construct('\x04\x00\x00\x00', 3, 35890)[LF]
    #2 /usr/local/edomi/main/include/php/modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Packet/ResponseFactory.php(83): ModbusTcpClient\Packet\ResponseFactory::parseResponse('\x8C2\x00\x00\x00\x07\x03\x04\x04\x00\x00\x00')[LF]#3 /usr/local/edomi/www/data/liveproject/lbs/EXE19001580.php(83): ModbusTcpClient\Packet\ResponseFactory::parseResponseOrThrow('\x8C2\x00\x00\x00\x07\x03\x04\x04\x00\x00\x00')[LF]
Coding I used (according to FC4-example)

//--------------------- FC4 use ModbusTcpClient\Network\BinaryStreamConnection; use ModbusTcpClient\Packet\ModbusFunction\ReadInputRegistersRequest; use ModbusTcpClient\Packet\ModbusFunction\ReadInputRegistersResponse; use ModbusTcpClient\Packet\ResponseFactory;

$connection = BinaryStreamConnection::getBuilder() ->setPort(502) ->setHost('192.168.20.64') ->build();

$startAddress = 30845; //$adr; $quantity = 2; //$quan; $packet = new ReadInputRegistersRequest($startAddress, $quantity, $slaveID); logging($id, 'ReadInputRegistersRequest: Packet to be sent (in hex): ' . $packet->toHex());

try { $binaryData = $connection->connect() ->sendAndReceive($packet); logging($id, 'Binary received (in hex): ' . unpack('H*', $binaryData)[1]);

$response = ResponseFactory::parseResponseOrThrow($binaryData);
logging($id, 'Parsed packet (in hex):     ' . $response->toHex());
logging($id, 'Data parsed from packet (bytes):');
logging($id, '',$response->getData());

foreach ($response as $word) {
    logging($id, '',$word->getBytes());
}
foreach ($response->asDoubleWords() as $doubleWord) {
    logging($id, '',$doubleWord->getBytes());
}

$responseWithStartAddress = $response->withStartAddress($startAddress);
logging($id, '',$responseWithStartAddress[256]->getBytes()); // use array access to get word
logging($id, '',$responseWithStartAddress->getDoubleWordAt(257)->getFloat());

} catch (Exception $exception) { logging($id, 'An exception occurred'); logging($id, $exception->getMessage()); logging($id, $exception->getTraceAsString()); } finally { $connection->close(); }



5. I will provide...
UPDATE 08.08.2020: see next message
gutschein commented 4 years ago

5.) tcdump with the old library (adduc/phpmodbus)

root@edomi:~# tcpdump -i eth0 -X host 192.168.20.64 and port 502
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
16:44:27.158027 IP edomi.39276 > pv.sma.si.asa-appl-proto: Flags [S], seq 1499443568, win 14600, options [mss 1460,sackOK,TS val 1103806320 ecr 0,nop,wscale 7], length 0
        0x0000:  4500 003c 0e00 4000 4006 8317 c0a8 1414  E..<..@.@.......
        0x0010:  c0a8 1440 996c 01f6 595f b170 0000 0000  ...@.l..Y_.p....
        0x0020:  a002 3908 bde5 0000 0204 05b4 0402 080a  ..9.............
        0x0030:  41ca bf70 0000 0000 0103 0307            A..p........
16:44:27.159227 IP pv.sma.si.asa-appl-proto > edomi.39276: Flags [S.], seq 0, ack 1499443569, win 1472, options [mss 1452], length 0
        0x0000:  4500 002c 0000 0000 4006 d127 c0a8 1440  E..,....@..'...@
        0x0010:  c0a8 1414 01f6 996c 0000 0000 595f b171  .......l....Y_.q
        0x0020:  6012 05c0 4286 0000 0204 05ac 0000       `...B.........
16:44:27.159247 IP edomi.39276 > pv.sma.si.asa-appl-proto: Flags [.], ack 1, win 14600, length 0
        0x0000:  4500 0028 0e01 4000 4006 832a c0a8 1414  E..(..@.@..*....
        0x0010:  c0a8 1440 996c 01f6 595f b171 0000 0001  ...@.l..Y_.q....
        0x0020:  5010 3908 26f3 0000                      P.9.&...
16:44:27.159356 IP edomi.39276 > pv.sma.si.asa-appl-proto: Flags [P.], seq 1:13, ack 1, win 14600, length 12
        0x0000:  4500 0034 0e02 4000 4006 831d c0a8 1414  E..4..@.@.......
        0x0010:  c0a8 1440 996c 01f6 595f b171 0000 0001  ...@.l..Y_.q....
        0x0020:  5018 3908 a9cb 0000 8f04 0000 0006 0303  P.9.............
        0x0030:  787d 0002                                x}..
16:44:27.161251 IP pv.sma.si.asa-appl-proto > edomi.39276: Flags [.], ack 13, win 1472, length 0
        0x0000:  4500 0028 0000 0000 4006 d12b c0a8 1440  E..(....@..+...@
        0x0010:  c0a8 1414 01f6 996c 0000 0001 595f b17d  .......l....Y_.}
        0x0020:  5010 05c0 5a2f 0000 0000 0000 0000       P...Z/........
16:44:27.165196 IP pv.sma.si.asa-appl-proto > edomi.39276: Flags [.], seq 1:13, ack 13, win 1472, length 12
        0x0000:  4500 0034 0000 0000 4006 d11f c0a8 1440  E..4....@......@
        0x0010:  c0a8 1414 01f6 996c 0000 0001 595f b17d  .......l....Y_.}
        0x0020:  5010 05c0 c414 0000 8f04 0000 0007 0303  P...............
        0x0030:  0400 0000                                ....
16:44:27.165214 IP edomi.39276 > pv.sma.si.asa-appl-proto: Flags [.], ack 13, win 14600, length 0
        0x0000:  4500 0028 0e03 4000 4006 8328 c0a8 1414  E..(..@.@..(....
        0x0010:  c0a8 1440 996c 01f6 595f b17d 0000 000d  ...@.l..Y_.}....
        0x0020:  5010 3908 26db 0000                      P.9.&...
16:44:27.167170 IP pv.sma.si.asa-appl-proto > edomi.39276: Flags [P.], seq 13:14, ack 13, win 1472, length 1
        0x0000:  4500 0029 0000 0000 4006 d12a c0a8 1440  E..)....@..*...@
        0x0010:  c0a8 1414 01f6 996c 0000 000d 595f b17d  .......l....Y_.}
        0x0020:  5018 05c0 f719 0000 6300 0000 0000       P.......c.....    <<<<<<<<<<<< HERE the proper value 0000 0063
16:44:27.167177 IP edomi.39276 > pv.sma.si.asa-appl-proto: Flags [.], ack 14, win 14600, length 0
        0x0000:  4500 0028 0e04 4000 4006 8327 c0a8 1414  E..(..@.@..'....
        0x0010:  c0a8 1440 996c 01f6 595f b17d 0000 000e  ...@.l..Y_.}....
        0x0020:  5010 3908 26da 0000                      P.9.&...
16:44:27.167295 IP edomi.39276 > pv.sma.si.asa-appl-proto: Flags [F.], seq 13, ack 14, win 14600, length 0
        0x0000:  4500 0028 0e05 4000 4006 8326 c0a8 1414  E..(..@.@..&....
        0x0010:  c0a8 1440 996c 01f6 595f b17d 0000 000e  ...@.l..Y_.}....
        0x0020:  5011 3908 26d9 0000                      P.9.&...
16:44:27.169194 IP pv.sma.si.asa-appl-proto > edomi.39276: Flags [.], ack 14, win 1472, length 0
        0x0000:  4500 0028 0000 0000 4006 d12b c0a8 1440  E..(....@..+...@
        0x0010:  c0a8 1414 01f6 996c 0000 000e 595f b17e  .......l....Y_.~
        0x0020:  5010 05c0 5a21 0000 0000 0000 0000       P...Z!........
16:44:27.171166 IP pv.sma.si.asa-appl-proto > edomi.39276: Flags [F.], seq 14, ack 14, win 1472, length 0
        0x0000:  4500 0028 0000 0000 4006 d12b c0a8 1440  E..(....@..+...@
        0x0010:  c0a8 1414 01f6 996c 0000 000e 595f b17e  .......l....Y_.~
        0x0020:  5011 05c0 5a20 0000 0000 0000 0000       P...Z.........
16:44:27.171182 IP edomi.39276 > pv.sma.si.asa-appl-proto: Flags [.], ack 15, win 14600, length 0
        0x0000:  4500 0028 0000 4000 4006 912b c0a8 1414  E..(..@.@..+....
        0x0010:  c0a8 1440 996c 01f6 595f b17e 0000 000f  ...@.l..Y_.~....
        0x0020:  5010 3908 26d8 0000                      P.9.&...
aldas commented 4 years ago

ok, seems packet is fragmented and last fragment is disregarded. I'll try to create dev branch and add some more logic to fread() method to get more packets if it knows it should have more

gutschein commented 4 years ago

sounds good, thank you

aldas commented 4 years ago

@gutschein could you try changing 1 line in library code.

In file vendor/aldas/modbus-tcp-client/src/Network/StreamHandler.php

                    $data = fread($stream, 256); // read max 256 bytes

to

                    $data = stream_get_contents($stream); 

maybe this is all we need.

gutschein commented 4 years ago

I changed the line to $data = stream_get_contents($stream); in this file via ../modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Network# nano StreamHandler.php

... but same result - sorry. I double checked, that the code has been processed (I wrote $data after that changed line into a file - just to be sure)...

ReadInputRegistersRequest: Packet to be sent (in hex): 5c24000000060304787d0002
Binary received (in hex): 5c2400000007030404000000 An exception occurred
packet byte count does not match bytes in packet! count: 4, actual: 3 
#0 /usr/local/edomi/main/include/php/modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Packet/ModbusFunction/ReadHoldingRegistersResponse.php(32): ModbusTcpClient\Packet\ByteCountResponse->__construct('\x04\x00\x00\x00', 3, 23588)[LF]
#1 /usr/local/edomi/main/include/php/modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Packet/ResponseFactory.php(52): ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersResponse->__construct('\x04\x00\x00\x00', 3, 23588)[LF]
#2 /usr/local/edomi/main/include/php/modbus-tcp-client/vendor/aldas/modbus-tcp-client/src/Packet/ResponseFactory.php(83): ModbusTcpClient\Packet\ResponseFactory::parseResponse('\\$\x00\x00\x00\x07\x03\x04\x04\x00\x00\x00')[LF]
#3 /usr/local/edomi/www/data/liveproject/lbs/EXE19001580.php(56): ModbusTcpClient\Packet\ResponseFactory::parseResponseOrThrow('\\$\x00\x00\x00\x07\x03\x04\x04\x00\x00\x00')[LF]
aldas commented 4 years ago

@gutschein hei, this is late response but try this

this is slightly modified receive part - it tries to read until expected amount of bytes is received or timeout is reached.

<?php

use ModbusTcpClient\Network\BinaryStreamConnection;
use ModbusTcpClient\Network\IOException;
use ModbusTcpClient\Packet\ErrorResponse;
use ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersRequest;
use ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersResponse;
use ModbusTcpClient\Packet\ResponseFactory;

require __DIR__ . '/../vendor/autoload.php';

$connection = BinaryStreamConnection::getBuilder()
    ->setPort(502)
    ->setHost('192.168.20.64')
    ->build();

$startAddress = 30845;
$quantity = 2;
$packet = new ReadHoldingRegistersRequest($startAddress, $quantity);
echo 'Packet to be sent (in hex): ' . $packet->toHex() . PHP_EOL;

try {
    $connection->connect()->send($packet);

    // response size = header (7) + function code (1) + unit code (1) + (quantity * 2 bytes per register)
    $expectedResponseSize = 9 + ($packet->getQuantity() * 2);
    $lastAccess = microtime(true);
    $binaryData = '';
    while (true) {
        $binaryData .= $connection->receive();
        echo 'Binary received (in hex):   ' . unpack('H*', $binaryData)[1] . PHP_EOL;

        $timeSpentWaiting = microtime(true) - $lastAccess;
        if ($timeSpentWaiting >= $connection->getReadTimeoutSec()) {
            throw new IOException('Read total timeout expired');
        }
        $lastAccess = microtime(true);

        $receivedSize = strlen($binaryData);
        if ($receivedSize === $expectedResponseSize) {
            break; // happy path, got exactly what we expect
        }
        if ($receivedSize > $expectedResponseSize) {
            throw new IOException('received more bytes than expected');
        }
        // check if returned packet is an error
        if ($receivedSize > 7 && (ord($binaryData[7]) & ErrorResponse::EXCEPTION_BITMASK) > 0) {
            throw new RuntimeException("modbus error");
        }
    }

    /**
     * @var $response ReadHoldingRegistersResponse
     */
    $response = ResponseFactory::parseResponseOrThrow($binaryData);
    echo 'Parsed packet (in hex):     ' . $response->toHex() . PHP_EOL;
    echo 'Data parsed from packet (bytes):' . PHP_EOL;
    print_r($response->getData());
} catch (Exception $exception) {
    echo 'An exception occurred' . PHP_EOL;
    echo $exception->getMessage() . PHP_EOL;
    echo $exception->getTraceAsString() . PHP_EOL;
} finally {
    $connection->close();
}
gutschein commented 4 years ago

Hej, don't worry that it took some time. It's just an hobby, no business for you and me. Therefore I'm glad, whenver we find a solution.

And....it looks good now! :) In the 2nd loop the missing Byte comes...and finally we get the proper value "99" without any exception or error.

PARAM: 192.168.20.64:502 / Adr:30845 / Quan:2
ReadInputRegistersRequest: Packet to be sent (in hex): 212c000000060304787d0002
Binary received (in hex): 212c00000007030404000000
Binary received (in hex): 212c0000000703040400000063
Parsed packet (in hex): 212c0000000703040400000063
Data parsed from packet (bytes):
================ ARRAY/OBJECT START ================
[0,0,0,99]
================ ARRAY/OBJECT END ================
aldas commented 4 years ago

nice. I'll add this fix to BinaryStreamConnection internals and publish a new release.

gutschein commented 4 years ago

great. Thank you.

aldas commented 4 years ago

@gutschein could you try this branch #63 ?

gutschein commented 4 years ago

of course....but to be honest: Using git (main) is fine. Change specific code in a file like above: fine. :) But how do I test a branche? Can I use Composer to get that branch? Or do I have to change some files manually? I've no experience with branches...sorry... mayb you've a hint?

aldas commented 4 years ago

If think for compose change compose.json

"require": {
    "aldas/modbus-tcp-client": "dev-issue_61_fixes"
}

as this branch seems to already visible in packagagist versions list (https://packagist.org/packages/aldas/modbus-tcp-client#dev-issue_61_fixes)

and do composer update

aldas commented 4 years ago

fastest way would be to clone repo and run fc3.php example with your settings

git clone --branch issue_61_fixes https://github.com/aldas/modbus-tcp-client.git
cd modbus-tcp-client
composer install
# edit fc3.php example with your ip/address etc
php examples/fc3.php
gutschein commented 4 years ago

I will try, but I'm really busy these days... sorry. Probably next weekend

gutschein commented 4 years ago

sorry...still very busy in my customer projects...I will try, but probably next weekend ~ 25.09.

gutschein commented 3 years ago

It took some time to find time to check again... sorry. But I'm back now to connect my devices finally with your library. I just tested V2.1.1 and it worked fine with the SMA devices now.

Great job! Convenient and simple to use. Thank you.