Skip to content
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

Doesn't connect with eModbus #15

Open
mcuadros opened this issue Oct 23, 2022 · 12 comments
Open

Doesn't connect with eModbus #15

mcuadros opened this issue Oct 23, 2022 · 12 comments

Comments

@mcuadros
Copy link

I am trying to make it work with eModbus, but apparently doesn't work, doesn't panic or error, just says can't connect. It's a complex project, so I can provide a sample code sorry for that.

In theory, is a drop-in replacement for AsyncTCP, right? Any hint to make it work?

Thanks for this wonderful initiative, AsyncTCP is very useful and convenient, but I always reach glitches that make me spend dozens of hours on debugging.

@avillacis
Copy link
Member

From a quick overview of eModbus, I see that the library supports an ESP32 being either client or server.

I am assuming that the connection is successful if using the AsyncTCP original library in all cases. Is this correct?

Which devices are ESP32 using eModbus plus AsyncTCPSock? The client? The server? Both? If there are two ESP32 involved, which one shows the error? Have you tried flashing just one of them with AsyncTCPSock, and then only the other, to see which side is actually faulty (client or server)?

What snapshot of AsyncTCPSock have you tested? The latest commit was at September 2.

Have you used Wireshark or similar sniffers to check out the traffic with both a successful and a failing case?

@mcuadros
Copy link
Author

mcuadros commented Oct 24, 2022

Hi, sorry I dropped the email without too much information.

I am using the client (I have around 20), and running it with AsyncTCP It works (some errors about the mismatch of the PCB but 0.6% failed requests of 600k).

About the code base is my full project, an extensive code base. I am compiling with platformio I load the HEAD of the default branch of AsyncTCPSock using lib_ignore = AsyncTCP. It compiles without a problem, but all the requests are failing at the connect() method as a timeout, but doesn't panic or something similar.

No sorry I used didn't run Wireshark or something similar, the boards are running in a dedicated WiFi.

I will try to run an example file from eModbus and check if works.

@mcuadros
Copy link
Author

I created https://github.com/mcuadros/eModbusTCPAsyncSocket, this contains eModbus library and TCPAsyncSocket, and doesn't work .

The output is

WIFi IP address: 10.0.0.1
sending request with token 5001
Error response: EA - IP connection failed token: 5001
sending request with token 10002
Error response: EA - IP connection failed token: 10002
sending request with token 15003
Error response: EA - IP connection failed token: 15003

@avillacis
Copy link
Member

I created https://github.com/mcuadros/eModbusTCPAsyncSocket, this contains eModbus library and TCPAsyncSocket, and doesn't work .

The output is

WIFi IP address: 10.0.0.1
sending request with token 5001
Error response: EA - IP connection failed token: 5001
sending request with token 10002
Error response: EA - IP connection failed token: 10002
sending request with token 15003
Error response: EA - IP connection failed token: 15003

You should enable the eModbus full verbose debugging output, and if possible, the full ESP32 debugging output too. From code examination, it seems you need to enable the LOG_LEVEL macro at the project level to the same value as LOG_LEVEL_VERBOSE, defined as (6) in src/Logging.h. This should enable display of the specific error that causes the disconnection with AsyncTCPSock, as supposed to be shown in ModbusClientTCPasync::onACError in src/ModbusClientTCPasync.cpp.

After doing that, please repeat your test and paste the extended error messages.

@avillacis
Copy link
Member

Just to check, I compiled your program with Arduino IDE 2.0.0 and Arduino-ESP32 2.0.5, and flashed it into a spare ESP32 board. I had to disable the portion in which the gateway, ip, and subnet were explicitly set in the WiFi connction, and instead relied on standard DHCP to get an address. I also ran a netcat listening on port 502 and running /bin/cat on every incoming connection so there is some data, even if invalid. I get the following:

