esp-idf: Missing MB_TCP_UID in xMBMasterTCPPortSendResponse ( ) (IDFGH-4636)

Environment

  • Module or chip used: [ESP32-WROOM-32]
  • IDF version: v4.3-dev-2586-g526f682397
  • Build System: [idf.py]
  • Compiler version : xtensa-esp32-elf-gcc (crosstool-NG esp-2020r3) 8.4.0
  • Operating System: [Linux]
  • Using an IDE?: [Yes] Eclipse
  • Power Supply: [USB]

Problem Description

I am implementing a Modbus TCP/IP application where I need to use the slave addresses [1, 2, 200]. Despite the issue I reported a few days ago (https://github.com/espressif/esp-idf/issues/6437), I came across another one. The problem lies in the function xMBMasterTCPPortSendResponse() in port_tcp_master.c and specifically in this part of the code (lines 900+):

    // If socket active then send data
    if (pxInfo->xSockId > -1) {
        // Apply TID field to the frame before send
        pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U);
        pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF);
        int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS);

When we send data using Modbus TCP/IP usually we don’t need to include the Unit Identifier byte and we set it to 0. However, in applications where we need the slave address this byte needs to be set to the desired value. I searched throughout the entire Modbus software you provided and there isn’t any set of the pucMBTCPFrame[MB_TCP_UID] value. Therefore, I propose, in the above piece of code to be added the following line:

        pucMBTCPFrame[MB_TCP_UID] = (UCHAR)(xMbPortConfig.ucCurSlaveIndex & 0xFF);

I checked the send and receive packets and the problem was that the MB_TCP_UID byte in the pucMBTCPFrame was always 0.

Steps to reproduce

  1. If you don’t have a Modbus device ready, use a slave simulator and set a simple holding register with slave address !=0
  2. Create a trivial Modbus master TCP/IP application with the esp32 (maybe the example provided already in github) and try to get the value on that slave address of the slave.
  3. Print the send and receive data in port_tcp_master.c in (the end of vMBTCPPortMasterReadPacket() and in xMBMasterTCPPortWritePoll()

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 17

Most upvoted comments

Hi @crmabs ,

Can the kconfig option “FMB_TCP_UID_ENABLED” help you to communicate with your inverter? There are many different modbus devices with custom options and behavior that for example support UID = 0, and also other UIDs at the same time. Please tell your interesting stories here… Thanks.

@crmabs ,

The first one is a proper tcp init for slave mode. What I’m missing is the master mode tcp init with similar code. Again, these are just first blinks on my side.

the master init is here master supports the list of slaves. The master takes the uid for slave from data dictionary. The ip address is defined in the slave_ip_address_table which is assigned using the field ip_addr in the communication structure. During the initialization master creates the list of slaves info where associates each slave uid with its IP address then uses it to connect to each slave. If the initialization of master is not completed correctly the master can not write to the slave which is not correctly registered in the port layer and is not connected.

The slave_uid in the communication structure is used only for slave and is dummy field for the master. In current implementation if you need to send data to different slave UID with the same IP you need to add the additional CID in data dictionary and add the same address in IP table for this CID.

As per your log and code the master assigns the UID field incorrectly as if the CONFIG_FMB_TCP_UID_ENABLED is not set, but it is set according to your sdkconfig. Then your slave drops the frame because of this. The functionality related to FMB_TCP_UID_ENABLED is tested before the merge and confirmed as functional. The issue can be observed due to incorrect FMB_TCP_UID_ENABLED configuration or if the incorrect version of the component is compiled instead of correct one. Please make sure you exclude the old component and use new one in your application. To exclude old component you need to include the line ‘set(EXCLUDE_COMPONENTS freemodbus)’ in your CMakeLists.txt file and use the manifest file like here. Please take a look to your *.map file to make sure if correct component is included into your project. I think you may be using the esp-idf v4.4 and do not exclude that component correctly. The generatated sdkconfig file should include the CONFIG_FMB_TCP_UID_ENABLED=y

The below is the log of TCP master with component esp-modbus v1.0.10. The “UID to send: 1” is what is actually set in the MBAP frame.

I (4050) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (4970) esp_netif_handlers: example_netif_sta ip: 192.168.88.252, mask: 255.255.255.0, gw: 192.168.88.1
I (4970) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.88.252
I (4980) example_common: Connected to example_netif_sta
I (4980) example_common: - IPv4 address: 192.168.88.252,
I (4990) wifi:Set ps type: 0

I (4990) uart: ESP_INTR_FLAG_IRAM flag not set while CONFIG_UART_ISR_IN_IRAM is enabled, flag updated
Waiting IP0 from stdin:

I (16040) MASTER_TEST: IP(0) = [192.168.88.251] set from stdin.
Waiting IP1 from stdin:
I (23990) wifi:<ba-add>idx:0 (ifx:0, 64:d1:54:1a:23:5b), tid:0, ssn:5, winSize:64

I (24510) MASTER_TEST: IP(1) = [192.168.88.251] set from stdin.
Waiting IP2 from stdin:

I (33550) MASTER_TEST: IP(2) = [192.168.88.251] set from stdin.
I (33550) MASTER_TEST: IP(3) is not set in the table.
I (33570) MASTER_TEST: Configured 3 IP addresse(s).
I (33570) MASTER_TEST: Modbus master stack initialized...
I (33570) MB_TCP_MASTER_PORT: TCP master stack initialized.
I (33580) MB_TCP_MASTER_PORT: Host[IP]: "192.168.88.251"[192.168.88.251]
I (33580) MB_TCP_MASTER_PORT: Add slave IP: 192.168.88.251
I (33580) MB_TCP_MASTER_PORT: Host[IP]: "192.168.88.251"[192.168.88.251]
I (33600) MB_TCP_MASTER_PORT: Add slave IP: 192.168.88.251
I (33600) MB_TCP_MASTER_PORT: Host[IP]: "192.168.88.251"[192.168.88.251]
I (33610) MB_TCP_MASTER_PORT: Add slave IP: 192.168.88.251
I (33620) MB_TCP_MASTER_PORT: Connecting to slaves...
---I (33660) MB_TCP_MASTER_PORT: Connected 3 slaves, start polling...
I (34210) MASTER_TEST: Start modbus test...
I (34210) MB_TCP_MASTER_PORT: UID to send: 1
I (34240) MASTER_TEST: Characteristic #0 Data_channel_0 (Volts) value = 0.000000 (0x0) read successful.
I (34240) MB_TCP_MASTER_PORT: UID to send: 1
I (34270) MASTER_TEST: Characteristic #1 Humidity_1 (%rH) value = 0.000000 (0x0) read successful.
I (34280) MB_TCP_MASTER_PORT: UID to send: 1
I (34300) MASTER_TEST: Characteristic #2 Temperature_1 (C) value = 0.000000 (0x0) read successful.
I (34310) MB_TCP_MASTER_PORT: UID to send: 200
I (34360) MASTER_TEST: Characteristic #3 Humidity_2 (%rH) value = 0.000000 (0x0) read successful.
I (34370) MB_TCP_MASTER_PORT: UID to send: 200

Please check the recommendations above then clean and rebuild your project. Let me know if you still have problems with this.

Update: not related but please decrease your CONFIG_FMB_PORT_TASK_PRIO to lower value. The priority = 23, may prevent esp-timer to work correctly.