18:21:40.874 -> load:0x40078000,len:13864
18:21:40.874 -> load:0x40080400,len:3608
18:21:40.874 -> entry 0x400805f0
18:21:41.132 -> [     4][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
18:21:41.132 -> E (183) psram: PSRAM ID read error: 0xffffffff
18:21:41.132 -> [     6][W][esp32-hal-psram.c:71] psramInit(): PSRAM init failed!
18:21:41.164 -> __ OK __
18:21:41.196 -> [    68][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 0 - WIFI_READY
18:21:41.291 -> [   151][V][WiFiGeneric.cpp:97] set_esp_interface_ip(): Configuring Station static IP: 0.0.0.0, MASK: 0.0.0.0, GW: 0.0.0.0
18:21:41.291 -> [   150][V][WiFiGeneric.cpp:338] _arduino_event_cb(): STA Started
18:21:41.291 -> [   157][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 2 - STA_START
18:21:41.388 -> [   247][V][WiFiGeneric.cpp:353] _arduino_event_cb(): STA Connected: SSID: {REDACTED}, BSSID: 3a:6b:1c:0b:ae:99, Channel: 1, Auth: WPA_WPA2_PSK
18:21:41.388 -> [   250][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 4 - STA_CONNECTED
18:21:41.485 -> . . [  1563][V][WiFiGeneric.cpp:367] _arduino_event_cb(): STA Got New IP:192.168.200.3
18:21:42.706 -> [  1564][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 7 - STA_GOT_IP
18:21:42.706 -> [  1567][D][WiFiGeneric.cpp:991] _eventCallback(): STA IP: 192.168.200.3, MASK: 255.255.255.0, GW: 192.168.200.1
18:21:43.510 -> WIFi IP address: 192.168.200.3
18:21:46.145 -> sending request with token 5001
18:21:46.145 -> [V] 5001| ModbusMessage.cpp    [ 477] checkData: Check data #3
18:21:46.145 -> [V] Enqueue: @3FFBD288/6:
18:21:46.145 ->   | 0000: 01 03 00 01 00 02                                 |......          |
18:21:46.145 -> [D] 5011| ModbusClientTCPasync.cpp [  60] connect: connecting
18:21:46.145 -> [  5022][I][AsyncTCP.cpp:62] _start_asyncsock_task(): Creating asyncTcpSock task running in core -1 (-1 for any available core)...
18:21:46.178 -> [D] 5026| ModbusClientTCPasync.cpp [ 112] addRequestM: Add TCP request result: 00
18:21:46.274 -> [D] 5150| ModbusClientTCPasync.cpp [ 166] onConnected: connected
18:21:46.402 -> [D] 5278| ModbusClientTCPasync.cpp [ 385] send: request sent (msgid:0)
18:21:46.402 -> [D] 5283| ModbusClientTCPasync.cpp [ 214] onPacket: packet received (len:6)

In my scenario, the library does connect and starts exchanging data. The only thing that is different, besides different WiFi credentials, is using DHCP instead of static IP and gateway information.

@mcuadros
Copy link
Author

Ok, I was able to make it "run" more or less. Looks like something is going slow or the callbacks are not triggered properly. I am using https://github.com/mcuadros/eModbus/blob/pointer/src/ModbusClientTCPasync.cpp#L383, and removing this line, It's running BUT...

The 10% of the request fail with a timeout (the timeout is set to 500ms), and the success requests are slow around 120ms. Same code TCPAsync, I have 0.01% timeout and avg request of 30ms.

Any idea? Thanks for your time.

@avillacis
Copy link
Member

Ok, I was able to make it "run" more or less. Looks like something is going slow or the callbacks are not triggered properly. I am using https://github.com/mcuadros/eModbus/blob/pointer/src/ModbusClientTCPasync.cpp#L383, and removing this line, It's running BUT...

The 10% of the request fail with a timeout (the timeout is set to 500ms), and the success requests are slow around 120ms. Same code TCPAsync, I have 0.01% timeout and avg request of 30ms.

Any idea? Thanks for your time.

I have a theory of what might be happening. The onPoll() callback might be incorrectly invoked while the socket is still in the middle of connecting. Please try the following patch:

diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp
index 217d862..21d777c 100644
--- a/src/AsyncTCP.cpp
+++ b/src/AsyncTCP.cpp
@@ -898,7 +898,7 @@ void AsyncClient::_sockIsReadable(void)
 
 void AsyncClient::_sockPoll(void)
 {
-    if (_socket == -1) return;
+    if (!connected()) return;
 
     uint32_t now = millis();
 

Flush any compiled code caches that might apply, recompile your test program and test. If this fixes your issues, I will make a proper commit to the library. Do not forget to undo your patch to eModbus as part of your tests - this is important to test the fix to the API compatibility bug.

@mcuadros
Copy link
Author

mcuadros commented Oct 28, 2022

Sadly nothing changed :/
Also, I changed this statement in other functions, but the result was the same even I got a panic

assert failed: xQueueSemaphoreTake queue.c:1545 (( pxQueue ))


Backtrace:0x40084441:0x3ffe96400x4008c625:0x3ffe9660 0x40091e2d:0x3ffe9680 0x4008d5e5:0x3ffe97b0 0x40159937:0x3ffe97f0 0x401599a5:0x3ffe9810 0x401599d5:0x3ffe9830 0x401499f2:0x3ffe9860 0x4014adb2:0x3ffe9880 0x4014a2ad:0x3ffe98c0 0x400d8e2a:0x3ffe98f0 0x400d8fed:0x3ffe9970 0x400d91d2:0x3ffe99c0 0x400d9259:0x3ffe9a00 0x400d92c1:0x3ffe9a40 0x400d31cd:0x3ffe9a60 0x400d2df1:0x3ffe9ab0 0x400db4de:0x3ffe9ad0

  #0  0x40084441:0x3ffe9640 in panic_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/panic.c:402
  #1  0x4008c625:0x3ffe9660 in esp_system_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/esp_system.c:128
  #2  0x40091e2d:0x3ffe9680 in __assert_func at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/newlib/assert.c:85
  #3  0x4008d5e5:0x3ffe97b0 in xQueueSemaphoreTake at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/freertos/queue.c:1549 (discriminator 1)
  #4  0x40159937:0x3ffe97f0 in AsyncClient::_clearWriteQueue() at .pio/libdeps/lolin_d32/AsyncTCPSock/src/AsyncTCP.cpp:1075
  #5  0x401599a5:0x3ffe9810 in AsyncClient::_close() at .pio/libdeps/lolin_d32/AsyncTCPSock/src/AsyncTCP.cpp:978
  #6  0x401599d5:0x3ffe9830 in AsyncClient::abort() at .pio/libdeps/lolin_d32/AsyncTCPSock/src/AsyncTCP.cpp:1118
  #7  0x401499f2:0x3ffe9860 in ModbusClientTCPasync::disconnect(bool) at .pio/libdeps/lolin_d32/eModbus/src/ModbusClientTCPasync.cpp:104
  #8  0x4014adb2:0x3ffe9880 in ModbusClient::waitSync(unsigned char, unsigned char, unsigned int) at .pio/libdeps/lolin_d32/eModbus/src/ModbusClient.cpp:115
  #9  0x4014a2ad:0x3ffe98c0 in ModbusClientTCPasync::syncRequestM(ModbusMessage, unsigned int) at .pio/libdeps/lolin_d32/eModbus/src/ModbusClientTCPasync.cpp:149 (discriminator 1)
  #10 0x400d8e2a:0x3ffe98f0 in ModbusMessage ModbusClient::syncRequest<int, Modbus::FunctionCode, int, int>(unsigned int, int&&, Modbus::FunctionCode&&, int&&, int&&) at .pio/libdeps/lolin_d32/eModbus/src/ModbusClient.h:54
      (inlined by) ModbusMessage MasterBrick::_doRequest<Modbus::FunctionCode, int, int>(Modbus::FunctionCode&&, int&&, int&&) at .pio/libdeps/lolin_d32/ModbusBrick/src/Brick.cpp:203
  #11 0x400d8fed:0x3ffe9970 in ModbusMessage MasterBrick::_doRequest<Modbus::FunctionCode, int, int>(int, Modbus::FunctionCode&&, int&&, int&&) at .pio/libdeps/lolin_d32/ModbusBrick/src/Brick.cpp:145
  #12 0x400d91d2:0x3ffe99c0 in MasterBrick::readValue(HoldingRegister*, int) at .pio/libdeps/lolin_d32/ModbusBrick/src/Brick.cpp:121
  #13 0x400d9259:0x3ffe9a00 in MasterBrick::getState(int) at .pio/libdeps/lolin_d32/ModbusBrick/src/Brick.cpp:107
  #14 0x400d92c1:0x3ffe9a40 in MasterBrick::getState() at .pio/libdeps/lolin_d32/ModbusBrick/src/Brick.cpp:102
  #15 0x400d31cd:0x3ffe9a60 in WaitState::loop() at .pio/libdeps/lolin_d32/ModbusBrick/src/Task.h:310
  #16 0x400d2df1:0x3ffe9ab0 in Sequence::loop() at .pio/libdeps/lolin_d32/ModbusBrick/src/Task.h:47
  #17 0x400db4de:0x3ffe9ad0 in TaskList::loop() at .pio/libdeps/lolin_d32/ModbusBrick/src/Task.h:394
      (inlined by) Controller::loop(void*) at .pio/libdeps/lolin_d32/ModbusBrick/src/Controller.cpp:39

@avillacis
Copy link
Member

Just to be in the same page, could you please tell me:

  • The Arduino-ESP32 version you use under PlatformIO (1.0.6, 2.0.0, .... 2.0.5)
  • The installed version of eModbus in your projects.

There is something strange about your line numbers within that backtrace that does not line up with my git checkout of the project. Also, a crash in the middle of taking a semaphore is unexpected in that code path.

@mcuadros
Copy link
Author

mcuadros commented Oct 28, 2022

I am using the code from my branch since eModbus has some other problems that are being fixed:
https://github.com/mcuadros/eModbus/, but of course, I also tried with the master branch.

About arduino-esp32 I am using 2.0.5.

One question... eModbus expects to have the full message available to read on onData callback this could be an issue?

@avillacis
Copy link
Member

One question... eModbus expects to have the full message available to read on onData callback this could be an issue?

I have not really reviewed the eModbus code, but if what you mention is true, then it is an eModbus library bug. The received TCP stream is, conceptually, a continuous stream of ordered bytes. The AsyncTCP API cannot guarantee that a certain amount of buffering will be made - it just reads the stream and calls the onData() callback with each data buffer/length as it arrives. Therefore, the higher-level code must buffer or otherwise update whatever state machine deals with incoming bytes until action can be taken. For example, imagine that the server side, for whatever reason, decides to send TCP/IP packets containing exactly one byte of protocol payload. This is a perfectly valid TCP stream, and the other side must be prepared to receive data one byte at a time.

@mcuadros
Copy link
Author

mcuadros commented Oct 28, 2022

https://github.com/eModbus/eModbus/blob/master/src/ModbusClientTCPasync.cpp#L233

It doesn't buffer it; just check if the onData has more than 6 bytes, and if yes, it decodes the message and try to read the full message directly based on the 6 bytes (the head with the length of the message).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants